ThinkGeo.com    |     Documentation    |     Premium Support

Label PointPlacement

I am using a custom TextStyle and an overload of the DrawCore method to display labels generated from colum data in a database.  While I can display the label at the correct point and at the correct angle I am unable to change the anchor position of the label.  I need to be able to change the anchor position of every label individually.


I can retrieve the PointPlacement value from the database, but how do I apply that within the DrawCore method.


Is there a way of converting this value to the equivalent XOffset and YOffset values to pass into the canvas.DrawText() method?


 



 We have in the Code Community a project Labeling Based On Columns that responds, I think, almost exactely to what you are looking for. It allows to display labels on the map based on a point based layer with the font color, size, angle etc coming from columns.


code.thinkgeo.com/projects/show/labelingbasedoncol


 Below, I slightly modified the class ColumBasedTextStyle to have the labels drawn according to some X and Y offset from columns. You can see how the function canvas.DrawText allows drawing the label with offsets in the override DrawCore.



using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using ThinkGeo.MapSuite.Core;

namespace LabelingBasedOnColumns
{
    class ColumnBasedTextStyle : TextStyle
    {
        private string sizeColumnName;
        private string angleColumnName;
        private string colorColumnName;
        private string fontColumnName;
        private string xOffsetColumnName;
        private string yOffsetColumnName;
        
        public ColumnBasedTextStyle()
            : this(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty,string.Empty)
        { }

        public ColumnBasedTextStyle( string TextColumnName, string SizeColumnName, string AngleColumnName, string ColorColumnName, string FontColumnName, 
                                     string XOffsetColumnName, string YOffsetColumnName)
        {
            this.TextColumnName = TextColumnName;
            this.sizeColumnName = SizeColumnName;
            this.angleColumnName = AngleColumnName;
            this.colorColumnName = ColorColumnName;
            this.fontColumnName = FontColumnName;
            this.xOffsetColumnName = XOffsetColumnName;
            this.yOffsetColumnName = YOffsetColumnName;
        }

       public string SizeColumnName
        {
            get { return sizeColumnName; }
            set { sizeColumnName = value; }
        }

        public string AngleColumnName
        {
            get { return angleColumnName; }
            set { angleColumnName = value; }
        }

        public string ColorColumnName
        {
            get { return colorColumnName; }
            set { colorColumnName = value; }
        }

        public string FontColumnName
        {
            get { return fontColumnName; }
            set { fontColumnName = value; }
        }

        public string XOffsetColumnName
        {
            get { return xOffsetColumnName; }
            set { xOffsetColumnName = value; }
        }

        public string YOffsetColumnName
        {
            get { return yOffsetColumnName; }
            set { yOffsetColumnName = value; }
        }


        protected override void DrawCore(IEnumerable<Feature> features, GeoCanvas canvas, Collection<SimpleCandidate> labelsInThisLayer, Collection<SimpleCandidate> labelsInAllLayers)
        {
            // Loop through each feature and get the values for the different columns to label.
            foreach (Feature feature in features)
            {
                //Get the values for Text, Angle, Size and Font of each feature.
                string Text = feature.ColumnValues[TextColumnName];
                float Angle = Convert.ToSingle(feature.ColumnValues[AngleColumnName]);
                float Size = Convert.ToSingle(feature.ColumnValues[SizeColumnName]);
                int Color = Convert.ToInt32(feature.ColumnValues[ColorColumnName]);
                string Font = feature.ColumnValues[FontColumnName];
                float XOffset = Convert.ToInt32(feature.ColumnValues[XOffsetColumnName]);
                float YOffset = Convert.ToInt32(feature.ColumnValues[YOffsetColumnName]);

                //Convert from world coordinate to screen coordinate the location of the feature.
                ScreenPointF textScreenPoint = ExtentHelper.ToScreenCoordinate (canvas .CurrentWorldExtent ,feature ,canvas. Width,canvas .Height );

                //Use DrawText method of canvas to label according to the values previously set.
                canvas.DrawText(Text,new GeoFont(Font,Size),new GeoSolidBrush(GeoColor.FromWin32(Color)), null, new ScreenPointF[] { textScreenPoint }, DrawingLevel.LevelFour, XOffset, YOffset,Angle );
            }
        }

        protected override Collection<string> GetRequiredColumnNamesCore()
        {
            // Here we grab the columns from the textStyle and then add
            // the required columns to make sure we pull back the column
            //  that we need for labeling.
            Collection<string> columns = new Collection<string>();
            if (!columns.Contains(TextColumnName))
            {
                columns.Add(TextColumnName);
            }
            if (!columns.Contains(sizeColumnName))
            {
                columns.Add(sizeColumnName);
            }
            if (!columns.Contains(angleColumnName))
            {
                columns.Add(angleColumnName);
            }
            if (!columns.Contains(colorColumnName))
            {
                columns.Add(colorColumnName);
            }
            if (!columns.Contains(fontColumnName))
            {
                columns.Add(fontColumnName);
            }
            if (!columns.Contains(xOffsetColumnName))
            {
                columns.Add(xOffsetColumnName);
            }
            if (!columns.Contains(yOffsetColumnName))
            {
                columns.Add(yOffsetColumnName);
            }
            return columns;
        }

    }
}


Val, thanks for the reply.  That’s the project I’ve based my code on, howeverthe database I’m reading (Ordinance Survey MasterMap) doesn’t store x-offset and y-offset.  It has a column with anchorPosition as follows: 
  
 2----------------5----------------8 
 |                      |                      | 
 1----------------4----------------7  
 |                      |                      | 
 0----------------3----------------6  
  
 I need some way of calculating the x and y offset values from the anchor position value.  This calculation must take into account the length and height of the text, the rotation angle and the anchor position to get the correct x and y offset values.  I’m afraid this is a bit beyond me. 
  
 I was hoping there might be a method within the MapSuite core that already provides this functionality since the PointPosition property follows the same layout and must be converted to offset values before drawing. 


Hi Gordon, 
  
 I am not sure how to use the ‘anchor position value’ you mentioned to calculate the xoffset and yoffset. As I known, there is a method called GetLabelingCandidates in MapSuite core is kind of the functionality you are hoping. This method calculates some appropriate labeling position and rotation angle based on the shape in the passing in feature and the label text. You can access this method only in the class derived from TextStyle. 
  
 So I think you could have a try using this method: wrapping the anchor position as a feature, put the label text as a column value in the feature, and then passing in this feature and canvas to the GetLavelingCandidates method, it will return a LabelingCandidate collection which contains one item usually. At last, you can access the LabelInformation of the LabelingCandidate object to get the label position and rotation angle information.  
  
 I’m not sure if this makes sense for you, just hope this can give you some tips. 
  
 Any more questions please let us know. 
  
 Thanks, 
  
 Sun