ThinkGeo.com    |     Documentation    |     Premium Support

Reference Scale on styles?

Is there currently any support for applying a style with respect to a reference scale with which you specify the feature or label style. Then, when zooming in or out, the line would then be scaled appropriately? I imagine it's possible to program this but it would be a nice feature to have built into the api if it does not already exist.


Thanks again.



Nelson,  
  
 I am not very sure about the "reference scale", do you mean for example I set the zoomlevel5.scale to 10000 and then the scales for the rest ZoomLevel are all automatically set?  Can you provide more description about that? 
  
 The styles are based on ZoomLevels and the scales of ZoomLevels can be changed, so you can create your own Style strategy very easily. Also in the upcoming release (be available around 22rd this month), with the new property map.CustomZoomLevels, you can custom the zoomLevels even more easily.  Let’s wait and see :) 
  
 Thanks, 
  
 Ben. 


What I mean is for instance say I am using a point marker that is displayed at 100% its size at a 10000 scale. now if I move into a zoom level of 1000 scale, the marker should display larger because it is maintaining the size it represented at 10000 reference scale. If I zoomed out to a 100000 scale, it would appear smaller because it is maintaining a level of proportion.  
  
 While I make an explanation for point markers, my particular interest at the moment is in line widths but also could be applied to font size, etc.

Nelson, 
  
   There is a sample of something like this in the Developers Blog area in the discussion forums, see the link below.  To do a line I think the method would be similar however on the Canvas you would want to call the DrawLine or some method like that.  I will see if someone is free to put together a sample with lines over the next few days and post that code.  The great thing is that styles are pretty easy to create yourself and it allows you a great deal of flexibility. 
  
 In the sample there is a lot of code for the properties, constructors etc but the main code that does the heavy lifting is the DrawCore.  This is where you will want to change the code so that it handles lines.  You can see in the sample we handle the scaling and even have a maximum and minimum sizes.  You could do the same thing with a line so that it never gets too large.  Another thing you could so is code it so that the style of the road changes as you zoom.  What I mean by this is that when you are far away the road displays as a single line but as you zoom in not only would the road get thicker but you could add the effect of adding white inner line to give a nice effect. 
  
 Let me know what you think and how comfortable you are with creating your own style.  Ben can help you out with any questions and I will check in on this thread to see how things are progressing. 
  
 gis.thinkgeo.com/Support/DiscussionForums/tabid/143/aff/16/aft/5014/afv/topic/Default.aspx

