MultiLayerPointSymbol containing SimpleMarkerSymbol not visualized in Runtime 100.11+ versions

2004
30
09-27-2022 04:18 AM
stuartkerkhof
New Contributor

Hi,

In my application I am using multilayerpointsymbols to create complex symbols. Sometimes one of these layers may even contain a simplemarkersymbol.  This is for example useful if the symbol should contain one or more circles, connected by lines for example.

Below code shows how I use the simplemarkersymbol combined with multilayerpointsymbols. This used to work fine. For readability I simplified a bit of the code. In the actual code I read symbol geometry elements from a JSON file, but that will be harder to analyze. 

            SolidStrokeSymbolLayer lineSymbol = new SolidStrokeSymbolLayer(1, Color.Black);

            List<SymbolLayer> symbolLayers = new List<SymbolLayer>
                {
                    lineSymbol
                };

            MultilayerPolylineSymbol multilayerPolylineSymbol = new MultilayerPolylineSymbol(symbolLayers);

            List<MapPoint> mapPoints = new List<MapPoint>();

            Coordinate[] coordinatesArray = new Coordinate[] { new Coordinate(0, 0), new Coordinate(5, 0), new Coordinate(5, 2), new Coordinate(5, -2) };

            foreach (Coordinate coordinate in coordinatesArray)
            {
                mapPoints.Add(new MapPoint(coordinate.X, coordinate.Y));
            }

            VectorMarkerSymbolElement symLyrEl = new VectorMarkerSymbolElement(new Polyline(mapPoints), multilayerPolylineSymbol);

            List<VectorMarkerSymbolElement> vectorMarkerSymbolElements = new List<VectorMarkerSymbolElement>();

            //add custom element to vectormarker symbol
            vectorMarkerSymbolElements.Add(symLyrEl);

            SimpleMarkerSymbol pointSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Circle, Color.Transparent, 5)
            {
                Color = Color.Transparent,
                Outline = new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, Color.Black, 1)
            };

            pointSymbol.Style = SimpleMarkerSymbolStyle.Circle;
            MultilayerPointSymbol multilayerPointSymbol = pointSymbol.ToMultilayerSymbol();

            VectorMarkerSymbolElement vectorMarkerSymbolElement = new VectorMarkerSymbolElement(new MapPoint(0, 10), multilayerPointSymbol);

            //add circle symbol to vectormarker symbol
            vectorMarkerSymbolElements.Add(vectorMarkerSymbolElement);

            VectorMarkerSymbolLayer symLyr = new VectorMarkerSymbolLayer(vectorMarkerSymbolElements);

            List<VectorMarkerSymbolLayer> vectorMarkerSymbolLayers = new List<VectorMarkerSymbolLayer>();

            vectorMarkerSymbolLayers.Add(symLyr);

            MultilayerPointSymbol sym = new MultilayerPointSymbol(vectorMarkerSymbolLayers)
            {
                AngleAlignment = SymbolAngleAlignment.Map,
            };

When updating to runtime versions above 100.11 the symbols are no longer visualized in the map. Though they are still 'renderable', as I am able to visualize them as a separate picture in a non-map environment using the "GetSymbol" function.

 

Has anybody else run into this problem? Did the SDK change on this subject?

 

Tags (1)
0 Kudos
30 Replies
stuartkerkhof
New Contributor

Hi Priyanka,

Good questions. The testsymbol code I provided also does not visualize. only in the legend:

stuartkerkhof_0-1664998913411.png

 

but not in the map.

I should add that uniquevalue renderer is not part of a graphicsoverlay, but a featurecollectionlayer.

 

                    FeatureCollectionTable pointTrackAssetsTable = new FeatureCollectionTable(trackAssetFields, GeometryType.Point, spatialReference)
                    {
                        DisplayName = filterName + arrayNameGeometryType.Item2,
                        Renderer = CreateUniqueValueRenderer(arrayNameGeometryType.Item2, symbolColor, lineEffect)
                    };
                    pointTrackAssetsTable.Renderer.RotationExpression = "[Rotation]";
                    listOfFeatureCollectionTables.Add(arrayNameGeometryType.Item2, pointTrackAssetsTable);

        public UniqueValueRenderer CreateUniqueValueRenderer(string typeName, Color symbolColor, GeometricEffect lineEffect)
        {
            UniqueValueRenderer trackAssetRenderer = new UniqueValueRenderer();
trackAssetRenderer.UniqueValues.Add(new UniqueValue(type, type, testSymbol(), new string[] { type, "design" }));
return trackAssetRenderer;
}
//then features are added, but code is very extensive.. 

//in the end a featurecollection is created
                NewFeatureCollection = new FeatureCollection();
                if (heightLinesTable != null) { NewFeatureCollection.Tables.Add(heightLinesTable); }
                NewFeatureCollection.Tables.Add(insertionPointTable);
                foreach (FeatureCollectionTable pointTable in listOfFeatureCollectionTables.Values)
                {
                    NewFeatureCollection.Tables.Add(pointTable);
                }

//then a featurecollectionlayer is created
            this.FeatureCollectionLayer = new FeatureCollectionLayer(FeatureCollection);
            FeatureCollectionLayer.Name = "NewSituation";
            await FeatureCollectionLayer.LoadAsync();

//then it is loaded in the map
            GeographicMapView.BackgroundGrid.IsVisible = false;
            geographicViewModel.FeatureCollectionLayer.Layers[0].ScaleSymbols = false;


            for (int i = 1; i < geographicViewModel.FeatureCollectionLayer.Layers.Count; i++)
            {
                geographicViewModel.FeatureCollectionLayer.Layers[i].ScaleSymbols = true;
            }
            GeographicMapView.Map.ReferenceScale = 445;

            await GeographicMapView.Map.LoadAsync();
            GeographicMapView.Map.OperationalLayers.AddRange(mapservicesViewModel.ListMapservicesList);
            GeographicMapView.Map.OperationalLayers.Add(geographicViewModel.FeatureCollectionLayer);
            MeasureToolbar.SelectedLinearUnit = MeasureToolbar.LinearUnits[4];
            _ = await GeographicMapView.SetViewpointCenterAsync(geographicViewModel.FeatureCollectionLayer.FullExtent.GetCenter(), scale: 10000);

 

I understand it is hard to troubleshoot without all the code. However the code is quite extensive and depends on multiple files. The above is a summary of what I think the most relevant calls are.

 

while writing this I saw that I define a reference scale, and that I scale the symbols. When I disable that part, the symbols visualize again:

stuartkerkhof_1-1664999726164.png

 

this is not a definite solution ofcourse, as scaling is necessary, but I guess the problem is in the scaling department. Maybe something to do with the newly added "ReferenceProperties" attribute of symbols?

 

 

0 Kudos
stuartkerkhof
New Contributor

 I tried numerous variations for the ReferenceProperties:

stuartkerkhof_2-1665000696560.png

 

also with min/max scale reversed. But that does not seem to be the cause.

Only when setting the referencescale of the view the symbols become invisible. I use this to keep symbols the same actual size, regardless of the zoom in level of the user.

0 Kudos
PriyankaRupani
Esri Contributor

As you are mentioning here in this comment["Only when setting the referencescale of the view the symbols become invisible. I use this to keep symbols the same actual size, regardless of the zoom in level of the user."],
It looks like you want to keep the symbols the same actual size, regardless of the zoom-in/out level?
Then we should not set the reference scale of the map.
Per the definition of map reference scale:
`When no reference scale has been set (the default behavior), symbol and text sizes remain the same on your map as you zoom in and out.`

https://pro.arcgis.com/en/pro-app/latest/help/mapping/properties/map-reference-scales.htm 

