Simple Picture Marker Rotate

4680
4
04-11-2013 09:31 AM
Labels (1)
BrianLocke
Occasional Contributor II
Would like to rotate symbol based on attributes, any one have any ideas have not seen any angle in the Docs.  Maybe using the ControlTemplate and then just setting the rendertransform?? not sure?
0 Kudos
4 Replies
MichaelBranscomb
Esri Frequent Contributor
Hi,

Rotating symbols based on an attribute is on the roadmap for a future release but in the mean time the best alternative is to create a renderer which will . This will depend on how many discrete values you have - you could use a UniqueValueRenderer for specific values (e.g. 0, 90, 180, 270) or a ClassBreaksRenderer for ranges of values (0-90, 91-180, 181-270, 271-360).

For an example, take a look at http://resources.arcgis.com/en/help/runtime-wpf/samples/index.html#/Rendering_with_XAML/02q200000036....

I would recommend avoiding ControlTemplating symbols because this is not supported in the hardware accelerated display (i.e. when you set Map.UseAcceleratedDisplay to True).

You can programmatically create symbols too - that's just given me a great idea for a new sample.

Cheers

Mike
0 Kudos
MichaelBranscomb
Esri Frequent Contributor
Hi,

Here's an example of how you could achieve this with a GraphicsLayer / FeatureLayer. It involves creating a unique value renderer with values from 0-360 and creating the same number of picture marker symbols, each rotated by one degree. Then assign the UVR to a graphics layer (in this cases I�??ve just added 100 graphics, each with an "Angle" property of between 0 and 360). If you weren't so concerned about each individual angle, you could use a ClassBreaksRenderer for ranges of angle values.

GraphicsLayer _graphicsLayer;

// Create an ImageBrush
ImageBrush simpleArrow = new ImageBrush();
simpleArrow.ImageSource = new BitmapImage(new Uri("pack://application:,,,/Images/SimpleArrow.png", UriKind.Absolute));
// Found an image on http://www.iconfinder.com/search/?q=simple+arrow

// Add an Ellipse Element & use the ImageBrush as the Fill for the Ellipse
Ellipse myEllipse = new Ellipse();
myEllipse.Fill = simpleArrow;
myEllipse.HorizontalAlignment = HorizontalAlignment.Center;
myEllipse.VerticalAlignment = VerticalAlignment.Center;
myEllipse.Width = 24;
myEllipse.Height = 24;

// Create a UniqueValueRenderer based on the Angle attribute/field in the underlying data
var renderer = new UniqueValueRenderer()
{
    Field = "Angle",
};

// Create UniqueValueInfo objects for each integer value 0-360 and an associated PictureMarkerSymbol for each one, rotated to that value.
for (int i = 0; i < 361; i++)
{
    // Rotate by the angle 0-360 and about the center of the 24x24 pixel image.
    myEllipse.RenderTransform = new RotateTransform(i,12,12);

    //Force a render
    myEllipse.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
    myEllipse.Arrange(new Rect(myEllipse.DesiredSize));
    RenderTargetBitmap render = new RenderTargetBitmap(34, 34, 96, 96, PixelFormats.Default);
    render.Render(myEllipse);

    // Create a PictureMarkerSymbol
    PictureMarkerSymbol pms = new PictureMarkerSymbol()
    {
        Source = render,
    };

    // Create the UniqueValueInfo
    UniqueValueInfo uniqueValueInfo = new UniqueValueInfo() 
    {
        Value = i,
        Symbol = pms,
    };
    // Add the UniqueValueInfo to the Infos property on the renderer
    renderer.Infos.Add(uniqueValueInfo);
}

// Create a new GraphicsLayer 
_graphicsLayer = new GraphicsLayer();

    // Create a instance of the Random class to generate random coordinate pairs.
Random random = new Random();

// Add graphics to a List<Graphic> 
var graphicsList = new List<Graphic>();
for (int i = 0; i < 100; i++)
{
    var x = (random.NextDouble() * 40000000) - 20000000;
    var y = (random.NextDouble() * 40000000) - 20000000;
    var graphic = new Graphic()
    {
        // assign each graphic a number 0, 1, 2 - we''ll use this to represent he color
        Geometry = new MapPoint(x, y),
        Attributes = { { "Angle", random.Next(0,361)} }
    };
    graphicsList.Add(graphic);
}

// Set the renderer
_graphicsLayer.Renderer = renderer;

// Bulk add of graphics - more efficient than adding one graphic at a time
_graphicsLayer.Graphics.AddRange(graphicsList);

// Add layer to Map
MyMap.Layers.Add(_graphicsLayer);


Hope that helps

Cheers

Mike
ChrisPyle
New Contributor II

Mike,
I've just run into this myself. While your solution looks like it will work for me, you mention that this was on the roadmap for the runtime sdk. As it's been a couple years since this post, I was wondering what the current status of this is?

Thanks,

-Chris

0 Kudos
MichaelBranscomb
Esri Frequent Contributor

Hi,

Yes it was added to the WPF SDK as a property on renderers - the links below relate to the SimpleRenderer:

RotationExpression Property

RotationType Property

And you will also find it in the new .NET SDK - again the example here is for a SimpleRenderer:

SimpleRenderer.RotationExpression Property

SimpleRenderer.RotationType Property

Cheers

Mike

0 Kudos