Create points with Mouse click

2285
15
Jump to solution
02-05-2013 09:06 AM
TonyAlmeida
Occasional Contributor II
I have a VBA button that allows me to click on my layer and generate a point by a MouseDown event. It populates a certain filed with the distance between the first temp point and the second temp point divided by 5.28 + InputBox. The point is also created from the second temp point. Since VBA will no longer be supported i thought i would look into python. I know you can capture coordinates with the onMouseDownMap function. maybe use point = arcpy.Point and ptGeometry = arcpy.PointGeometry(point) to get the distance between the two points,then cursor = arcpy.UpdateCursor to update the field, then feature store?

any ideas, thoughts? i would gratefully appreciate it.

Here is my vba code
Dim pFeature1 As IFeature Dim tmpPoint1 As IPoint  Private Sub UIToolControl1_MouseDown(ByVal button As Long, ByVal shift As Long, ByVal x As Long, ByVal y As Long)  'Adds a point to a shapefile     Dim pMap As IMap     Dim pMxDoc As IMxDocument     Set pMxDoc = ThisDocument     Set pMap = pMxDoc.FocusMap     Dim pDataset As IDataset     Dim pFeature1 As IFeature     'Dim tmpPoint1 As IPoint      'Get the first layer in the map     Dim pFeatLyr As IGeoFeatureLayer     Set pFeatLyr = pMap.Layer(0)             'Create a point from the mouse down click     Dim tmpPoint As IPoint     Set tmpPoint = New Point     Set tmpPoint = pMxDoc.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(x, y)      'Get the feature class     Dim pFClass As IFeatureClass     Set pFClass = pFeatLyr.FeatureClass  'QI from IFeatureclass to IDataset  'Dim pDataset As IDataset Set pDataset = pFClass  'Get the Workspace from the IDataset Dim pWorkspace As IWorkspace Set pWorkspace = pDataset.Workspace  'QI from IWorkspace to IWorkspaceEdit Dim pWorkspaceEdit As IWorkspaceEdit Set pWorkspaceEdit = pWorkspace  'Start editing if needed If Not pWorkspaceEdit.IsBeingEdited Then pWorkspaceEdit.StartEditing (True) End If  'Start an edit operation pWorkspaceEdit.StartEditOperation      'Create the new point feature     Dim pFeature As IFeature     Dim dblDist As Double     If button = 2 Then         Set pFeature1 = Nothing         Set tmpPoint1 = Nothing         Exit Sub     End If     If pFeature1 Is Nothing Then         If tmpPoint1 Is Nothing Then             Set tmpPoint1 = tmpPoint         Else             Set pFeature = pFClass.CreateFeature             Set pFeature.Shape = tmpPoint             If Not tmpPoint1 Is Nothing Then                 dblDist = 0                 dblDist = GetDistance1(pFeature)                 pFeature.Value(pFeature.Class.Fields.FindField("Distance_")) = dblDist                 pFeature.Value(pFeature.Class.Fields.FindField("SiteNum")) = (dblDist / 5.28) + InputBox("Enter Address Range") & ""                 pFeature.Store             End If             Set pFeature1 = pFeature         End If     Else         Set pFeature = pFClass.CreateFeature         Set pFeature.Shape = tmpPoint         If Not pFeature1 Is Nothing Then             dblDist = 0             dblDist = GetDistance(pFeature1, pFeature)             pFeature.Value(pFeature.Class.Fields.FindField("Distance_")) = dblDist             pFeature.Value(pFeature.Class.Fields.FindField("SiteNum")) = (dblDist / 5.28) + InputBox("Enter Address Range") & ""              pFeature.Store                      End If         Set pFeature1 = pFeature     End If 'Complete the edit operation     'pWorkspaceEdit.StopEditOperation     pMxDoc.ActiveView.Refresh     pMxDoc.UpdateContents End Sub Function GetDistance1(pFeature1 As IFeature) As Double     Dim pGeom1 As IGeometry     Dim pGeom2 As IGeometry     Dim pProx As IProximityOperator     Dim dblDist As Double     Set pGeom1 = tmpPoint1     Set pGeom2 = pFeature1.Shape     Set pProx = pGeom2     dblDist = pProx.ReturnDistance(pGeom1)     'MsgBox dblDist     GetDistance1 = dblDist End Function Function GetDistance(pFeature1 As IFeature, pFeature2 As IFeature) As Double     Dim pGeom1 As IGeometry     Dim pGeom2 As IGeometry     Dim pProx As IProximityOperator     Dim dblDist As Double     Set pGeom1 = pFeature1.Shape     Set pGeom2 = pFeature2.Shape     Set pProx = pGeom2     dblDist = pProx.ReturnDistance(pGeom1)     'MsgBox dblDist     GetDistance = dblDist  End Function 
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
JakeSkinner
Esri Esteemed Contributor
Hi Tony,