0 Kudos
stuartkerkhof
New Contributor

Hi Priyanka,

 

I have been using the referencescale for some time now. So disabling does not make sense. I wrote "same actual size". so if a symbol is real life 10 meters, it should always be 10 meters. That means that screen size will change, but the actual size (relative to a geographical map itself) does not change. But maybe it's a matter of interpretation.

anyhow, I need the reference scale. It is currently not working with the symbols as stated before. Is there a way to get this working again? 

0 Kudos
PriyankaRupani
Esri Contributor

Okay, thanks for the information. 

In the screenshot, you shared above, where you set the ReferenceProperty on MultilayerPolylineSymbol(let's refer as layer1), 
are you also setting the ReferenceProperty on the MultilayerPointSymbol(which is created using SimpleMarkerSymbol)(let's refer to as layer2)
and to the MultilayerPointSymbol (which is created from VectorMarkerSymbolLayer containing the above two layers aka layer1 and layer2?)

are you setting the same min max scale for all symbols? (10000,1.0)

Also, is any default scale set for the SimpleMarkerSymbol, the min and max values?

Can you share the entire code, where you are setting ReferenceProperty to all the symbols? 



0 Kudos
PriyankaRupani
Esri Contributor

Hi Stuart,

Below is the sample code that works with the ReferenceProperties set on all the symbols and they all render within the min-max scale specified for symbols. Using Runtime Android SDK 100.15.0

One thing I noticed is that you are setting the map reference scale and not the map scale

When setting 

SymbolReferenceProperties

we are giving the scale at which the symbols will be visible. So, to see those symbols, we need to set the correct map scale.


Can you try setting 

mapView.setViewpointScaleAsync(445.0)

 in your code?


Entire working code:

var y = 200.0
var x = -50.0

// create a MultilayerPolylineSymbol
val strokeSymbolLayer = SolidStrokeSymbolLayer(5.0, Color.BLACK, LinkedList(), StrokeSymbolLayer.LineStyle3D.TUBE)
strokeSymbolLayer.capStyle = StrokeSymbolLayer.CapStyle.ROUND
var symbolLayer = ArrayList<SymbolLayer>()
symbolLayer.add(strokeSymbolLayer)
val polylineSymbol = MultilayerPolylineSymbol(symbolLayer)
// set symbol scale
val symRefProp = SymbolReferenceProperties(10000.0, 1.0)
polylineSymbol.referenceProperties = symRefProp
var polylineBuilder = PolylineBuilder(mapView.spatialReference)
polylineBuilder.addPoint(Point(x, y, mapView.spatialReference))
polylineBuilder.addPoint(Point(x + 500, y, mapView.spatialReference))
val vmse_polyline = VectorMarkerSymbolElement(polylineBuilder.toGeometry(), polylineSymbol)
var vmselement: MutableList<VectorMarkerSymbolElement> = ArrayList()
vmselement.add(vmse_polyline)



// create SimpleMarkerSymbol, convert to multilayerSymbol
var vec_elem_geom = Geometry.fromJson("{\"curveRings\" : [[[0.0,5.0],[0.0,5.0],{\"c\":[[0.0,5.0],[0.0,-5.0]]}]] }")
val pointSymbol = SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE, Color.BLACK, 300.0f)
val multilayerPointSymbol: MultilayerPointSymbol = pointSymbol.toMultilayerSymbol()
// set symbol scale
val symRefProp1 = SymbolReferenceProperties(10000.0, 1.0)
multilayerPointSymbol.referenceProperties = symRefProp1
// 4. Create a VectorMarkerSymbolElement using geometry and MultiLayerPointSymbol
var vmse_circle = VectorMarkerSymbolElement(vec_elem_geom, multilayerPointSymbol)
vmselement.add(vmse_circle)



// 5. Create a VectorMarkerSymbolLayer with the VectorMarkerSymbolElement
var vectormarkersymbollayer = VectorMarkerSymbolLayer(vmselement)
// 6. create a MultilayerPointSymbol from VectorMarkerSymbolLayer
var vectormarkersymbollayers: MutableList<VectorMarkerSymbolLayer> = ArrayList()
vectormarkersymbollayers.add(vectormarkersymbollayer)
var finalmultilayerPointSymbol = MultilayerPointSymbol(vectormarkersymbollayers)

// set symbol scale
val symRefProp2 = SymbolReferenceProperties(10000.0, 1.0)
finalmultilayerPointSymbol.referenceProperties = symRefProp2

// 7. create Graphic using the MultilayerPointSymbol
mapView.setViewpointScaleAsync(445.0)
var graphic = Graphic(Point(0.0, 0.0, mapView.spatialReference), finalmultilayerPointSymbol)
// 8. Add it to GraphicsOverlay
val graphicsOverlay = GraphicsOverlay(GraphicsOverlay.RenderingMode.STATIC)
// Set a UniqueValueRenderer that uses a SimpleMarkerSymbol
graphicsOverlay.renderer = UniqueValueRenderer()
mapView.graphicsOverlays.add(graphicsOverlay)
graphicsOverlay.graphics.add(graphic)
}

Please try the code in your app with .NET 100.15.0 latest, and let us know?

For mapView.setViewpointScaleAsync(445.0)
When I give scale value below 1.0 and above 10000, I don't see the symbols render, which is correct behaviour. And the symbol renders the same size between the scale 10000 to 1




0 Kudos
PriyankaRupani
Esri Contributor

Hi Stuart,

When setting Reference properties per symbol, we need to set the map scale or zoom into the map until you reach the scale at which the symbols are desired to be visualized. more info and usage with examples here https://www.esri.com/arcgis-blog/products/api-net-win-desktop/developers/defining-scale-based-symbol... 

And Per the definition of map reference scale "Setting a reference scale on an ArcGISMap fixes the size of symbols and text to the desired height and width at that scale. As you zoom in and out, symbols and text will increase or decrease in size accordingly."

In my code, I do set the reference scale too, along with scaleSymbols property set to true and it works as expected.

var y = 200.0
var x = -50.0

// create a MultilayerPolylineSymbol
val strokeSymbolLayer = SolidStrokeSymbolLayer(5.0, Color.BLACK, LinkedList(), StrokeSymbolLayer.LineStyle3D.TUBE)
strokeSymbolLayer.capStyle = StrokeSymbolLayer.CapStyle.ROUND
var symbolLayer = ArrayList<SymbolLayer>()
symbolLayer.add(strokeSymbolLayer)
val polylineSymbol = MultilayerPolylineSymbol(symbolLayer)
// set symbol scale
val symRefProp = SymbolReferenceProperties(10000.0, 1.0)
polylineSymbol.referenceProperties = symRefProp
var polylineBuilder = PolylineBuilder(mapView.spatialReference)
polylineBuilder.addPoint(Point(x, y, mapView.spatialReference))
polylineBuilder.addPoint(Point(x + 500, y, mapView.spatialReference))
val vmse_polyline = VectorMarkerSymbolElement(polylineBuilder.toGeometry(), polylineSymbol)
var vmselement: MutableList<VectorMarkerSymbolElement> = ArrayList()
vmselement.add(vmse_polyline)


// create SimpleMarkerSymbol, convert to multilayerSymbol
var vec_elem_geom = Geometry.fromJson("{\"curveRings\" : [[[0.0,5.0],[0.0,5.0],{\"c\":[[0.0,5.0],[0.0,-5.0]]}]] }")
val pointSymbol = SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE, Color.BLACK, 300.0f)