Nelson, 
  
 Here is the raw codes for you about ScalingLineStyle, we will polish it and have a post in our blog. 
 
  class ScalingLineStyle : Style
    {
        // A default constructor that just calls the main constructor
        public ScalingLineStyle()
            : this(GeographyUnit.Unknown, double.MaxValue, double.MinValue, new LineWidth(0, 0, 0), new LineWidth(0, 0, 0), GeoColor.SimpleColors.Transparent, GeoColor.SimpleColors.Transparent, GeoColor.SimpleColors.Transparent, 0, 0)
        { }

        // The main constructor, it allows you to set all of the options available.
        public ScalingLineStyle(GeographyUnit mapUnit, double maximumScale, double minimumScale, LineWidth maximumLineWidth, LineWidth minimumLineWidth, GeoColor centerPenColor, GeoColor innerPenColor, GeoColor outerPenColor, float xOffset, float yOffset)
            : base()
        {
            this.MapUnit = mapUnit;
            this.MaximumScale = maximumScale;
            this.MinimumScale = minimumScale;
            this.MaximumLineWidth = maximumLineWidth;
            this.MinimumLineWidth = minimumLineWidth;
            this.CenterPenColor = centerPenColor;
            this.InnerPenColor = innerPenColor;
            this.OuterPenColor = outerPenColor;
            this.XOffset = xOffset;
            this.YOffset = yOffset;
        }

        // This is the map unit to determine the scale.
        public GeographyUnit MapUnit
        { get; set; }

        // The maximum scale will be the largest scale used to calculate the resizing.
        // If the scale gets larger than the max then we compute the scaling based on
        // this number instead.  This is mean that after this scale the image will not get
        // any smaller no matter how much more you zoom out.
        public double MaximumScale
        { get; set; }

        // The minimum scale will be the smallest scale used to calculate the resizing.
        // If the scale gets smaller than the min then we compute the scaling based on
        // this number instead.  This is mean that after this scale the image will not get
        // any larger no matter how much more you zoom in.
        public double MinimumScale
        { get; set; }

        // The MaximumSize is the width of the line at MinimumScale and lower.
        public LineWidth MaximumLineWidth
        { get; set; }

        // The MinimumLineWidth is the size of the image at MaximumScale and higher
        public LineWidth MinimumLineWidth
        { get; set; }

        // The color of the center pen for the line
        public GeoColor CenterPenColor
        { get; set; }

        // The color of the inner pen for the line
        public GeoColor InnerPenColor
        { get; set; }

        // The color of the outer pen for the line
        public GeoColor OuterPenColor
        { get; set; }

        // This is the X offset in pixels for the image.
        public float XOffset
        { get; set; }

        // This is the Y offset in pixels for the image.
        public float YOffset
        { get; set; }

        protected override void DrawCore(IEnumerable<Feature> features, GeoCanvas canvas, Collection<SimpleCandidate> labelsInThisLayer, Collection<SimpleCandidate> labelsInAllLayers)
        {
            // Loop through all of the features being passed in to draw.
            foreach (Feature feature in features)
            {
                // Let’s make sure the features being passed in are line or multi lines.
                WellKnownType shapeWellKnownType = feature.GetWellKnownType();
                if (shapeWellKnownType == WellKnownType.Line || shapeWellKnownType == WellKnownType.Multiline)
                {
                    double currentScale = ExtentHelper.GetScale(canvas.CurrentWorldExtent, canvas.Width, MapUnit);

                    // Enforce the minimum and maximum scale properties
                    if (currentScale > MaximumScale) { currentScale = MaximumScale; }
                    if (currentScale < MinimumScale) { currentScale = MinimumScale; }

                    // Get the width of the line according to the current scale
                    float centerPenWidth = GetCurrentWidth(currentScale, MaximumLineWidth.CenterPenWidth, MinimumLineWidth.CenterPenWidth);
                    float innerPenWidth = GetCurrentWidth(currentScale, MaximumLineWidth.InnerPenWidth, MinimumLineWidth.InnerPenWidth);
                    float outerPenWidth = GetCurrentWidth(currentScale, MaximumLineWidth.OuterPenWidth, MinimumLineWidth.OuterPenWidth);

                    // Draw the line
                    if (outerPenWidth != 0)
                        canvas.DrawLine(feature, new GeoPen(OuterPenColor, outerPenWidth), DrawingLevel.LevelOne, XOffset, YOffset);
                    if (innerPenWidth != 0)
                        canvas.DrawLine(feature, new GeoPen(InnerPenColor, innerPenWidth), DrawingLevel.LevelOne, XOffset, YOffset);
                    if (centerPenWidth != 0)
                        canvas.DrawLine(feature, new GeoPen(CenterPenColor, centerPenWidth), DrawingLevel.LevelOne, XOffset, YOffset);
                }
            }
        }

        private float GetCurrentWidth(double currentScale, double maxWidth, double minWidth)
        {
            return (float)(maxWidth - (currentScale - MinimumScale) * (maxWidth - minWidth) / (MaximumScale - MinimumScale));
        }
    }

    // This class is a wrapper for the widths of line’s pens.
    class LineWidth
    {
        public LineWidth()
            : this(0, 0, 0)
        { }

        public LineWidth(float centerPenWidth, float innerPenWidth, float outerPenWidth)
        {
            this.CenterPenWidth = centerPenWidth;
            this.InnerPenWidth = innerPenWidth;
            this.OuterPenWidth = outerPenWidth;
        }

        public float CenterPenWidth
        { get; set; }

        public float InnerPenWidth
        { get; set; }

        public float OuterPenWidth
        { get; set; }
    }
 
 Thanks, 
  
 Ben

Thanks guys. Didn’t mean to drop the ball on this but I’m mainly a VB programmer with a general understanding of C# and haven’t had time to convert this over and adapt. It’s a novelty at this time so once some other things are tied up this will be an interesting Style type to implement.

 


Nelson,




 


No problem. I think the scaling styles is a cool idea. We entered an issue into out tracking system to come out with a complete line of scaling styles. Thanks for the idea. On the VB / C# I understand. I was a VB developer from way way back and just recently converted to C#. We will try and post more VB samples in the future. For now I converted the code above with a free website, link below. I havent tried to run the code so it may not even compile but it's at least a good start.




 


