Creating Point at end of line

1167
24
09-11-2020 09:06 AM
BrianBulla
Regular Contributor

Hi,

I've created a MapTool that creates a line and places point features at the to/from point of the line.  I use code like this to accomplish this....

I use this to get the sketch geometry to create the from point (connectionPoint) and to point (plugPoint):


var pointCollection = ((Multipart)geometry).Points;
MapPoint connectionPoint = pointCollection[0];
MapPoint plugPoint = pointCollection[pointCollection.Count - 1];

I then create the plugPoint like this:


var plugAttributes = new Dictionary<string, object>
{
{"SUBTYPECD", 4 },
{"DIAMETER1", 200 },
{"Shape", plugPoint.Clone() }
};

editOp.Create(waterFittingsLayer, plugAttributes);

Does using plugPoint.Clone create an EXACT clone??  Is there a more preferred way of doing this??

I'm finding that most of the time it does create the point correctly, but then other times the point created is not exactly the same.  I cannot figure out why this is happening.  Here are some screenshots of the values I am seeing.  The first value is the TO point of the line and the second value is the 'cloned' point.

0 Kudos
24 Replies
Wolf
by Esri Regular Contributor
Esri Regular Contributor

Clone does not change the point geometry, however, when the point is stored in a feature class the xy resolution could come into play.  

0 Kudos
BrianBulla
Regular Contributor

Thanks Wolfgang,

So would you say that using the geometry of the sketch is not the best way to create a point at the to/from points??

Looking back at my old ArcObjects code, I would capture the Mouse Click points and use those coordinates to create the features at the ends of the line.  That never seemed to cause any problems, just more coding for me.  I figured doing it this way would be more efficient coding wise (which it is), but if it causes other problems than that is not so good.

0 Kudos
Wolf
by Esri Regular Contributor
Esri Regular Contributor