val multilayerPointSymbol: MultilayerPointSymbol = pointSymbol.toMultilayerSymbol()
// set symbol scale
val symRefProp1 = SymbolReferenceProperties(10000.0, 1.0)
multilayerPointSymbol.referenceProperties = symRefProp1
// 4. Create a VectorMarkerSymbolElement using geometry and MultiLayerPointSymbol
var vmse_circle = VectorMarkerSymbolElement(vec_elem_geom, multilayerPointSymbol)
vmselement.add(vmse_circle)


// 5. Create a VectorMarkerSymbolLayer with the VectorMarkerSymbolElement
var vectormarkersymbollayer = VectorMarkerSymbolLayer(vmselement)
// 6. create a MultilayerPointSymbol from VectorMarkerSymbolLayer
var vectormarkersymbollayers: MutableList<VectorMarkerSymbolLayer> = ArrayList()
vectormarkersymbollayers.add(vectormarkersymbollayer)
var finalmultilayerPointSymbol = MultilayerPointSymbol(vectormarkersymbollayers)

// set symbol scale
val symRefProp2 = SymbolReferenceProperties(10000.0, 1.0)
finalmultilayerPointSymbol.referenceProperties = symRefProp2

// 7. create Graphic using the MultilayerPointSymbol
var graphic = Graphic(Point(0.0, 0.0, mapView.spatialReference), finalmultilayerPointSymbol)
// 8. Add it to GraphicsOverlay
val graphicsOverlay = GraphicsOverlay(GraphicsOverlay.RenderingMode.STATIC)
// Set a UniqueValueRenderer that uses a SimpleMarkerSymbol
graphicsOverlay.renderer = UniqueValueRenderer()

// go.scaleSymbols default value is false
graphicsOverlay.isScaleSymbols = true
mapView.setViewpointScaleAsync(500.0)
mapView.map.referenceScale = 500.0

mapView.graphicsOverlays.add(graphicsOverlay)
graphicsOverlay.graphics.add(graphic)

 

 

0 Kudos
stuartkerkhof
New Contributor

Hi Priyanka,

 

thanks for trying. But this does not seem to solve the issue.

In your code I see you're adding a unique value renderer. But you're not doing anything with it. The symbol is directly added to the graphics overlay. In my code, symbols are loaded at runtime using a uniquevaluerenderer to load the appropriate symbols with specific feature properties ( "attributes").

 

I tried only setting the map scale view, but that only changes the scale of the view at a certain moment. Reference scale sets the symbols to a constant "real life" size. as stated in the SDK docs: " // The reference scale of the map is the scale at which a client should view the
// map for the feature symbols and text to appear at their authored size.
// If the client changes the viewing scale, then feature symbols and text will grow
// or shrink to keep a consistent size on the map (not the screen). This only happens
// if the reference scale is greater than zero and for feature layers that have
// Esri.ArcGISRuntime.Mapping.FeatureLayer.ScaleSymbols set to true, otherwise the
// symbols and text stay at their authored size."

this is the desired behavior for me. 

 

I have tried setting the reference properties of the symbols exactly as in your example, but that doesn't work.

 

By the way, In my original code I never used the referenceproperties property of symbols. This was only introduced in runtime 100.12. I'm only trying it out now because I thought this might be a part of the solution.

 

Isn't there any way you can check out the actual SDK code and figure out what was changed with regards to referencescale and simplemarkersymbol conversion? It seems to me something is going wrong with the conversion of a simplemarkersymbol to multilayerpointsymbol.

 

kind regards,

Stuart

 