David




 


Convert C# to VB.NET


developerfusion.com/tool...arp-to-vb/




 




 



Class ScalingLineStyle 
    Inherits Style 
    ' A default constructor that just calls the main constructor 
    Public Sub New() 
        Me.New(GeographyUnit.Unknown, Double.MaxValue, Double.MinValue, New LineWidth(0, 0, 0), New LineWidth(0, 0, 0), GeoColor.SimpleColors.Transparent, _ 
        GeoColor.SimpleColors.Transparent, GeoColor.SimpleColors.Transparent, 0, 0) 
    End Sub 
    
    ' The main constructor, it allows you to set all of the options available. 
    Public Sub New(ByVal mapUnit As GeographyUnit, ByVal maximumScale As Double, ByVal minimumScale As Double, ByVal maximumLineWidth As LineWidth, ByVal minimumLineWidth As LineWidth, ByVal centerPenColor As GeoColor, _ 
    ByVal innerPenColor As GeoColor, ByVal outerPenColor As GeoColor, ByVal xOffset As Single, ByVal yOffset As Single) 
        MyBase.New() 
        Me.MapUnit = mapUnit 
        Me.MaximumScale = maximumScale 
        Me.MinimumScale = minimumScale 
        Me.MaximumLineWidth = maximumLineWidth 
        Me.MinimumLineWidth = minimumLineWidth 
        Me.CenterPenColor = centerPenColor 
        Me.InnerPenColor = innerPenColor 
        Me.OuterPenColor = outerPenColor 
        Me.XOffset = xOffset 
        Me.YOffset = yOffset 
    End Sub 
    
    ' This is the map unit to determine the scale. 
Private _MapUnit As GeographyUnit 
    Public Property MapUnit() As GeographyUnit 
        Get 
            Return _MapUnit 
        End Get 
        Set(ByVal value As GeographyUnit) 
            _MapUnit = value 
        End Set 
    End Property 
    
    ' The maximum scale will be the largest scale used to calculate the resizing. 
    ' If the scale gets larger than the max then we compute the scaling based on 
    ' this number instead. This is mean that after this scale the image will not get 
    ' any smaller no matter how much more you zoom out. 
Private _MaximumScale As Double 
    Public Property MaximumScale() As Double 
        Get 
            Return _MaximumScale 
        End Get 
        Set(ByVal value As Double) 
            _MaximumScale = value 
        End Set 
    End Property 
    
    ' The minimum scale will be the smallest scale used to calculate the resizing. 
    ' If the scale gets smaller than the min then we compute the scaling based on 
    ' this number instead. This is mean that after this scale the image will not get 
    ' any larger no matter how much more you zoom in. 
Private _MinimumScale As Double 
    Public Property MinimumScale() As Double 
        Get 
            Return _MinimumScale 
        End Get 
        Set(ByVal value As Double) 
            _MinimumScale = value 
        End Set 
    End Property 
    
    ' The MaximumSize is the width of the line at MinimumScale and lower. 
Private _MaximumLineWidth As LineWidth 
    Public Property MaximumLineWidth() As LineWidth 
        Get 
            Return _MaximumLineWidth 
        End Get 
        Set(ByVal value As LineWidth) 
            _MaximumLineWidth = value 
        End Set 
    End Property 
    
    ' The MinimumLineWidth is the size of the image at MaximumScale and higher 
Private _MinimumLineWidth As LineWidth 
    Public Property MinimumLineWidth() As LineWidth 
        Get 
            Return _MinimumLineWidth 
        End Get 
        Set(ByVal value As LineWidth) 
            _MinimumLineWidth = value 
        End Set 
    End Property 
    
    ' The color of the center pen for the line 
Private _CenterPenColor As GeoColor 
    Public Property CenterPenColor() As GeoColor 
        Get 
            Return _CenterPenColor 
        End Get 
        Set(ByVal value As GeoColor) 
            _CenterPenColor = value 
        End Set 
    End Property 
    
    ' The color of the inner pen for the line 
Private _InnerPenColor As GeoColor 
    Public Property InnerPenColor() As GeoColor 
        Get 
            Return _InnerPenColor 
        End Get 
        Set(ByVal value As GeoColor) 
            _InnerPenColor = value 
        End Set 
    End Property 
    
    ' The color of the outer pen for the line 