Hi Brian,

 I don't think it's possible to get different coordinates for points stored as part of a line feature or a point feature as long as both feature class have the same spatial reference and domain settings, regardless weather you clone the point or not.  Can you send me a map package (you can attach the map package using the advanced editor option) that contains your map with your relevant layers (needless to say i don't need any data)?  With the map package i get all  relevant map and feature class spatial references and domains.  I will try to duplicate the issue you are seeing.  I made a test add-in and can't duplicate the issue.  The two coordinates you display on your image, where exactly are those values coming from?  Can you give me a code snippet?

0 Kudos
BrianBulla
Regular Contributor

Hi Wolfgang,

I've attached the package.

Those values are coming from a tool that looks at a selected feature water fitting feature and determines what subtype, diameter, etc. it needs to be based on the intersecting feature.  In the screen shot below, both of these water service lines were created using my MapTool.  The one on the left worked properly, snapping the 'plug' to the endpoint.  But in the one on the right, the 'plug' gets converted to a 'service point' because the code determines that it is not snapped to the to point.

The two coordinates above come from the code that is looking to make sure the to-point and feature point are the same.  I just created a message box to try and figure out what was going wrong.

MessageBox.Show(toPoint.X.ToString() + " - " + toPoint.Y.ToString() + "\n" + fittingPoint.X.ToString() + " - " + fittingPoint.Y.ToString());

0 Kudos
Wolf
by Esri Regular Contributor
Esri Regular Contributor

Sorry about the delay, Brian, but I just now got around to revisit your issue.   Let me first summarize what i think the workflow and the resulting problems are:

  • A MapTool is used to sketch a line. 
  • The sketched line geometry is used to create two points: a 'Connection' point which is the 'from' point of the line (first point) and a 'Plug' point, which is the 'to' point of the line (last point).  The points are computed as shown here:
  • MapPoint connectionPoint = ((Multipart)geometry).Points[0];
  • MapPoint plugPoint = ((Multipart)geometry).Points[((Multipart)geometry).PointCount - 1];
  • A new fitting feature is created using the plugPoint (let's call this one fitting) using the plugPoint's geometry by calling: plugPoint.Clone().  The fitting's attributes are also driven by the 'Connection' point, which should be connected to a water man.

The first problem is that the coordinates of plugPoint are changed as a result of calling 'Clone' and hence your fitting's point location is not coincident with plugPoint.  Is that still the case as stated in your original question above?

The second problem is that the fitting turns into a service point type because the Connection point is not connected to the water main?

I also wanted to know what projection your data is using.  Is it the same projection as is used by your sample map?  NAD_1983_UTM_Zone_17N?

I wrote a test program to duplicate the Clone problem and i was not able to duplicate the problem.   For the second issue i would first look at the snapping configuration in your MapTool.  Make sure the tool is configured to snap to the correct layer(s) ... i think we have discussed this in another thread: https://community.esri.com/thread/258729-help-with-finding-intersecting-layer 

0 Kudos
BrianBulla
Regular Contributor

Hi Wolfgang.  Thanks for taking the time to help me with this.  Here is some additional info to help clarify what I am doing:

1.  Yes, a map tool is used to sketch a line.  I my code I enable snapping, so I don't think that is an issue.  Also, when I create the sketch I am careful to make sure I am snapping to the proper geometry.  For this tool, it is really only the 'from' point that is snapped to an existing feature (the edge of a watermain).

2.  Yes, the sketched geometry is used to create a 'service connection' (from point...snapped to a watermain) and the 'plug' (to point).  The sketched line is also used to create the 'water service' (full sketch) and a 'valve' (2nd vertice on the line).  So the end result should look like this:

3.  Here is the code I use to create each feature, basically using .Clone on the [0], [Count -1], and [1] of the pointCollection.....and then using the whole sketch geometry for the water service line.

        protected override Task<bool> OnSketchCompleteAsync(Geometry geometry)
        {
            //use the sketch geometry to create the connectionPoint and plugPoint
            var pointCollection = ((Multipart)geometry).Points;
            MapPoint connectionPoint = pointCollection[0];
            MapPoint plugPoint = pointCollection[pointCollection.Count - 1];
            MapPoint valvePoint = pointCollection[1];

            //start creating the features
            QueuedTask.Run(() =>
            {
                if (Global.IntersectsLayer(connectionPoint, waterMainLayer) == false)
                {
                    ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show(connectionPoint.X.ToString() + ", " + connectionPoint.Y.ToString(), "Error");
                    ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show("The starting point must intersect the WaterMain or Water Service layer.", "Error");
                    return;
                }
                
                //start a new edit operation and name it for the 'Undo' stack
                var editOp = new EditOperation();
                editOp.Name = "Create new ICI Connection";

                //set the attributes for the connectionPoint and create the point in the Fittings layer
                var connectionAttributes = new Dictionary<string, object>
                {
                    {"SUBTYPECD", 6 },
                    {"DIAMETER1", 200 },
                    {"Shape", connectionPoint.Clone() }
                };

                editOp.Create(waterFittingsLayer, connectionAttributes);

                //set the attributes for the valve and create the point in the Control Valve layer
                var valveAttributes = new Dictionary<string, object>
                {
                    {"SUBTYPECD", 2 },
                    {"Shape", valvePoint.Clone() },
                    {"DIAMETER", 200 }
                };

                editOp.Create(controlValveLayer, valveAttributes);

                //set the attributes for the plug and create the point in the Fittings layer
                var plugAttributes = new Dictionary<string, object>
                {
                    {"SUBTYPECD", 4 },
                    {"DIAMETER1", 200 },
                    {"Shape", plugPoint.Clone() }
                };

                editOp.Create(waterFittingsLayer, plugAttributes);

                //set the attributes for the connection line and create the line in the Connections layer
                var lineAttributes = new Dictionary<string, object>
                {
                    {"SUBTYPECD", 1 },
                    {"Shape", geometry.Clone() },
                    {"DIAMETER", 200 },
                    {"LENGTH", GeometryEngine.Instance.Length(geometry).ToString()}
                };

                editOp.Create(waterServiceLayer, lineAttributes);

                //show an error message if not successful
                var result = editOp.Execute();
                if (result != true || editOp.IsSucceeded != true)
                    throw new Exception($@"Edit failed: {editOp.ErrorMessage}");
                
            });

            return base.OnSketchCompleteAsync(geometry);
        }

4.  Yes, it seems like .Clone is always creating an exact clone.  Once I am finished creating the features there is actually another tool I run that looks at the geoemety between the water service and the fitting (in this case, the plug).  If the fitting point (ie. X/Y) does not match exactly the water service from point (ie X/Y), then the tool considers them to not be intersecting and converts the plug into a service connection.

Here is an example.  Initially both lines below had a 'plug' after being created by the sketching tool.  But then after running my 'Fittings Tool', the top one gets converted to a service connection because it does not meet the criteria of a plug (ie. intersecting the from point of a water service).  The bottom one was intersecting, so no problems.

5.  Yes, NAD 83, 17N

6.  Yes, I am 100% sure the snapping is working as expected.  If I do not snap that first point to a watermain, I get an error....as expected.  This tool will only create the features if the first point has an intersecting watermain.  It's more the snapping of the points created by .Clone that seems to be a problem.

Thanks again.  Let me know if you need anything else from me.  I am basically converting an old ArcObjects tool to ArcPro.  We've been using it for years and I've never seen any issues like this.  The inconsistencies are what is most confusing to me.  As in the example above, sometimes it works and sometimes it doesn't....all with the same code.

0 Kudos
BrianBulla
Regular Contributor

And.....it seems like this is only happening with the plug (to point).  In my testing, the service connection (from point, also created with .Clone) is always intersecting the water service line.

0 Kudos
Wolf
by Esri Regular Contributor
Esri Regular Contributor

I created a test add-in (attached: GeoNet259853-Add-in.zip) and I was not able to duplicate the problem with my Pro project (also attached: GeoNet259853.mpkx).

I was not able to test with your data since the feature classes didn't come across with your map package (probably due to the fact that your data is enterprise data) so I made up my own data - it's a different projection and also a file geodatabase and not an enterprise geodatabase.

Maybe you can try to duplicate is issue by using GeoNet259853-Add-in.  The way the test works is:

  1. Use the 'Create Service Connection' tool to create a new service connection.  To do so snap the 'from' point of a water main, then add 1 or more vertices.
  2. Use the 'select by rectangle' tool to select the 'plug' end point of the newly create service connection line.
  3. Click the 'Selection Coincidence' button to see if the 'fitting' end point is coincident with the service line's 'to' point.  You should get a message showing if the coordinates are coincident and the actual x/y pairs.

If you can duplicate the issue with this add-in and your data we might have a problem that is related to the use of Enterprise geodatabases.  Also since the coordinates are limited by the domain's x/y resolution (see above), the coordinates might differ on the least significant digits, but the coincidence check using 'MapPoint.IsEqual' should account for that (as in toPoint.IsEqual(pntFitting) ).

Anyways let me know what you find and also what RDBMS are you using (SQL server/Oracle)

0 Kudos
BrianBulla
Regular Contributor

Hi Wolfgang Kaiser‌,

Using your sample code I am getting similar results to when I am using my own code.  It's a bit of a mixed bag.  Sometimes the plug is coincident, and other times not.  I used your "Select Coincidence" button to test and your tool to create the Service Connection.  It is not always coincident.

I also used my tool create the connection and used your button to verify, and the results were basically the same.  A mixed bag of some working, and others not.

We are using an SQL backend.  Do you think that has something to do with it??

0 Kudos