0 Kudos
stuartkerkhof
New Contributor

 

 public async Task<FeatureCollection> CreateNewFeatureCollection(NetTopologySuite.Features.FeatureCollection inputFeatureCollection, Color symbolColor,
            bool schematic = false, HashSet<string> puicFilter = null, string filterName = "", GeometricEffect lineEffect = null)
        {
            FeatureCollection NewFeatureCollection = null;

            List<Field> trackAssetFields = new List<Field>();
            Field puicField = new Field(FieldType.Guid, "Puic", "Puic Value", 50);
            Field nameField = new Field(FieldType.Text, "Name", "Name Value", 50);
            Field typeField = new Field(FieldType.Text, "Type", "Type Value", 50);
            Field situationField = new Field(FieldType.Text, "Situation", "Situation Value", 50);
            Field sideField = new Field(FieldType.Text, "Side", "Side Value", 50);
            Field heightField = new Field(FieldType.Float32, "HeightAverage", "HeightAverage Value", 50);
            Field rotationField = new Field(FieldType.Float32, "Rotation", "Rotation Value", 0);
            Field kilometerRibbonField = new Field(FieldType.Float32, "KMRibbon", "KMRibbon Value", 50);
            Field labelPositionField = new Field(FieldType.Float32, "LabelPosition", "LabelPosition Value", 0);

            trackAssetFields.Add(puicField);
            trackAssetFields.Add(nameField);
            trackAssetFields.Add(typeField);
            trackAssetFields.Add(sideField);
            trackAssetFields.Add(rotationField);
            trackAssetFields.Add(kilometerRibbonField);
            trackAssetFields.Add(labelPositionField);
            trackAssetFields.Add(situationField);

            List<Field> lineFields = new List<Field>
            {
                puicField,
                nameField
            };

            SpatialReference spatialReference = schematic ? new SpatialReference(4839) : new SpatialReference(28992);

            Dictionary<string, FeatureCollectionTable> listOfFeatureCollectionTables = new Dictionary<string, FeatureCollectionTable>();

            NetTopologySuite.Features.FeatureCollection featureCollection = new NetTopologySuite.Features.FeatureCollection();
            inputFeatureCollection.ToList().ForEach(x => featureCollection.Add(x));

            //filter feature collection
            if (puicFilter != null)
            {
                featureCollection.Where(x => !puicFilter.Contains(x.Attributes["puic"].ToString())).ToList().ForEach(x => featureCollection.Remove(x));
            }


            (string, string)[] listOfArrays = featureCollection
                .Where(x => x.Attributes.Count > 2)
                .GroupBy(x => x.Attributes["arrayName"])
                .Select(x => (x.First().Geometry.GeometryType, x.First().Attributes["arrayName"].ToString()))
                .ToArray();


            FeatureCollectionTable heightLinesTable = null;

            FeatureCollectionTable insertionPointTable = new FeatureCollectionTable(trackAssetFields, GeometryType.Point, spatialReference)
            {
                DisplayName = "insertion points",
                Renderer = new SimpleRenderer(new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.X, Color.Purple, 5))
            };
            IConvenientObjectDesignService convenientObjectDesignService = NetworkAgentFunctionLib.FunctionsKernel.Get<IConvenientObjectDesignService>();

            foreach ((string, string) arrayNameGeometryType in listOfArrays)
            {
                if (arrayNameGeometryType.Item1 == nameof(NetTopologySuite.Geometries.Point))
                {
                    FeatureCollectionTable pointTrackAssetsTable = new FeatureCollectionTable(trackAssetFields, GeometryType.Point, spatialReference)
                    {
                        DisplayName = filterName + arrayNameGeometryType.Item2,
                        Renderer = CreateUniqueValueRenderer(arrayNameGeometryType.Item2, symbolColor, lineEffect)
                    };
                    pointTrackAssetsTable.Renderer.RotationExpression = "[Rotation]";
                    listOfFeatureCollectionTables.Add(arrayNameGeometryType.Item2, pointTrackAssetsTable);


                }
                else if (arrayNameGeometryType.Item1 == nameof(NetTopologySuite.Geometries.LineString) ||
                    arrayNameGeometryType.Item1 == nameof(NetTopologySuite.Geometries.MultiLineString))
                {
                    FeatureCollectionTable lineTrackAssetsTable = new FeatureCollectionTable(trackAssetFields, GeometryType.Polyline, spatialReference)
                    {
                        DisplayName = filterName + arrayNameGeometryType.Item2
                    };
                    switch (arrayNameGeometryType.Item2)
                    {
                        case nameof(RHDHVRailAPI.IMSpoorCore.RailConnection):
                            if (!schematic)
                            {
                                trackAssetFields.Add(heightField);
                                heightLinesTable = CreateHeightMapTable(filterName, trackAssetFields, spatialReference);
                                lineTrackAssetsTable.Renderer = CreateRenderer(GeometryType.Polyline, Color.DimGray, SimpleLineSymbolStyle.LongDash);
                                listOfFeatureCollectionTables.Add(arrayNameGeometryType.Item2, lineTrackAssetsTable);
                            }
                            else
                            {
                                lineTrackAssetsTable.Renderer = CreateRenderer(GeometryType.Polyline, Color.ForestGreen);
                                listOfFeatureCollectionTables.Add(arrayNameGeometryType.Item2, lineTrackAssetsTable);
                            }
                            break;
                        case nameof(RHDHVRailAPI.IMSpoorCore.AxleCounterSection):
                        case nameof(RHDHVRailAPI.IMSpoorCore.TrackCircuit):
                            lineTrackAssetsTable.Renderer = CreateRenderer(GeometryType.Polyline, Color.MediumPurple, SimpleLineSymbolStyle.Dot);
                            listOfFeatureCollectionTables.Add(arrayNameGeometryType.Item2, lineTrackAssetsTable);
                            break;
                        default:
                            lineTrackAssetsTable.Renderer = CreateRenderer(GeometryType.Polyline, Color.Black, SimpleLineSymbolStyle.Solid);
                            listOfFeatureCollectionTables.Add(arrayNameGeometryType.Item2, lineTrackAssetsTable);
                            break;
                    }
                }
            }


            foreach (NetTopologySuite.Features.IFeature feature in featureCollection)
            {
                try
                {
                    if (feature.Geometry is NetTopologySuite.Geometries.Point)
                    {
                        if (feature.Geometry.Coordinates.FirstOrDefault() == null) { continue; }
                        // Create a new point feature, provide geometry and attribute values
                        Esri.ArcGISRuntime.Data.Feature pointFeature = listOfFeatureCollectionTables[feature.Attributes["arrayName"].ToString()].CreateFeature();
                        NetTopologySuite.Geometries.Point currentPoint = feature.Geometry as NetTopologySuite.Geometries.Point;

                        pointFeature.SetAttributeValue(puicField, Guid.Parse(feature.Attributes["puic"].ToString()));
                        pointFeature.SetAttributeValue(nameField, feature.Attributes["name"]);
                        pointFeature.SetAttributeValue(typeField, feature.Attributes["type"]);
                        pointFeature.SetAttributeValue(situationField, "design");
                        if (feature.Attributes.GetNames().Contains("side"))
                        {
                            pointFeature.SetAttributeValue(typeField, feature.Attributes["type"].ToString());
                        }
                        if (feature.Attributes.GetNames().Contains("LabelPosition") && feature.Attributes.GetNames().Contains("KMRibbonInfo"))
                        {
                            pointFeature.SetAttributeValue(labelPositionField, float.Parse(feature.Attributes["LabelPosition"].ToString()));
                            pointFeature.SetAttributeValue(kilometerRibbonField, float.Parse(feature.Attributes["KMRibbonInfo"].ToString()));
                        }
                        pointFeature.SetAttributeValue(rotationField, float.Parse(feature.Attributes["rotation"] == null ? "0" : feature.Attributes["rotation"].ToString()));
                        MapPoint point1 = new MapPoint(currentPoint.Coordinates[0].X, currentPoint.Coordinates[0].Y, spatialReference);
                        pointFeature.Geometry = point1;

                        Esri.ArcGISRuntime.Data.Feature insertionPointFeature = insertionPointTable.CreateFeature();
                        insertionPointFeature.Geometry = point1;
                        insertionPointFeature.SetAttributeValue(typeField, "InsertionPoint");
                        try
                        {
                            await listOfFeatureCollectionTables[feature.Attributes["arrayName"].ToString()].AddFeatureAsync(pointFeature);
                            await insertionPointTable.AddFeatureAsync(insertionPointFeature);
                        }
                        catch (Exception e2)
                        {
                            _ = MessageBox.Show(e2.ToString(), "Error");
                        }
                    }
                    else if (feature.Geometry is NetTopologySuite.Geometries.LineString && feature.Geometry.Coordinates.Length > 1)
                    {
                        // Create a new line feature, provide geometry and attribute values
                        Feature lineFeature = listOfFeatureCollectionTables[feature.Attributes["arrayName"].ToString()].CreateFeature();
                        lineFeature.SetAttributeValue(puicField, Guid.Parse(feature.Attributes["puic"].ToString()));
                        lineFeature.SetAttributeValue(nameField, feature.Attributes["name"]);
                        lineFeature.SetAttributeValue(typeField, feature.Attributes["type"]);

                        List<MapPoint> mapPoints = new List<MapPoint>();
                        NetTopologySuite.Geometries.LineString currentLineString = feature.Geometry as NetTopologySuite.Geometries.LineString;
                        mapPoints.AddRange(currentLineString.Coordinates.Select(cdns => new MapPoint(cdns.X, cdns.Y)));

                        if (feature.Attributes["arrayName"].ToString() == nameof(RHDHVRailAPI.IMSpoorCore.RailConnection) && !schematic && heightLinesTable != null)
                        {
                            for (int i = 0; i < currentLineString.Coordinates.Length - 1; i++)
                            {
                                Feature subLineFeature = heightLinesTable.CreateFeature();
                                NetTopologySuite.Geometries.Coordinate cdns = currentLineString.Coordinates[i];
                                NetTopologySuite.Geometries.Coordinate nextCdn = currentLineString.Coordinates[i + 1];
                                Polyline subLine = new Polyline(new List<MapPoint>() { new MapPoint(cdns.X, cdns.Y), new MapPoint(nextCdn.X, nextCdn.Y) });
                                subLineFeature.SetAttributeValue(heightField, float.Parse((Math.Abs(cdns.Z - nextCdn.Z) + cdns.Z).ToString()));
                                subLineFeature.Geometry = subLine;
                                await heightLinesTable.AddFeatureAsync(subLineFeature);
                            }
                        }

                        Polyline line = new Polyline(mapPoints);
                        lineFeature.Geometry = line;
                        await listOfFeatureCollectionTables[feature.Attributes["arrayName"].ToString()].AddFeatureAsync(lineFeature);
                    }
                    else if (feature.Geometry is NetTopologySuite.Geometries.MultiLineString multiLineString && feature.Geometry.Coordinates.Length > 1)
                    {
                        Feature lineFeature = listOfFeatureCollectionTables[feature.Attributes["arrayName"].ToString()].CreateFeature();
                        lineFeature.SetAttributeValue(puicField, Guid.Parse(feature.Attributes["puic"].ToString()));
                        lineFeature.SetAttributeValue(nameField, feature.Attributes["name"]);
                        lineFeature.SetAttributeValue(typeField, feature.Attributes["type"]);

                        List<Segment[]> allSegments = new List<Segment[]>();
                        foreach (NetTopologySuite.Geometries.Geometry lineString in multiLineString.Geometries)
                        {
                            List<Segment> segments = new List<Segment>();
                            for (int i = 0; i < lineString.Coordinates.Length - 1; i++)
                            {
                                var startCoordinate = lineString.Coordinates[i];
                                var endCoordinate = lineString.Coordinates[i + 1];
                                segments.Add(
                                    new Esri.ArcGISRuntime.Geometry.LineSegment
                                    (
                                        new MapPoint(startCoordinate.X, startCoordinate.Y),
                                        new MapPoint(endCoordinate.X, endCoordinate.Y), spatialReference
                                    ));
                            }
                            allSegments.Add(segments.ToArray());
                        }

                        Polyline line = new Polyline(allSegments);

                        lineFeature.Geometry = line;
                        await listOfFeatureCollectionTables[feature.Attributes["arrayName"].ToString()].AddFeatureAsync(lineFeature);
                    }
                }
                catch (Exception e)
                {
                    //TODO: handle exception
                    //this means something has gone wrong while loading, should be added to a load error list
                }
            }


            try
            {
                // Create a feature collection and add the feature collection tables
                NewFeatureCollection = new FeatureCollection();
                if (heightLinesTable != null) { NewFeatureCollection.Tables.Add(heightLinesTable); }
                NewFeatureCollection.Tables.Add(insertionPointTable);
                foreach (FeatureCollectionTable pointTable in listOfFeatureCollectionTables.Values)
                {
                    NewFeatureCollection.Tables.Add(pointTable);
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString(), "Error");
            }
            return NewFeatureCollection;
        }

        private static FeatureCollectionTable CreateHeightMapTable(string filterName, List<Field> trackAssetFields, SpatialReference spatialReference)
        {
            FeatureCollectionTable heightLinesTable = new FeatureCollectionTable(trackAssetFields, GeometryType.Polyline, spatialReference)
            {
                DisplayName = filterName + "HeightMap",

                Renderer = new ClassBreaksRenderer("HeightAverage", new List<ClassBreak>()
                                    {
                                        new ClassBreak("0 to 1", "-4 - -3", -3,-2, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, Color.FromArgb(255,255,255,0), 3)),
                                        new ClassBreak("0 to 1", "-3 - -2", -3,-2, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, Color.FromArgb(255,255,250,0), 3)),
                                        new ClassBreak("0 to 1", "-2 - -1", -2,-1, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, Color.FromArgb(255,255,245,0), 3)),
                                        new ClassBreak("0 to 1", "-1 - -0", -1, 0, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, Color.FromArgb(255,255,244,0), 3)),
                                        new ClassBreak("0 to 1", "0 - 1",  0, 1, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid,   Color.FromArgb(255,255,242,0), 3)),
                                        new ClassBreak("0 to 1", "1 - 2",  1, 2, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid,   Color.FromArgb(255,255,240,0), 3)),
                                        new ClassBreak("0 to 1", "2 - 3",  2, 3, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid,   Color.FromArgb(255,255,220,0), 3)),
                                        new ClassBreak("0 to 1", "3 - 4",  3, 4, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid,   Color.FromArgb(255,255,200,0), 3)),
                                        new ClassBreak("0 to 1", "4 - 5",  4, 5, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid,   Color.FromArgb(255,255,180,0), 3)),
                                        new ClassBreak("0 to 1", "5 - 6",  5, 6, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid,   Color.FromArgb(255,255,160,0), 3)),
                                        new ClassBreak("0 to 1", "6 - 7",  6, 7, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid,   Color.FromArgb(255,255,140,0), 3)),
                                        new ClassBreak("0 to 1", "7 - 8",  7, 8, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid,   Color.FromArgb(255,255,120,0), 3)),
                                        new ClassBreak("0 to 1", "8 - 9",  8, 9, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid,   Color.FromArgb(255,255,100,0), 3)),
                                        new ClassBreak("0 to 1", "9 - 10,",  9, 10, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid,  Color.FromArgb(255,255,80,0), 3)),
                                        new ClassBreak("0 to 1", "10 - 11",  10, 11, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, Color.FromArgb(255,255,60,0), 3)),
                                        new ClassBreak("0 to 1", "11 - 12",  11, 12, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, Color.FromArgb(255,255,40,0), 3)),
                                        new ClassBreak("0 to 1", "12 - 13",  12, 13, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, Color.FromArgb(255,255,35,0), 3)),
                                        new ClassBreak("0 to 1", "13 - 14",  13, 14, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, Color.FromArgb(255,255,30,0), 3)),
                                        new ClassBreak("0 to 1", "14 - 15",  13, 14, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, Color.FromArgb(255,255,20,0), 3)),
                                        new ClassBreak("0 to 1", "15 - 16",  13, 14, new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, Color.FromArgb(255,255,10,0), 3)),
                                    }
            )
            };
            return heightLinesTable;
        }




        /// <summary>
        /// this method creates a renderer that contains symbols for each unique object type
        /// symbols have been extracted from autocad plugin and are contained in this project in a json file
        /// </summary>
        /// <returns></returns>
        public UniqueValueRenderer CreateUniqueValueRenderer(string typeName, Color symbolColor, GeometricEffect lineEffect)
        {

            string symbolsJSON = System.IO.File.ReadAllText(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "/resources/symbols_autocad_updated.json");
            GeoJSON.Net.Feature.FeatureCollection symbolCollection = JsonConvert.DeserializeObject<GeoJSON.Net.Feature.FeatureCollection>(symbolsJSON);
            IMSpoorObjectCreationFunctions objectCreationFunctions = CoreFunctionLib.FunctionsKernel.Get<IMSpoorObjectCreationFunctions>();
            UniqueValueRenderer trackAssetRenderer = new UniqueValueRenderer();
            trackAssetRenderer.FieldNames.Add("type");
            trackAssetRenderer.FieldNames.Add("situation");

            object MagicallyCreateOtherInstance(string className)
            {
                try
                {
                    var assembly = Assembly.GetAssembly(typeof(VirtualDangerPoint));
                    var assemblyNA = Assembly.GetAssembly(typeof(VirtualTrackAsset));

                    List<Type> typesList = new List<Type>();

                    foreach (Type t in assembly.GetTypes())
                    {
                        typesList.Add(t);
                    }

                    foreach (Type t in assemblyNA.GetTypes())
                    {
                        typesList.Add(t);
                    }

                    var types = typesList.First(t => t.Name == className);

                    return Activator.CreateInstance(types);
                }
                catch
                {
                    return null;
                }
            }

            object imspoorObjectTypeInstance = ImspoorType.GetByName(typeName) != null ?
                objectCreationFunctions.CreateInstance(typeName) : MagicallyCreateOtherInstance(typeName);

            string type = "";
            PropertyInfo typeProperty = imspoorObjectTypeInstance.GetType().GetProperty
                    ($"{Char.ToLowerInvariant(imspoorObjectTypeInstance.GetType().Name[0]) + imspoorObjectTypeInstance.GetType().Name.Substring(1)}Type");


            Type enumType = null;

            if (typeProperty != null)
            {
                enumType = typeProperty.PropertyType;
            }
            else
            {
                type = imspoorObjectTypeInstance.GetType().Name;
            }

            for (int i = 0; i < symbolCollection.Features.Count; i++)
            {
                GeoJSON.Net.Feature.Feature feature = symbolCollection.Features[i];
                if (type != feature.Properties["assetName"].ToString() && !(enumType != null && Enum.IsDefined(enumType, feature.Properties["assetName"].ToString())))
                {
                    continue;
                }

                List<VectorMarkerSymbolElement> vectorMarkerSymbolElements = new List<VectorMarkerSymbolElement>();

                SolidStrokeSymbolLayer lineSymbol = lineEffect is null ? new SolidStrokeSymbolLayer(1, symbolColor) : new SolidStrokeSymbolLayer(1, symbolColor, new List<GeometricEffect>() { lineEffect });

                List<SymbolLayer> symbolLayers = new List<SymbolLayer>
                {
                    lineSymbol
                };

                MultilayerPolylineSymbol multilayerPolylineSymbol = new MultilayerPolylineSymbol(symbolLayers);
                double symbolSizeLength = 15;

                if (feature.Geometry is GeoJSON.Net.Geometry.MultiLineString)
                {
                    vectorMarkerSymbolElements = GetSymbolGeometry(feature, out NetTopologySuite.Geometries.MultiLineString multiLineString, multilayerPolylineSymbol, symbolColor, lineEffect);

                    if (multiLineString.Envelope.Area > 0)
                    {
                        List<double> xS = new List<double>();
                        List<double> yS = new List<double>();
                        foreach (NetTopologySuite.Geometries.Coordinate cdn in multiLineString.Coordinates)
                        {
                            xS.Add(cdn.X);
                            yS.Add(cdn.Y);
                        }
                        double maxX = xS.Max();
                        double minX = xS.Min();
                        double maxY = yS.Max();
                        double minY = yS.Min();
                        double pythLength = Math.Sqrt(Math.Pow((maxX - minX), 2) + Math.Pow((maxY - minY), 2));
                        symbolSizeLength = pythLength;
                    }
                }

                List<VectorMarkerSymbolLayer> vectorMarkerSymbolLayers = new List<VectorMarkerSymbolLayer>();

                VectorMarkerSymbolLayer symLyr = new VectorMarkerSymbolLayer(vectorMarkerSymbolElements);
                double minXel = 0;
                double maxXel = 0;
                foreach (VectorMarkerSymbolElement element in vectorMarkerSymbolElements)
                {

                    maxXel = maxXel > element.Geometry.Extent.XMax ? maxXel : element.Geometry.Extent.XMax;
                    minXel = minXel < element.Geometry.Extent.XMin ? minXel : element.Geometry.Extent.XMin;

                }

                symLyr.Anchor = new SymbolAnchor(-0.5, 0, SymbolAnchorPlacementMode.Relative);

                MultilayerPointSymbol sym;
                if (feature.Properties["assetName"].ToString() == "Unknown")
                {
                    symLyr.Size = symbolSizeLength * 0.07;
                }
                else if (Enum.IsDefined(typeof(RHDHVRailAPI.IMSpoorCore.tSignalEnum), feature.Properties["assetName"].ToString()))
                {

                    symLyr.Size = symbolSizeLength * 1.5;
                }
                else if (feature.Properties["assetName"].ToString().Contains("Crossing"))
                {
                    symLyr.Size = symbolSizeLength * 1.5;
                    symLyr.Anchor = new SymbolAnchor(0, 0, SymbolAnchorPlacementMode.Relative);
                }
                else if (feature.Properties["assetName"].ToString() == "SingleSwitch")
                {

                    symLyr.Size = symbolSizeLength * 1;
                    symLyr.Anchor = new SymbolAnchor(0, -0.5, SymbolAnchorPlacementMode.Relative);
                    List<VectorMarkerSymbolElement> singleSwitchMirrored = GetSymbolGeometry(feature, out NetTopologySuite.Geometries.MultiLineString multiLineString, multilayerPolylineSymbol, symbolColor, lineEffect, -1);
                    List<VectorMarkerSymbolLayer> vectorMarkerSymbolLayersSwitch = new List<VectorMarkerSymbolLayer>();
                    VectorMarkerSymbolLayer symLyrSwitch = new VectorMarkerSymbolLayer(singleSwitchMirrored)
                    {
                        Size = symbolSizeLength * 1,
                        Anchor = new SymbolAnchor(0, 0.5, SymbolAnchorPlacementMode.Relative)
                    };
                    vectorMarkerSymbolLayersSwitch.Add(symLyrSwitch);
                    sym = new MultilayerPointSymbol(vectorMarkerSymbolLayersSwitch)
                    {
                        AngleAlignment = SymbolAngleAlignment.Map
                    };
                    trackAssetRenderer.UniqueValues.Add(new UniqueValue(feature.Properties["assetName"].ToString(), feature.Properties["assetName"].ToString(), sym, new string[] { feature.Properties["assetName"].ToString() + "R", "design" }));


                }
                else if (feature.Properties["assetName"].ToString() == "StopMarkerBoard")
                {
                    symLyr.Size = symbolSizeLength * 2;
                    symLyr.Anchor = new SymbolAnchor(-0.5, 0, SymbolAnchorPlacementMode.Relative);
                    List<VectorMarkerSymbolElement> stopMarkerBoardMirrored = GetSymbolGeometry(feature, out NetTopologySuite.Geometries.MultiLineString multiLineString, multilayerPolylineSymbol, symbolColor, lineEffect, -1);
                    List<VectorMarkerSymbolLayer> vectorMarkerSymbolLayersSwitch = new List<VectorMarkerSymbolLayer>();
                    VectorMarkerSymbolLayer symlyrSMB = new VectorMarkerSymbolLayer(stopMarkerBoardMirrored)
                    {
                        Size = symbolSizeLength * 2,
                        Anchor = new SymbolAnchor(-0.5, 0, SymbolAnchorPlacementMode.Relative)
                    };
                    vectorMarkerSymbolLayersSwitch.Add(symlyrSMB);
                    sym = new MultilayerPointSymbol(vectorMarkerSymbolLayersSwitch)
                    {
                        AngleAlignment = SymbolAngleAlignment.Map
                    };
                    trackAssetRenderer.UniqueValues.Add(new UniqueValue(feature.Properties["assetName"].ToString(), feature.Properties["assetName"].ToString(), sym, new string[] { feature.Properties["assetName"].ToString() + "R", "design" }));
                }
                else if (ImspoorType.GetByName("tDepartureSignalEnum") != null && Enum.IsDefined(objectCreationFunctions.CreateInstance("tDepartureSignalEnum").GetType(), feature.Properties["assetName"].ToString()))
                {
                    vectorMarkerSymbolElements = GetSymbolGeometry(feature, out NetTopologySuite.Geometries.MultiLineString multiLineString, multilayerPolylineSymbol, symbolColor, lineEffect, 1);
                    symLyr = new VectorMarkerSymbolLayer(vectorMarkerSymbolElements)
                    {
                        Size = symbolSizeLength * 3,
                        Anchor = new SymbolAnchor(0, -0.26, SymbolAnchorPlacementMode.Relative),
                        Heading = 180
                    };
                }
                else if (Enum.IsDefined(typeof(RHDHVRailAPI.IMSpoorCore.tSpeedSignEnum), feature.Properties["assetName"].ToString()))
                {
                    symLyr.Size = symbolSizeLength * 2;
                }
                else if (Enum.IsDefined(typeof(RHDHVRailAPI.IMSpoorCore.tSignEnum), feature.Properties["assetName"].ToString()))
                {
                    symLyr.Size = symbolSizeLength * 2;
                }
                else if (feature.Properties["assetName"].ToString() == "AxleCounterDetectionPoint")
                {
                    symLyr.Size = symbolSizeLength * 4;
                    symLyr.Anchor = new SymbolAnchor(0, -0.5, SymbolAnchorPlacementMode.Relative);
                }
                else if (feature.Properties["assetName"].ToString() == "InsulatedJoint")
                {
                    symLyr.Size = symbolSizeLength * 2;
                    symLyr.Anchor = new SymbolAnchor(0, 0, SymbolAnchorPlacementMode.Relative);
                }
                else if (feature.Properties["assetName"].ToString() == "ATBVVBeacon")
                {
                    symLyr.Size = symbolSizeLength * 4;
                    symLyr.Anchor = new SymbolAnchor(0, 0.5, SymbolAnchorPlacementMode.Relative);
                }
                else if (feature.Properties["assetName"].ToString() == "PPCTrack")
                {
                    symLyr.Anchor = new SymbolAnchor(0, 0, SymbolAnchorPlacementMode.Relative);
                }
                else if (feature.Properties["assetName"].ToString() == "Pedal")
                {
                    symLyr.Size = symbolSizeLength * 2;
                }
                else if (feature.Properties["assetName"].ToString() == "None")
                {
                    symLyr.Anchor = new SymbolAnchor(0, 0, SymbolAnchorPlacementMode.Relative);
                    symLyr.Size = symbolSizeLength * 1;
                }
                vectorMarkerSymbolLayers.Add(symLyr);
                sym = new MultilayerPointSymbol(vectorMarkerSymbolLayers)
                {
                    AngleAlignment = SymbolAngleAlignment.Map,
                };

                trackAssetRenderer.UniqueValues.Add(new UniqueValue(feature.Properties["assetName"].ToString(),
                    feature.Properties["assetName"].ToString(), sym, new string[] { feature.Properties["assetName"].ToString(), "design" }));


                MultilayerPointSymbol redSym = new MultilayerPointSymbol(vectorMarkerSymbolLayers)
                {
                    Color = Color.Red
                };
            }

            if (imspoorObjectTypeInstance is RHDHVRailAPI.FlankProtection.Objects.VirtualDangerPoint)
            {
                trackAssetRenderer.UniqueValues.Add(new UniqueValue(type, type, testSymbol(), new string[] { type, "design" }));
            }
            else if (imspoorObjectTypeInstance is RHDHVRailAPI.NetworkAgent.ConvenientObjects.JunctionMathematicalPoint)
            {
                trackAssetRenderer.UniqueValues.Add(new UniqueValue(type, type, new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Circle, Color.Black, 5), new string[] { type, "design" }));
            }
            else if (imspoorObjectTypeInstance is RHDHVRailAPI.NetworkAgent.ConvenientObjects.PlatformWallEndMarker)
            {
                trackAssetRenderer.UniqueValues.Add(new UniqueValue(type, type, new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Cross, Color.Yellow, 5), new string[] { type, "design" }));
            }

            return trackAssetRenderer;
        }

        private List<VectorMarkerSymbolElement> GetSymbolGeometry(GeoJSON.Net.Feature.Feature feature, out
           NetTopologySuite.Geometries.MultiLineString outputmultiLineString, MultilayerPolylineSymbol multilayerPolylineSymbol, Color symbolColor, GeometricEffect lineEffect, int mirrorMultiplier = 1)
        {

            List<VectorMarkerSymbolElement> vectorMarkerSymbolElements = new List<VectorMarkerSymbolElement>();

            GeoJSON.Net.Geometry.MultiLineString multiLineString = feature.Geometry as GeoJSON.Net.Geometry.MultiLineString;
            List<NetTopologySuite.Geometries.LineString> linestringsNet = new List<NetTopologySuite.Geometries.LineString>();
            foreach (GeoJSON.Net.Geometry.LineString lineString in multiLineString.Coordinates)
            {
                List<MapPoint> mapPoints = new List<MapPoint>();
                List<NetTopologySuite.Geometries.Coordinate> coordinates = new List<NetTopologySuite.Geometries.Coordinate>();
                foreach (GeoJSON.Net.Geometry.IPosition coordinate in lineString.Coordinates)
                {
                    mapPoints.Add(new MapPoint(coordinate.Latitude, coordinate.Longitude * mirrorMultiplier));
                    coordinates.Add(new NetTopologySuite.Geometries.Coordinate(coordinate.Latitude, coordinate.Longitude * mirrorMultiplier));

                }

                NetTopologySuite.Geometries.LineString netSuiteLineString = new NetTopologySuite.Geometries.LineString(coordinates.ToArray());
                linestringsNet.Add(netSuiteLineString);

                VectorMarkerSymbolElement symLyrEl = new VectorMarkerSymbolElement(new Polyline(mapPoints), multilayerPolylineSymbol);
                vectorMarkerSymbolElements.Add(symLyrEl);
            }

            if (feature.Properties.ContainsKey("SimpleMarkerSymbol"))
            {
                string symbolInfo = feature.Properties["SimpleMarkerSymbol"].ToString();
                GeoJSON.Net.Geometry.Point[] symbolGeometries = JsonConvert.DeserializeObject<GeoJSON.Net.Geometry.Point[]>(symbolInfo);
                SimpleMarkerSymbol pointSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Circle, Color.Transparent, symbolGeometries[0].Coordinates.Latitude * 1.3)
                {
                    Color = Color.Transparent,
                    Outline = new SimpleLineSymbol(lineEffect is DashGeometricEffect ? SimpleLineSymbolStyle.Dash : SimpleLineSymbolStyle.Solid, symbolColor, 1)
                };

                pointSymbol.Style = SimpleMarkerSymbolStyle.Circle;
                MultilayerPointSymbol multilayerPointSymbol = pointSymbol.ToMultilayerSymbol();

                //multilayerPointSymbol.ReferenceProperties = new SymbolReferenceProperties(20000, 0);
                VectorMarkerSymbolElement vectorMarkerSymbolElement = new VectorMarkerSymbolElement(new MapPoint(symbolGeometries[1].Coordinates.Latitude,
                    symbolGeometries[1].Coordinates.Longitude * mirrorMultiplier), multilayerPointSymbol);
                vectorMarkerSymbolElements.Add(vectorMarkerSymbolElement);
            }

            outputmultiLineString = new NetTopologySuite.Geometries.MultiLineString(linestringsNet.ToArray());
            return vectorMarkerSymbolElements;

        }

        MultilayerPointSymbol testSymbol()
        {
            SolidStrokeSymbolLayer lineSymbol = new SolidStrokeSymbolLayer(1, Color.Black);

            List<SymbolLayer> symbolLayers = new List<SymbolLayer>
                {
                    lineSymbol
                };

            MultilayerPolylineSymbol multilayerPolylineSymbol = new MultilayerPolylineSymbol(symbolLayers);

            List<MapPoint> mapPoints = new List<MapPoint>();

            Coordinate[] coordinatesArray = new Coordinate[] { new Coordinate(0, 0), new Coordinate(5, 0), new Coordinate(5, 2), new Coordinate(5, -2) };

            SymbolReferenceProperties symbolReferenceProperties = new SymbolReferenceProperties(10000.0, 1.0);
            foreach (Coordinate coordinate in coordinatesArray)
            {
                mapPoints.Add(new MapPoint(coordinate.X, coordinate.Y));
            }
            multilayerPolylineSymbol.ReferenceProperties = symbolReferenceProperties;
            VectorMarkerSymbolElement symLyrEl = new VectorMarkerSymbolElement(new Polyline(mapPoints), multilayerPolylineSymbol);
            
            List<VectorMarkerSymbolElement> vectorMarkerSymbolElements = new List<VectorMarkerSymbolElement>();

            //add custom element to vectormarker symbol
            vectorMarkerSymbolElements.Add(symLyrEl);

            SimpleMarkerSymbol pointSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Circle, Color.Transparent, 5)
            {
                Color = Color.Transparent,
                Outline = new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, Color.Black, 1),
                
                
            };
            pointSymbol.Style = SimpleMarkerSymbolStyle.Circle;
            MultilayerPointSymbol multilayerPointSymbol = pointSymbol.ToMultilayerSymbol();
            multilayerPointSymbol.ReferenceProperties = symbolReferenceProperties;
            VectorMarkerSymbolElement vectorMarkerSymbolElement = new VectorMarkerSymbolElement(new MapPoint(0, 10), multilayerPointSymbol);
            vectorMarkerSymbolElement.Symbol.ReferenceProperties = symbolReferenceProperties;
            //add circle symbol to vectormarker symbol
            vectorMarkerSymbolElements.Add(vectorMarkerSymbolElement);

            VectorMarkerSymbolLayer symLyr = new VectorMarkerSymbolLayer(vectorMarkerSymbolElements);

            List<VectorMarkerSymbolLayer> vectorMarkerSymbolLayers = new List<VectorMarkerSymbolLayer>();

            vectorMarkerSymbolLayers.Add(symLyr);

            MultilayerPointSymbol sym = new MultilayerPointSymbol(vectorMarkerSymbolLayers)
            {
                AngleAlignment = SymbolAngleAlignment.Map,
                ReferenceProperties = symbolReferenceProperties
            };
            return sym;
        }

        internal Renderer CreateRenderer(GeometryType rendererType, Color color, SimpleLineSymbolStyle lineSymbolStyle = SimpleLineSymbolStyle.Solid)
        {
            // Return a simple renderer to match the geometry type provided
            Esri.ArcGISRuntime.Symbology.Symbol sym = null;

            switch (rendererType)
            {
                case GeometryType.Point:
                case GeometryType.Multipoint:
                    SolidStrokeSymbolLayer lineSymbol = new SolidStrokeSymbolLayer(2, Color.Red);
                    List<SymbolLayer> symbolLayers = new List<SymbolLayer>
                    {
                        lineSymbol
                    };

                    MultilayerPolylineSymbol multilayerPolylineSymbol = new MultilayerPolylineSymbol(symbolLayers);
                    List<VectorMarkerSymbolElement> vectorMarkerSymbolElements = new List<VectorMarkerSymbolElement>();

                    List<MapPoint> mapPoints = new List<MapPoint>
                    {
                        new MapPoint(0, 0),
                        new MapPoint(0, 5)
                    };

                    VectorMarkerSymbolElement symLyrEl = new VectorMarkerSymbolElement(new Polyline(mapPoints), multilayerPolylineSymbol);
                    vectorMarkerSymbolElements.Add(symLyrEl);

                    List<VectorMarkerSymbolLayer> vectorMarkerSymbolLayers = new List<VectorMarkerSymbolLayer>();
                    VectorMarkerSymbolLayer symLyr = new VectorMarkerSymbolLayer(vectorMarkerSymbolElements);
                    vectorMarkerSymbolLayers.Add(symLyr);

                    sym = new MultilayerPointSymbol(vectorMarkerSymbolLayers);


                    break;
                case GeometryType.Polyline:
                    // Create a line symbol
                    sym = new SimpleLineSymbol(lineSymbolStyle, color, 2);
                    break;
                case GeometryType.Polygon:
                    // Create a fill symbol
                    SimpleLineSymbol lineSym = new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, Color.DarkBlue, 2);
                    sym = new SimpleFillSymbol(SimpleFillSymbolStyle.DiagonalCross, Color.Cyan, lineSym);
                    break;
                default:
                    break;
            }

            // Return a new renderer that uses the symbol created above
            return new SimpleRenderer(sym);
        }