Private _OuterPenColor As GeoColor 
    Public Property OuterPenColor() As GeoColor 
        Get 
            Return _OuterPenColor 
        End Get 
        Set(ByVal value As GeoColor) 
            _OuterPenColor = value 
        End Set 
    End Property 
    
    ' This is the X offset in pixels for the image. 
Private _XOffset As Single 
    Public Property XOffset() As Single 
        Get 
            Return _XOffset 
        End Get 
        Set(ByVal value As Single) 
            _XOffset = value 
        End Set 
    End Property 
    
    ' This is the Y offset in pixels for the image. 
Private _YOffset As Single 
    Public Property YOffset() As Single 
        Get 
            Return _YOffset 
        End Get 
        Set(ByVal value As Single) 
            _YOffset = value 
        End Set 
    End Property 
    
    Protected Overloads Overrides Sub DrawCore(ByVal features As IEnumerable(Of Feature), ByVal canvas As GeoCanvas, ByVal labelsInThisLayer As Collection(Of SimpleCandidate), ByVal labelsInAllLayers As Collection(Of SimpleCandidate)) 
        ' Loop through all of the features being passed in to draw. 
        For Each feature As Feature In features 
            ' Let's make sure the features being passed in are line or multi lines. 
            Dim shapeWellKnownType As WellKnownType = feature.GetWellKnownType() 
            If shapeWellKnownType = WellKnownType.Line OrElse shapeWellKnownType = WellKnownType.Multiline Then 
                Dim currentScale As Double = ExtentHelper.GetScale(canvas.CurrentWorldExtent, canvas.Width, MapUnit) 
                
                ' Enforce the minimum and maximum scale properties 
                If currentScale > MaximumScale Then 
                    currentScale = MaximumScale 
                End If 
                If currentScale < MinimumScale Then 
                    currentScale = MinimumScale 
                End If 
                
                ' Get the width of the line according to the current scale 
                Dim centerPenWidth As Single = GetCurrentWidth(currentScale, MaximumLineWidth.CenterPenWidth, MinimumLineWidth.CenterPenWidth) 
                Dim innerPenWidth As Single = GetCurrentWidth(currentScale, MaximumLineWidth.InnerPenWidth, MinimumLineWidth.InnerPenWidth) 
                Dim outerPenWidth As Single = GetCurrentWidth(currentScale, MaximumLineWidth.OuterPenWidth, MinimumLineWidth.OuterPenWidth) 
                
                ' Draw the line 
                If outerPenWidth <> 0 Then 
                    canvas.DrawLine(feature, New GeoPen(OuterPenColor, outerPenWidth), DrawingLevel.LevelOne, XOffset, YOffset) 
                End If 
                If innerPenWidth <> 0 Then 
                    canvas.DrawLine(feature, New GeoPen(InnerPenColor, innerPenWidth), DrawingLevel.LevelOne, XOffset, YOffset) 
                End If 
                If centerPenWidth <> 0 Then 
                    canvas.DrawLine(feature, New GeoPen(CenterPenColor, centerPenWidth), DrawingLevel.LevelOne, XOffset, YOffset) 
                End If 
            End If 
        Next 
    End Sub 
    
    Private Function GetCurrentWidth(ByVal currentScale As Double, ByVal maxWidth As Double, ByVal minWidth As Double) As Single 
        Return CSng((maxWidth - (currentScale - MinimumScale) * (maxWidth - minWidth) / (MaximumScale - MinimumScale))) 
    End Function 
End Class 

' This class is a wrapper for the widths of line's pens. 
Class LineWidth 
    Public Sub New() 
        Me.New(0, 0, 0) 
    End Sub 
    
    Public Sub New(ByVal centerPenWidth As Single, ByVal innerPenWidth As Single, ByVal outerPenWidth As Single) 
        Me.CenterPenWidth = centerPenWidth 
        Me.InnerPenWidth = innerPenWidth 
        Me.OuterPenWidth = outerPenWidth 
    End Sub 
    
Private _CenterPenWidth As Single 
    Public Property CenterPenWidth() As Single 
        Get 
            Return _CenterPenWidth 
        End Get 
        Set(ByVal value As Single) 
            _CenterPenWidth = value 
        End Set 
    End Property 
    
