Select to view content in your preferred language

Using the Cut function of a geometry service gives unexpected results

3737
8
09-21-2011 01:30 PM
NicholasFloersch
Deactivated User
Hi all. I have implemented a simple interface to use the my local geometry service's cut functionality. I want to allow a user to take an existing polygon and split it into two. Seems simple given that there is an example in the Silverlight interactive SDK that does just this.

However, while my code appears to suceed at this task, the returned results from the cut process are only partly correct. If I take a polygon P and draw a line to split it into two non-overlapping portions A and B together which should comprise the entire original geometry of P, I instead get two geometries back from the cut task - A and P? In other words one of the two geometries returned is as I desired one part of the original polygon P, defined by the bisecting line I drew on the map. The other geometry returned should be B, a second polygon also defined by the bisecting line - the other half of P. But instead the second geometry is the entire original polygon P.

I guess I could now take my returned polygon A and use it with a reshape function to reshape the returned P-sized geometry to manually create the B polygon I was expecting, but none of the sample code I have seen suggests a need to do this.

At first I thought maybe the cut task returns all three geometries - A, B, and just for good measure, P. But I looked at the returned structure during debugging and it only contains the two geometries A and P.

This was very confusing at first because my code blindly adds both geometries back to my graphics layer, and the second geometry which was the size of the original P kept getting added on top of A - so I would not see A. I finally realized the issue when I started exploring the returned geometries in an ArcMap edit session...

Here is some code:
private void btnStartSplit_Click(object sender, RoutedEventArgs e) 
{
 // Empty container that gets filled with the polygon geometry I want
 //  cut by a polyline geometry.
 private IList<Graphic> toSplit = new List<Graphic>();
 
 // The source of the graphics used during cutting
 GraphicsLayer editsMapLayer = ((GraphicsLayer)MainPage.CPMap.Layers["GraphicsLayer_PLUSelection"]);
 
 // Look for the polyline I drew earlier, of which there will only be one
 //   because without the polyline, we cannot perform the cut...
 //
 // Start by getting a collection of all graphics in the graphics layer
 GraphicCollection tEdits = editsMapLayer.Graphics;
 // Then return only the geometries (of which there will be 0 or 1) where the type is
 //   ESRI....Polyline
 Graphic theLine = tEdits.Where(g => g.Geometry.GetType().FullName == "ESRI.ArcGIS.Client.Geometry.Polyline").FirstOrDefault();
 if (theLine == null) return; // And quit here if there was no line
 
 // Obtain the geometry of that line...
 ESRI.ArcGIS.Client.Geometry.Polyline theLineGeom = (ESRI.ArcGIS.Client.Geometry.Polyline)theLine.Geometry;
 // I know that there is a polygon in my graphics layer to cut, so I search for it and add
 //   it to my set of geometries to be cut.
 toSplit.Add(tEdits.Where(g => g.Geometry.GetType().FullName == "ESRI.ArcGIS.Client.Geometry.Polygon").FirstOrDefault());
 
 // Create a new geometry service
 ESRI.ArcGIS.Client.Tasks.GeometryService geoSvc = new ESRI.ArcGIS.Client.Tasks.GeometryService(MainPage.editorMainMap.GeometryServiceUrl);
 
 // Setup the event handler
 geoSvc.CutCompleted += new EventHandler<ESRI.ArcGIS.Client.Tasks.CutEventArgs>(geoSvc_CutCompleted);
 
 // Call the cut process asynchronously passing in the container of one polygon geometry to cut,
 //   and one polyline geometry with which to cut that polygon geometry.
 geoSvc.CutAsync(toSplit,theLineGeom);
}


void geoSvc_CutCompleted(object sender, ESRI.ArcGIS.Client.Tasks.CutEventArgs e)
{
 MessageBox.Show("Cut Event Returned At Least!");
 
        // I will be adding the returned geometries as new graphics to the SubAreas Featurelayer of my map.
 FeatureLayer subareaMapLayer = ((FeatureLayer)MainPage.CPMap.Layers["SubAreas"]);

        // Featurelayer save-event-handlers
 subareaMapLayer.SaveEditsFailed += new EventHandler<ESRI.ArcGIS.Client.Tasks.TaskFailedEventArgs>(subareaMapLayer_SaveEditsFailed);
 subareaMapLayer.EndSaveEdits += new EventHandler<ESRI.ArcGIS.Client.Tasks.EndEditEventArgs>(subareaMapLayer_EndSaveEdits);
 subareaMapLayer.BeginSaveEdits += new EventHandler<ESRI.ArcGIS.Client.Tasks.BeginEditEventArgs>(subareaMapLayer_BeginSaveEdits);
 
        // This is where I find I will loop two times, once for each returned geometry...
        //   one geometry (A from my description above) is correct, and one (P) is not. There
        //   does not appear to be a third geometry (B)... 
 foreach (Graphic g in e.Results)
 {
                // Give the geometry/graphic a default symbol
  g.Symbol = MainPage.MainGrid.Resources["DefaultFillSymbol"] as ESRI.ArcGIS.Client.Symbols.Symbol;
                // Set some attributes on the geometry/graphic...
  g.Attributes["SubareaID"] = "{" + Guid.NewGuid().ToString() + "}";
  g.Attributes["PlanningLandUnitID"] = OriginPlanningLandUnitId;
  g.Attributes["LandUseID"] = Convert.ToInt32(OriginPlanningLandUnitUseId);
  g.Attributes["parent_subareaid"] = SplitPractice.Description.ToString();
                // Add the new graphic to the Featurelayer
  subareaMapLayer.Graphics.Add(g);
                // Save the edit
  subareaMapLayer.SaveEdits();
 } // Process next geometry/graphic in return set
 subareaMapLayer.Update();
}