Here is an example on how to do this:

import arcpy from arcpy import env env.workspace = r"C:\temp\python\test.gdb" env.overwriteOutput = 1  input = arcpy.GetParameterAsText(0)  # Create empty Point and Array objects point = arcpy.Point() array = arcpy.Array()  # A list that will hold each the Polyline object featureList = []  rows = arcpy.SearchCursor(input) for row in rows:     geom = row.Shape     point.X = geom.centroid.X     point.Y = geom.centroid.Y     # Add each point to the array     array.add(point)      # Create the polyline polyline = arcpy.Polyline(array) # Clear the array for future use array.removeAll() featureList.append(polyline)  del row, rows  # Copy the polyline to file geodatabase to create a Shape_Length field arcpy.CopyFeatures_management(featureList, "line_test") rows = arcpy.SearchCursor("line_test") for row in rows:     # Create a variable to store the length     length = row.Shape_Length     arcpy.AddMessage(length) del row, rows  # Convert the line's end point to a point arcpy.FeatureVerticesToPoints_management("line_test", "point_test", "END") # Add a field to store the length from the point1 to point2 arcpy.AddField_management("point_test", "Length", "DOUBLE")  rows = arcpy.UpdateCursor("point_test") for row in rows:     row.Length = length     rows.updateRow(row)  del row, rows  arcpy.Delete_management("line_test")


Once the script is created, you can add it to a toolbox.  After it's added, right-click on the script > Properties > Parameters tab.  Create a parameter and set it to Feature Set for the Data Type.  Within the Parameter Properties, import a feature class or shapefile for the schema.  You can then double click on the script, enter two points on the map and then run the tool.

View solution in original post

0 Kudos
15 Replies
TonyAlmeida
Occasional Contributor II
wow no response...I can't find much discussion on generating points.

Can anyone show me how to generate two clicks and create a point on the second click add the distance of those two points to a filed? In a Tool format please??

I would gratefully appreciate any help.
0 Kudos
JakeSkinner
Esri Esteemed Contributor
Hi Tony,

Here is an example on how to do this:

import arcpy from arcpy import env env.workspace = r"C:\temp\python\test.gdb" env.overwriteOutput = 1  input = arcpy.GetParameterAsText(0)  # Create empty Point and Array objects point = arcpy.Point() array = arcpy.Array()  # A list that will hold each the Polyline object featureList = []  rows = arcpy.SearchCursor(input) for row in rows:     geom = row.Shape     point.X = geom.centroid.X     point.Y = geom.centroid.Y     # Add each point to the array     array.add(point)      # Create the polyline polyline = arcpy.Polyline(array) # Clear the array for future use array.removeAll() featureList.append(polyline)  del row, rows  # Copy the polyline to file geodatabase to create a Shape_Length field arcpy.CopyFeatures_management(featureList, "line_test") rows = arcpy.SearchCursor("line_test") for row in rows:     # Create a variable to store the length     length = row.Shape_Length     arcpy.AddMessage(length) del row, rows  # Convert the line's end point to a point arcpy.FeatureVerticesToPoints_management("line_test", "point_test", "END") # Add a field to store the length from the point1 to point2 arcpy.AddField_management("point_test", "Length", "DOUBLE")  rows = arcpy.UpdateCursor("point_test") for row in rows:     row.Length = length     rows.updateRow(row)  del row, rows  arcpy.Delete_management("line_test")


Once the script is created, you can add it to a toolbox.  After it's added, right-click on the script > Properties > Parameters tab.  Create a parameter and set it to Feature Set for the Data Type.  Within the Parameter Properties, import a feature class or shapefile for the schema.  You can then double click on the script, enter two points on the map and then run the tool.
0 Kudos
TonyAlmeida
Occasional Contributor II
JSkinn3 i am grateful for your replay and help.