Hi Priyanka,

 

maybe this helps. I've attached the complete code. You can see how I'm using unique value renderers to specify which symbols to load for specific features.

Also the method "testSymbol" is included, that is the symbol we've been talking about as an example. You can see I set the reference properties at all points. Also when I don't set any referenceproperties, it does not work.

 

when the featurecollection is completed, and the featurecollectionlayer is loaded, the following code is executed.

        private async void FeatureCollectionLayer_Loaded(object sender, EventArgs e)
        {
            GeographicMapViewModel geographicViewModel = GeographicMapView.DataContext as GeographicMapViewModel;
            MapservicesViewModel mapservicesViewModel = geographicViewModel.MapservicesControl.DataContext as MapservicesViewModel;

            GeographicMapView.BackgroundGrid.IsVisible = false;
            geographicViewModel.FeatureCollectionLayer.Layers[0].ScaleSymbols = false;


            for (int i = 1; i < geographicViewModel.FeatureCollectionLayer.Layers.Count; i++)
            {
                geographicViewModel.FeatureCollectionLayer.Layers[i].ScaleSymbols = true;
            }
            GeographicMapView.Map.ReferenceScale = 445;

            await GeographicMapView.Map.LoadAsync();
            GeographicMapView.Map.OperationalLayers.AddRange(mapservicesViewModel.ListMapservicesList);
            GeographicMapView.Map.OperationalLayers.Add(geographicViewModel.FeatureCollectionLayer);
            MeasureToolbar.SelectedLinearUnit = MeasureToolbar.LinearUnits[4];
            _ = await GeographicMapView.SetViewpointCenterAsync(geographicViewModel.FeatureCollectionLayer.FullExtent.GetCenter(), scale: 10000);
            _ = await GeographicMapView.SetViewpointScaleAsync(445);
            LoadWindow.Loading = false;
            LoadWindow.Visibility = Visibility.Collapsed;

        }