Aside from the interactive SDK, is there anywhere else I can look for examples on what I am supposed to do to use the cut command of my geometry service? What geometries exactly I should expect back from the cut command?

Thanks for any input!
Nick Floersch
0 Kudos
8 Replies
JenniferNery
Esri Regular Contributor
Can you try the following SDK Sample with your GeometryService: http://help.arcgis.com/en/webapi/silverlight/samples/start.htm#EditToolsExplicitSave

You can use Editor.Cut. Cut Selected button becomes enabled once the you make your selection or set AutoSelect=True on the layer or Editor. Update the highlighted properties. Kindly see if you still get the same "unexpected results".
            <esri:Editor x:Key="MyEditor" 
                         Map="{Binding ElementName=MyMap}" 
                         LayerIDs="ThreatAreas"   
                       GeometryServiceUrl="http://tasks.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer"
                             />
0 Kudos
NicholasFloersch
Deactivated User
Hi Jennifer,

I started thinking about what you were proposing but have taken a slight tangent. The reason is that even if using the editor's built-in command to cut worked, the work flow it requires is not quite what I want ... it is too much of a package deal, and I need a more customized work flow. I mean, I'll go that route if I must, but it lead me to another question that may be related.

In the API documentation it says that the CutEventArgs class contains three things: CutIndexes, Results, and UserState. I do not believe that the contents of UserState are relevant to my task. However, I am currently simply looping through the two graphics I found in Results and adding them to my output Featurelayer. This leaves me wondering, what is this 'CutIndexes' array, and what is its purpose? Am I suppose to use it in some way? The documentation is completely unhelpful regarding the CutIndexes array saying only that it holds the indexes of the new geometries derived from the original. I mean, that sort of sounds like what I want... but then when it says "The indexes of the new geometries..." it never says 'indexes into ... what??' What array or structure are the indexes referencing? The list of graphics in the Results IList? If so, what's the point? What do the values of the CutIndexes values mean - I have two Indexes listed [0] and [1], and each index stores only the value '0' which doesn't tell me a whole lot.

This lead to yet another related question: the Geometry Service has a property named 'CutLastResult' ... which is described vaguely as 'Gets the cut last result' ..? Does that mean the 'Results' IList from the last completed CutAsync event? Or is this a different IList containing only the last graphic object of the last set of results? Is there a difference in meaning between Result and Results here? And if the last single result graphic is returned, but multiple geometries are defined by a cut, which is the last one?

Thanks for any pointers!
Nick
0 Kudos
NicholasFloersch
Deactivated User
Quick follow up... I downloaded the SDK examples and tried to build them after having modified the geometry service URL in the Explicit Save sample, but get an error at runtime about some Init parameter XML file missing from inside the App.xaml.cs ...
0 Kudos
JenniferNery
Esri Regular Contributor
Please make the website your startup project (kindly see attached image).
0 Kudos
NicholasFloersch
Deactivated User
Hi again!

So, the answer to your initial query is "yes" - using the SDK explicit save sample to draw and then cut a polygon works fine. Unfortunately, I need my cutting workflow to be controlled via the codebehind, and not by the pre-packaged cut tool from the Editor widget..? The user needs to draw the cutting line and have it displayed on the map without having the cut happen yet - then after the user has checked some things, the user hits a button to finalize the cut, and that is when I am trying to get the cut to happen but getting the odd results.

So I modified the Utilities->Cut SDK sample to my geometry service as well, and that also works. What I notice is that when the cut is submitted it submits all polygons on the map as possible cut targets, and then the returned results list of graphics contains all of those same polygons plus some extras if the cut cut anything. Yet the CutIndexes member of the CutEventArgs 'e' object passed to the CutCompleted event handler does not clearly define anything ... it has one index entry for each of the returned graphics, but each index entry's value is simply the number of index ... index [10] has a value of 10. How would one determine from the returned set of polygon graphics which polygon is the newly created cut, and which one it came from?

Thanks for continuing to pay attention to this thread!
Nick
0 Kudos
JenniferNery
Esri Regular Contributor
I've attached a small sample that grabs little bits and pieces from our sample SDK.

This sample has a GraphicsLayer with polygon geometries, a Draw with DrawMode=Polyline. I've included attributes to the graphic and a MapTip on the layer so you can see how you can transfer them to the cut results. To run this app, MouseLeftButtonDown will select the graphic. You can then click on "Cut" button to activate Draw. In the DrawCompleted event, you can call GeometryService.CutAsync and use UserState to pass the original graphic. In the CutCompleted event, you can update the original graphic.Geometry and use update the other parts with the same attributes.
0 Kudos
JenniferNery
Esri Regular Contributor
The CutIndexes is useful when you pass multiple graphics as target for cut. This basically helps tell which piece belongs to which graphic. Try the sample I sent, select both polygons and cut through them. CutCompleted will show e.CutIndexes to be [0,0,1,1].

For simplicity, the sample assumes only one graphic will be target so foreach loop is used. But you can switch to for-loop and grab pair the original graphic with cut result using CutIndex.
for (int i = 0; i < e.Results.Count; i++)
{
 int cutIndex = e.CutIndexes;
 var r = e.Results[cutIndex];
//more code goes here.
}
0 Kudos
SujaSudhan
Deactivated User
Hi,

I am not getting any user inputs for cutter polyline. I am converting an extent envelope to a polyline object and using that as a cutter polyline. This is done to cut a polyline graphic only to my required extent. However, the cut completed results has got only 1 result which means there was no cut perfomed.

Can CutAsync method be used only when user digitizes a polyline as the cutter? I wouldn't assume so, but why is this behaviour?

Thanks!
0 Kudos