Private _InnerPenWidth As Single 
    Public Property InnerPenWidth() As Single 
        Get 
            Return _InnerPenWidth 
        End Get 
        Set(ByVal value As Single) 
            _InnerPenWidth = value 
        End Set 
    End Property 
    
Private _OuterPenWidth As Single 
    Public Property OuterPenWidth() As Single 
        Get 
            Return _OuterPenWidth 
        End Get 
        Set(ByVal value As Single) 
            _OuterPenWidth = value 
        End Set 
    End Property 
End Class 


hi guys...


I tried to modify the class so the line is drawn with round end or join points... here is the modification in DrawCore:


// Draw the line

LineStyle testtemp = LineStyles.LocalRoad1;

if (centerPenWidth != 0)

{

GeoPen geoPen = new GeoPen(CenterPenColor, centerPenWidth);

geoPen.LineJoin = DrawingLineJoin.Round;

geoPen.StartCap = DrawingLineCap.Round;

geoPen.DashCap = GeoDashCap.Flat;

geoPen.EndCap = DrawingLineCap.Round;


canvas.DrawLine(feature, geoPen, DrawingLevel.LevelOne, XOffset, YOffset);

}





if (outerPenWidth != 0)

{

GeoPen geoPen = new GeoPen(OuterPenColor, outerPenWidth);

geoPen.LineJoin = DrawingLineJoin.Round;

geoPen.StartCap = DrawingLineCap.Round;

geoPen.DashCap = GeoDashCap.Flat;

geoPen.EndCap = DrawingLineCap.Round;


canvas.DrawLine(feature, geoPen, DrawingLevel.LevelOne, XOffset, YOffset);

}

if (innerPenWidth != 0)

{

GeoPen geoPen = new GeoPen(InnerPenColor, innerPenWidth);

geoPen.LineJoin = DrawingLineJoin.Round;

geoPen.StartCap = DrawingLineCap.Round;

geoPen.DashCap = GeoDashCap.Flat;

geoPen.EndCap = DrawingLineCap.Round;


canvas.DrawLine(feature, geoPen, DrawingLevel.LevelOne, XOffset, YOffset);

}



I get the result as seen in attached image1.jpg (see att)


without it, result as seen in attached image2.jpg (looks like broken ends)


how can I change the code in image1.jpg to have round ends at the end of each line instead of each segment of line?


here is my calling function:




LineWidth stmaxWidth = new LineWidth(10, 10, 12);

LineWidth stminWidth = new LineWidth(4, 4, 6);

ScalingLineStyle stStyle = new ScalingLineStyle(GeographyUnit.Meter, 30000.0, 1000.0, stmaxWidth, stminWidth, LineStyles.LocalRoad1.CenterPen.Color, LineStyles.LocalRoad1.InnerPen.Color, LineStyles.LocalRoad1.OuterPen.Color, 0, 0);

 



 



 


Thanks


 


Paul



here are the attached pictures


image1.jpg:



Image2.jpg:




Paul,



I see what is exactly what is going on.  The issue is all of the pens are drawing on the same drawing level.  For each record we process it is on drawing level one which means for record one we draw the back outer pen then the inner white pen etc for each record, that gives you all the strange drawing artifacts.  What the drawing level does is create separate bitmaps in memory and when you draw the outer pen it draw on the first bitmap and the white pen will draw on a separate bitmap.  When all the records are finished we combine the multiple drawing level together and it gives you  a nice effect.  The code changes are below. Note how I changed the inner pen to draw on drawing level two and the center pen to drawing level three.  This should fix your issue, it was a mistake in the original code.




                ' Draw the line 
                If outerPenWidth <> 0 Then 
                    canvas.DrawLine(feature, New GeoPen(OuterPenColor, outerPenWidth), DrawingLevel.LevelOne, XOffset, YOffset) 
                End If 
                If innerPenWidth <> 0 Then 
                    canvas.DrawLine(feature, New GeoPen(InnerPenColor, innerPenWidth), DrawingLevel.LevelTwo, XOffset, YOffset) 
                End If 
                If centerPenWidth <> 0 Then 
                    canvas.DrawLine(feature, New GeoPen(CenterPenColor, centerPenWidth), DrawingLevel.LevelThree, XOffset, YOffset) 
                End If 



David