0 Kudos
PreetiMaske
Esri Contributor

PreetiMaske_0-1664994670119.png

Priyanka tried in Android and it works. Then in tried in .Net I see above symbol created with exact code you provided, just changed the coordinate collection to an array of MapPoint and added a graphic to graphics overlay that uses this symbol and it all works fine.

 

 SolidStrokeSymbolLayer lineSymbol = new SolidStrokeSymbolLayer(1, Color.Black);

            List<SymbolLayer> symbolLayers = new List<SymbolLayer>
                {
                    lineSymbol
                };

            MultilayerPolylineSymbol multilayerPolylineSymbol = new MultilayerPolylineSymbol(symbolLayers);

            List<MapPoint> mapPoints = new List<MapPoint>();

            MapPoint[] coordinatesArray = new MapPoint[] { new MapPoint(0, 0), new MapPoint(5, 0), new MapPoint(5, 2), new MapPoint(5, -2) };

            foreach (MapPoint coordinate in coordinatesArray)
            {
                mapPoints.Add(coordinate);
            }

            VectorMarkerSymbolElement symLyrEl = new VectorMarkerSymbolElement(new Polyline(mapPoints), multilayerPolylineSymbol);

            List<VectorMarkerSymbolElement> vectorMarkerSymbolElements = new List<VectorMarkerSymbolElement>();

            //add custom element to vectormarker symbol
            vectorMarkerSymbolElements.Add(symLyrEl);

            SimpleMarkerSymbol pointSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Circle, Color.Transparent, 5)
            {
                Color = Color.Transparent,
                Outline = new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, Color.Black, 1)
            };

            pointSymbol.Style = SimpleMarkerSymbolStyle.Circle;
            MultilayerPointSymbol multilayerPointSymbol = pointSymbol.ToMultilayerSymbol();

            VectorMarkerSymbolElement vectorMarkerSymbolElement = new VectorMarkerSymbolElement(new MapPoint(0, 10), multilayerPointSymbol);

            //add circle symbol to vectormarker symbol
            vectorMarkerSymbolElements.Add(vectorMarkerSymbolElement);

            VectorMarkerSymbolLayer symLyr = new VectorMarkerSymbolLayer(vectorMarkerSymbolElements);

            List<VectorMarkerSymbolLayer> vectorMarkerSymbolLayers = new List<VectorMarkerSymbolLayer>();

            vectorMarkerSymbolLayers.Add(symLyr);

            MultilayerPointSymbol sym = new MultilayerPointSymbol(vectorMarkerSymbolLayers)
            {
                AngleAlignment = SymbolAngleAlignment.Map,
            };

            var map = new Map(BasemapStyle.ArcGISLightGray);
            mapview.Map = map;
            var GO = new GraphicsOverlay();
            mapview.GraphicsOverlays.Add(GO);           
            var g = new Graphic(new MapPoint(10, 10, SpatialReferences.Wgs84), sym);
            GO.Graphics.Add(g);

 

 

0 Kudos