I followed you instructions to the T, but nothing seems to happen. No point_test filed was created.
Your code has giving me great in site!

I was thinking that this would be done with the onMouseDownMap function. I also would have thought this would have been through a class def_init_(self). I would like to make this an add-in. My other thought was starting an edit session and an edit operation, creating a row in a table, then stopping the edit operation and committing the edit session. Your thoughts?

again thank you so much for your code and your time!!
0 Kudos
JakeSkinner
Esri Esteemed Contributor
You can take the code and easily add it to an add-in.  Ex:

import arcpy
import pythonaddins

class ToolClass2(object):
    """Implementation for Tool_addin.tool (Tool)"""
    def __init__(self):
        self.enabled = True
        self.cursor = 3
        self.shape = "Line"
    def onLine(self, line_geometry):
        arcpy.env.workspace = r"C:\temp\python\test.gdb"
        arcpy.CopyFeatures_management(line_geometry, "line_test")
        rows = arcpy.SearchCursor("line_test")
        for row in rows:
            length = row.Shape_Length
            print length
        del row, rows

        arcpy.FeatureVerticesToPoints_management("line_test", "point_test", "END")
        arcpy.AddField_management("point_test", "Length", "DOUBLE")

        rows = arcpy.UpdateCursor("point_test")
        for row in rows:
            row.Length = length
            rows.updateRow(row)
        del row, rows

        arcpy.Delete_management("line_test")


In order to implement an edit session, take a look at adding the arcpy.da.Editor class.
0 Kudos
TonyAlmeida
Occasional Contributor II
intresting....

on the tool class you went to lin_geometry. Why no arcpy.point (x,y)?

Here is the code i have been working with. I would like the length of the two points to be store in the Point_test.shp Distance_ field and create a point on the second point.

I get this error...
Traceback (most recent call last):
  File "C:\Users\talmeida\AppData\Local\ESRI\Desktop10.1\AssemblyCache\{5339F9FA-E8D6-15EE-CD2E-3C72F2909D42}\Point_addin.py", line 17, in onMouseDownMap
    edit = arcpy.da.Editor(env.workspace)
RuntimeError: cannot open workspace

import arcpy
from arcpy import env
import pythonaddins
import os

class PointTool(object):
    """Implementation for Point_addin.PointTool (Tool)"""
    def __init__(self):
        self.enabled = True
        self.cursor=3
        self.shape = "Line"
    def onLine(self, line_geometry):
        env.workspace = r"C:\temp\Point_test.shp"
        env.overwriteOutput = 1

        # Start an edit session. Must provide the worksapce.
        edit = arcpy.da.Editor(env.workspace)

        # Edit session is started without an undo/redo stack for versioned data
        #  (for second argument, use False for unversioned data)
        edit.startEditing(False, True)

        # Start an edit operation
        edit.startOperation()
        
        # Create empty Point and Array objects
        point = arcpy.Point()
        array = arcpy.Array()

        # A list that will hold each the Polyline object
        featureList = []

        rows = arcpy.SearchCursor("Line_test")
        for row in rows:
            geom = row.Shape
            point.X = geom.centroid.X
            point.Y = geom.centroid.Y
            # Add each point to the array
            array.add(point)    

        # Create the polyline
        polyline = arcpy.Polyline(array)
        # Clear the array for future use
        array.removeAll()
        featureList.append(polyline)

        del row, rows

        # Copy the polyline to file geodatabase to create a Shape_Length field
        arcpy.CopyFeatures_management(featureList, "line_test")
        rows = arcpy.SearchCursor("line_test")
        for row in rows:
            # Create a variable to store the length
            length = row.Shape_Length
            arcpy.AddMessage(length)
        del row, rows

        # Convert the line's end point to a point
        # Insert a row into the table.
        with arcpy.da.InsertCursor(env.workspace, ('SHAPE@', 'Distance_')) as icur:
            icur.insertRow([(x,y), 'line_test'])

        del row, rows

        arcpy.Delete_management("line_test")

        # Stop the edit operation.
        edit.stopOperation()

        # Stop the edit session and save the changes
        edit.stopEditing(True)

        arcpy.RefreshActiveView()


0 Kudos
JakeSkinner
Esri Esteemed Contributor
Tony,

The point geometry would be a little more difficult.  You would need to some how code it so that your second click would only create the point, and not the first.

The reason you're getting this error is because you're setting the workspace to a shapefile.  The workspace will need to be a folder or geodatabase.  You will then need to update your arcpy.da.InsertCursor to just the shapefile name rather than 'env.workspace'.
0 Kudos
TonyAlmeida
Occasional Contributor II
That's my problem i am not very familiar with python :(.
0 Kudos
TonyAlmeida
Occasional Contributor II
I believe i am getting closer. Would it be possiable to place the distance between the two points "in_memory", so you wouldn't have to create a feature class?

Here is my code so far. Any help would be great!

I am receiving an error...

Traceback (most recent call last):
  File "C:\Users\ta\AppData\Local\ESRI\Desktop10.1\AssemblyCache\{5339F9FA-E8D6-15EE-CD2E-3C72F2909D42}\Point_addin.py", line 46, in onLine
    cursor.insertRow(row.length,)
UnboundLocalError: local variable 'row' referenced before assignment

import arcpy
from arcpy import env
import pythonaddins
import os

class PointTool(object):
    """Implementation for Point_addin.PointTool (Tool)"""
    def __init__(self):
        self.enabled = True
        self.cursor=3
        self.shape = "Line"
    def onLine(self, line_geometry):
        fc = "C:\Temp\Test_points.shp"
        workspace = os.path.dirname(fc)
        arcpy.env.overwriteOutput = True
                
        # Start an edit session. Must provide the worksapce.
        edit = arcpy.da.Editor(workspace)

        # Edit session is started without an undo/redo stack for versioned data
        #  (for second argument, use False for unversioned data)
        edit.startEditing(False, True)

        # Start an edit operation
        edit.startOperation()

        arcpy.CopyFeatures_management(line_geometry, "line_test")
        rows = arcpy.SearchCursor("line_test")
        for row in rows:
            length = row.Shape_Length
            print length
        del row, rows

        arcpy.FeatureVerticesToPoints_management("line_test", "in_memory", "END")
        arcpy.AddField_management("in_memory", "Length", "DOUBLE")

        rows = arcpy.UpdateCursor("in_memory")
        for row in rows:
            row.Length = length
            rows.updateRow(row)
        del row, rows

        rowss = arcpy.SearchCursor(fc, "", "", "Distance_")
        
        cursor = arcpy.da.InsertCursor(fc, ('SHAPE@', 'Distance_'))
        cursor.insertRow(row.length,)

        arcpy.Delete_management("in_memory")

        # Stop the edit operation.
        edit.stopOperation()

        # Stop the edit session and save the changes
        edit.stopEditing(True)

        arcpy.RefreshActiveView()

0 Kudos
JakeSkinner
Esri Esteemed Contributor
I would recommend creating a feature class.  The great thing about feature classes is that a Shape_Length field is automatically added to the feature class.  Therefore, you don't have to add additional code to add a field to the IN_MEMORY layer and then calculate the length. 

Here is an example where it starts an edit session, inserts the line's endpoint into a shapefile called 'Point_Test', and updates a field within the shapefile called 'Distance'.

import arcpy
import pythonaddins

class ToolClass2(object):
    """Implementation for Tool_addin.tool (Tool)"""
    def __init__(self):
        self.enabled = True
        self.cursor = 3
        self.shape = "Line"
    def onLine(self, line_geometry):
        arcpy.env.workspace = r"C:\temp\python\test.gdb"

        edit = arcpy.da.Editor(r"C:\temp\python")
        arcpy.CopyFeatures_management(line_geometry, "line_test")

        rows = arcpy.SearchCursor("line_test")
        for row in rows:
            geom = row.shape
            X = geom.lastPoint.X
            Y = geom.lastPoint.Y
            length = row.Shape_Length
        del row, rows

        row_value = (length, (X, Y))

        cursor = arcpy.da.InsertCursor(r"C:\temp\python\point_test.shp", ("Distance", "SHAPE@XY"))
        cursor.insertRow(row_value)
        del cursor

        arcpy.Delete_management("line_test")

        edit.stopOperation()
        edit.stopEditing(True)
0 Kudos