def voronoi_polygons(grid): ''' Creates Voronoi polygons in x,y from a set of points. Returns: cell (list[Cell]): the cells of the graph. A cell has a `center` and a\ `polygon` list of vertices. An example can be seen below: >>> g = grid((3, 3), scale=2.5) >>> voronoi_polygons(g) [Cell(center=Point3d(2.5, 2.5, 0), polygon=[Point3d(3.75, 1.25, 0), Point3d(3.75, 3.75, 0), Point3d(1.25, 3.75, 0), Point3d(1.25, 1.25, 0)])] ''' pyvoronoi_scaling = 100.0 voro = pv.Pyvoronoi(pyvoronoi_scaling) for p in grid: voro.AddPoint(p.xy) voro.Construct() pv_cells = voro.GetCells() cells = [] for i, pv_cell in enumerate(pv_cells): if pv_cell.is_open: continue polygon = [] for edge_index in pv_cell.edges: e = voro.GetEdge(edge_index) start = voro.GetVertex(e.start) polygon.append(Point3d(start.X, start.Y, grid[pv_cell.site].z)) cells.append(Cell( Point3d(*grid[pv_cell.site]), polygon, )) return cells
def __init__(self, points: list, segments: list, bounding_box_coords: list, scaling_factor=100000.0): if pyvoronoi is None: raise ImportError("Impossible to use Voronoi utils, `pyvoronoi` package not found.") self.pv = pyvoronoi.Pyvoronoi(scaling_factor) for p in points: self.pv.AddPoint(p) for s in segments: self.pv.AddSegment(s) self.pv.Construct() self.discretization_tolerance = 10000 / scaling_factor self.bounding_box_coords = bounding_box_coords
def run(self): # return [1,2,3] pv = pyvoronoi.Pyvoronoi(1) pv.AddSegment([[0, 0], [0, 2]]) pv.AddSegment([[0, 2], [1, 2]]) pv.AddSegment([[1, 2], [1, 0]]) pv.AddSegment([[1, 0], [0, 0]]) pv.Construct() edges = pv.GetEdges() vertices = pv.GetVertices() return vertices
def __get_voronoi(self) -> Tuple[pyvoronoi.Pyvoronoi, List]: all_segments = self.__get_segments_for_elements(self.all_elements) # Add the page boundary as segments: all_segments += [ [(0, 0), (0, self.page.height)], [(0, 0), (self.page.width, 0)], [(0, self.page.height), (self.page.width, self.page.height)], [(self.page.width, 0), (self.page.width, self.page.height)], ] pv = pyvoronoi.Pyvoronoi(10) for segment in all_segments: pv.AddSegment(segment) pv.Construct() return pv, all_segments
def MaximumInscribedCircle(geom): ''' Computer maximum inscribed circle of a polygon by voronoi of its boundary segments with pyvoronoi ''' if not isinstance(geom, Polygon): raise ValueError('Must be instance of a Polygon class; found ' + geom.__class__.__name__) pv = pyvoronoi.Pyvoronoi(1) exterior = geom.exterior ptnum = len(exterior.coords) coords = exterior.coords[:] for i in range(ptnum - 1): j = (i + 1) % ptnum pv.AddSegment([coords[i], coords[j]]) for interior in geom.interiors: ptnum = len(interior.coords) coords = interior.coords[:] for i in range(ptnum - 1): j = (i + 1) % ptnum pv.AddSegment([coords[i], coords[j]]) pv.Construct() vertices = pv.GetVertices() radius = 0 center = None for v in vertices: pt = Point(v.X, v.Y) if (geom.contains(pt)): r = pt.distance(geom.boundary) if (r > radius): radius = r center = pt return (center.x, center.y, radius)
def unsafe_neighbors(shapes, scale=100, border=1): # shapes must not intersect. pv = pyvoronoi.Pyvoronoi(scale) site_to_shape = [] for i, shape in enumerate(shapes): if shape.is_empty: continue coords = np.asarray(shape.exterior) assert np.all(coords[0] == coords[-1]) for a, b in zip(coords, coords[1:]): assert np.any(a != b) pv.AddSegment((a, b)) site_to_shape.append(i) minx, miny, maxx, maxy = shape_collection_bounds(shapes, border) pv.AddSegment(((minx, miny), (maxx, miny))) pv.AddSegment(((maxx, miny), (maxx, maxy))) pv.AddSegment(((maxx, maxy), (minx, maxy))) pv.AddSegment(((minx, maxy), (minx, miny))) site_to_shape.extend([-1, -1, -1, -1]) pv.Construct() edges = pv.GetEdges() cells = pv.GetCells() graph = nx.Graph() graph.add_nodes_from(range(len(cells))) def adjacent_cell(): for edge in edges: yield edge.cell, edges[edge.twin].cell graph.add_edges_from(adjacent_cell()) for i, cell in enumerate(cells): if cell.is_open or cell.site < 0: graph.remove_node(i) elif not cell.contains_segment: edges = np.array(list(graph.edges(i))) nhood = set(edges.flatten()) - set([i]) nhood = list(nhood) for j, x in enumerate(nhood): for y in nhood[j + 1:]: graph.add_edge(x, y) graph.remove_node(i) partitions = [[] for _ in shapes] for i in graph.nodes(): k = site_to_shape[cells[i].site] partitions[k].append(i) graph = nx.quotient_graph(graph, partitions) mapping = dict() for group in graph.nodes: if group: mapping[group] = site_to_shape[cells[next(iter(group))].site] graph = nx.relabel_nodes(graph, mapping) return graph
def main(): try: ################################################################################## #READ PARAMETERS ################################################################################## inpoints = arcpy.GetParameterAsText(0) inlines = arcpy.GetParameterAsText(1) outWorkspace = arcpy.GetParameterAsText(2) outpoints = arcpy.GetParameterAsText(3) outsegments = arcpy.GetParameterAsText(4) outpolygons = arcpy.GetParameterAsText(5) inroads_identifier = arcpy.GetParameterAsText(6) arcpy.env.workspace = outWorkspace ################################################################################## #HARD CODED PARAMETERS ################################################################################## if arcpy.env.scratchWorkspace is None: arcpy.env.scratchWorkspace = r'C:\Users\fancelin\Documents\ArcGIS\Default.gdb' factor = 100 inroads_split_name = "voronoying_lines_split" inroads_split_line_name = "voronoying_lines_split_lines" inroads_split = "{0}{1}{2}".format(arcpy.env.scratchWorkspace, os.path.sep, inroads_split_name) inroads_split_line = "{0}{1}{2}".format(arcpy.env.scratchWorkspace, os.path.sep, inroads_split_line_name) spatial_reference = arcpy.Describe(inlines).spatialReference ################################################################################## #VALIDATION ################################################################################## arcpy.AddMessage("Validation") #Validate license requirements validateLicense() #Validate lines are provided if len(outsegments) == 0: raise Exception("Input lines were not provided.") #Validate that a line identifier was provided if len(inroads_identifier) == 0: raise Exception("Input lines identifer was not provided.") extents = [] #Validate input line feature class. inlinesBBox = validateInputLineFeatureClass(inlines) extents.append(inlinesBBox) #Validate input point feature class if required. inPointsBBox = validateInputPointFeatureClass(inpoints) if len( arcpy.GetParameterAsText(0)) > 0 else None ################################################################################## #REMOVE FEATURE CLASSES ################################################################################## for fc in [ inroads_split, inroads_split_line, "{0}{1}{2}".format(outWorkspace, os.path.sep, outpoints), "{0}{1}{2}".format(outWorkspace, os.path.sep, outsegments), "{0}{1}{2}".format(outWorkspace, os.path.sep, outpolygons) ]: delFCByPath(fc) ################################################################################## #COMPUTING THE BOUNDING BOX ################################################################################## # Instanciate pyvoronoi pv = pyvoronoi.Pyvoronoi(factor) arcpy.AddMessage("Add points to voronoi") pointOIDs = [] if inPointsBBox != None: extents.append(inPointsBBox) for point in arcpy.da.SearchCursor(inpoints, ['SHAPE@X', 'SHAPE@Y', 'OID@']): pointOIDs.append(point[2]) pv.AddPoint([point[0], point[1]]) arcpy.AddMessage("Computing bounding box outlines") finalBBox = mergeExtent(extents) finalBBoxExpended = arcpy.Extent(finalBBox.XMin - 1, finalBBox.YMin - 1, finalBBox.XMax + 1, finalBBox.YMax + 1) bbox_line = [ arcpy.Array([ arcpy.Point(finalBBox.XMin, finalBBox.YMin), arcpy.Point(finalBBox.XMax, finalBBox.YMin) ]), arcpy.Array([ arcpy.Point(finalBBox.XMin, finalBBox.YMin), arcpy.Point(finalBBox.XMin, finalBBox.YMax) ]), arcpy.Array([ arcpy.Point(finalBBox.XMax, finalBBox.YMax), arcpy.Point(finalBBox.XMin, finalBBox.YMax) ]), arcpy.Array([ arcpy.Point(finalBBox.XMax, finalBBox.YMax), arcpy.Point(finalBBox.XMax, finalBBox.YMin) ]), arcpy.Array([ arcpy.Point(finalBBoxExpended.XMin, finalBBoxExpended.YMin), arcpy.Point(finalBBoxExpended.XMax, finalBBoxExpended.YMin) ]), arcpy.Array([ arcpy.Point(finalBBoxExpended.XMin, finalBBoxExpended.YMin), arcpy.Point(finalBBoxExpended.XMin, finalBBoxExpended.YMax) ]), arcpy.Array([ arcpy.Point(finalBBoxExpended.XMax, finalBBoxExpended.YMax), arcpy.Point(finalBBoxExpended.XMin, finalBBoxExpended.YMax) ]), arcpy.Array([ arcpy.Point(finalBBoxExpended.XMax, finalBBoxExpended.YMax), arcpy.Point(finalBBoxExpended.XMax, finalBBoxExpended.YMin) ]) ] arcpy.AddMessage("Bounding Box Info: {0},{1} | {2},{3}".format( finalBBox.XMin, finalBBox.YMin, finalBBox.XMax, finalBBox.YMax)) ################################################################################## #FORMAT INPUT. NEED TO MAKE SURE LINE ARE SPLIT AT VERTICES AND THAT THERE ARE NO OVERLAPS ################################################################################## arcpy.AddMessage("Format lines") arcpy.AddMessage("Split lines at vertices") arcpy.SplitLine_management(in_features=inlines, out_feature_class=inroads_split) arcpy.AddMessage("Add bounding box") with arcpy.da.InsertCursor(inroads_split, ['SHAPE@', inroads_identifier]) as op: for pointArray in bbox_line: arcpy.AddMessage("{0},{1} - {2},{3}".format( pointArray[0].X, pointArray[0].Y, pointArray[1].X, pointArray[1].Y)) op.insertRow([arcpy.Polyline(pointArray), None]) del op arcpy.AddMessage("Split lines at intersections") arcpy.FeatureToLine_management(inroads_split, inroads_split_line, '#', 'ATTRIBUTES') ################################################################################## #SEND LINE INPUT TO VORONOI AND CONSTRUCT THE GRAPH ################################################################################## arcpy.AddMessage("Add lines to voronoi") lineIds = [] for road in arcpy.da.SearchCursor( inroads_split_line, ['SHAPE@', 'OID@', 'SHAPE@LENGTH', inroads_identifier]): if (road[2] > 0): lineIds.append(road[3]) pv.AddSegment([[road[0].firstPoint.X, road[0].firstPoint.Y], [road[0].lastPoint.X, road[0].lastPoint.Y]]) arcpy.AddMessage("Construct voronoi") pv.Construct() cells = pv.GetCells() edges = pv.GetEdges() vertices = pv.GetVertices() ################################################################################## #CREATE THE OUTPUT FEATURE CLASSES ################################################################################## arcpy.AddMessage("Construct output point feature class") if len(outpoints) > 0: arcpy.CreateFeatureclass_management( outWorkspace, outpoints, 'POINT', spatial_reference=spatial_reference) arcpy.AddField_management(outpoints, 'IDENTIFIER', "LONG") fields = ['IDENTIFIER', 'SHAPE@X', 'SHAPE@Y'] cursor = arcpy.da.InsertCursor(outpoints, fields) for vIndex in range(len(vertices)): v = vertices[vIndex] cursor.insertRow([vIndex, v.X, v.Y]) arcpy.AddMessage("Construct output segment feature class") if len(outsegments) > 0: arcpy.CreateFeatureclass_management( outWorkspace, outsegments, 'POLYLINE', spatial_reference=spatial_reference) arcpy.AddField_management(outsegments, 'EdgeIndex', "LONG") arcpy.AddField_management(outsegments, 'Start', "LONG") arcpy.AddField_management(outsegments, 'End', "LONG") arcpy.AddField_management(outsegments, 'IsLinear', "SHORT") arcpy.AddField_management(outsegments, 'IsPrimary', "SHORT") arcpy.AddField_management(outsegments, 'Site1', "LONG") arcpy.AddField_management(outsegments, 'Site2', "LONG") arcpy.AddField_management(outsegments, 'Cell', "LONG") arcpy.AddField_management(outsegments, 'Twin', "LONG") arcpy.AddField_management(outsegments, 'FROM_X', "DOUBLE") arcpy.AddField_management(outsegments, 'FROM_Y', "DOUBLE") arcpy.AddField_management(outsegments, 'TO_X', "DOUBLE") arcpy.AddField_management(outsegments, 'TO_Y', "DOUBLE") fields = [ 'EdgeIndex', 'Start', 'End', 'IsLinear', 'IsPrimary', 'Site1', 'Site2', 'Cell', 'Twin', 'FROM_X', 'FROM_Y', 'TO_X', 'TO_Y', 'SHAPE@' ] cursor = arcpy.da.InsertCursor(outsegments, fields) for cIndex in range(len(cells)): cell = cells[cIndex] if cell.is_open == False: if (cIndex % 5000 == 0 and cIndex > 0): arcpy.AddMessage("Cell Index: {0}".format(cIndex)) for i in range(len(cell.edges)): e = edges[cell.edges[i]] startVertex = vertices[e.start] endVertex = vertices[e.end] max_distance = Distance( [startVertex.X, startVertex.Y], [endVertex.X, endVertex.Y]) / 10 array = arcpy.Array() if startVertex != -1 and endVertex != -1: if (e.is_linear == True): array = arcpy.Array([ arcpy.Point(startVertex.X, startVertex.Y), arcpy.Point(endVertex.X, endVertex.Y) ]) else: try: points = pv.DiscretizeCurvedEdge( cell.edges[i], max_distance, 1 / factor) for p in points: array.append(arcpy.Point(p[0], p[1])) except pyvoronoi.FocusOnDirectixException: arcpy.AddMessage( "FocusOnDirectixException at: {5}. The drawing has been defaulted from a curved line to a straight line. Length {0} - From: {1}, {2} To: {3}, {4}" .format(max_distance, startVertex.X, startVertex.Y, endVertex.X, endVertex.Y, cell.edges[i])) array = arcpy.Array([ arcpy.Point(startVertex.X, startVertex.Y), arcpy.Point(endVertex.X, endVertex.Y) ]) except pyvoronoi.UnsolvableParabolaEquation: edge = pv.outputEdges[cell.edges[i]] sites = pv.ReturnCurvedSiteInformation( edge) pointSite = sites[0] segmentSite = sites[1] edgeStartVertex = pv.outputVertices[ edge.start] edgeEndVertex = pv.outputVertices[edge.end] print "Input Point: {0}".format(pointSite) print "Input Segment: {0}".format( segmentSite) print "Parabola Start: {0}".format( [edgeStartVertex.X, edgeStartVertex.Y]) print "Parabola End: {0}".format( [edgeEndVertex.X, edgeEndVertex.Y]) print "Distance: {0}".format(max_distance) arcpy.AddMessage( "UnsolvableParabolaEquation exception at: {5}. The drawing has been defaulted from a curved line to a straight line. Length {0} - From: {1}, {2} To: {3}, {4}" .format(max_distance, startVertex.X, startVertex.Y, endVertex.X, endVertex.Y, cell.edges[i])) array = arcpy.Array([ arcpy.Point(startVertex.X, startVertex.Y), arcpy.Point(endVertex.X, endVertex.Y) ]) polyline = arcpy.Polyline(array) cursor.insertRow( (cell.edges[i], e.start, e.end, e.is_linear, e.is_primary, e.site1, e.site2, e.cell, e.twin, startVertex.X, startVertex.Y, endVertex.X, endVertex.Y, polyline)) arcpy.AddMessage("Construct output cells feature class") if len(outpolygons) > 0: arcpy.CreateFeatureclass_management( outWorkspace, outpolygons, 'POLYGON', spatial_reference=spatial_reference) arcpy.AddField_management(outpolygons, 'CELL_ID', "LONG") arcpy.AddField_management(outpolygons, 'CONTAINS_POINT', "SHORT") arcpy.AddField_management(outpolygons, 'CONTAINS_SEGMENT', "SHORT") arcpy.AddField_management(outpolygons, 'SITE', "LONG") arcpy.AddField_management(outpolygons, 'SOURCE_CATEGORY', "SHORT") arcpy.AddField_management(outpolygons, 'INPUT_TYPE', "TEXT") arcpy.AddField_management(outpolygons, 'INPUT_ID', "LONG") fields = [ 'CELL_ID', 'CONTAINS_POINT', 'CONTAINS_SEGMENT', 'SHAPE@', 'SITE', 'SOURCE_CATEGORY', 'INPUT_TYPE', 'INPUT_ID' ] cursor = arcpy.da.InsertCursor(outpolygons, fields) for cIndex in range(len(cells)): cell = cells[cIndex] if cell.is_open == False: if (cIndex % 5000 == 0 and cIndex > 0): arcpy.AddMessage("Cell Index: {0}".format(cIndex)) pointArray = arcpy.Array() for vIndex in cell.vertices: pointArray.add( arcpy.Point(vertices[vIndex].X, vertices[vIndex].Y)) input_type = None input_id = None if cell.site >= len(pointOIDs): input_type = "LINE" input_id = lineIds[cell.site - len(pointOIDs)] else: input_type = "POINT" input_id = pointOIDs[cell.site] polygon = arcpy.Polygon(pointArray) cursor.insertRow( (cell.cell_identifier, cell.contains_point, cell.contains_segment, polygon, cell.site, cell.source_category, input_type, input_id)) del cursor except Exception: tb = sys.exc_info()[2] tbInfo = traceback.format_tb(tb)[-1] arcpy.AddError('PYTHON ERRORS:\n%s\n%s: %s\n' % (tbInfo, sys.exc_type, sys.exc_value)) # print('PYTHON ERRORS:\n%s\n%s: %s\n' % # (tbInfo, _sys.exc_type, _sys.exc_value)) arcpy.AddMessage('PYTHON ERRORS:\n%s\n%s: %s\n' % (tbInfo, sys.exc_type, sys.exc_value)) gp_errors = arcpy.GetMessages(2) if gp_errors: arcpy.AddError('GP ERRORS:\n%s\n' % gp_errors)
def main(): try: ################################################################################## # READ PARAMETERS ################################################################################## inpoints = arcpy.GetParameterAsText(0) inlines = arcpy.GetParameterAsText(1) out_workspace = arcpy.GetParameterAsText(2) outpoints = arcpy.GetParameterAsText(3) outsegments = arcpy.GetParameterAsText(4) outpolygons = arcpy.GetParameterAsText(5) inroads_identifier = arcpy.GetParameterAsText(6) curve_ratio_txt = arcpy.GetParameterAsText(7) arcpy.env.workspace = out_workspace ################################################################################## # HARD CODED PARAMETERS ################################################################################## if arcpy.env.scratchWorkspace is None: arcpy.env.scratchWorkspace = r'in_memory' factor = 100 default_curve_ratio = 10 inroads_split_name = "voronoying_lines_split" inroads_split_line_name = "voronoying_lines_split_lines" inroads_split = os.path.join(arcpy.env.scratchWorkspace, inroads_split_name) inroads_split_line = os.path.join(arcpy.env.scratchWorkspace, inroads_split_line_name) spatial_reference = arcpy.Describe(inlines).spatialReference ################################################################################## # VALIDATION ################################################################################## arcpy.AddMessage("Validation") # Validate license requirements validate_license() # Validate lines are provided if len(outsegments) == 0: raise Exception("Input lines were not provided.") # Validate that a line identifier was provided if len(inroads_identifier) == 0: raise Exception("Input lines identifier was not provided.") extents = [] # Validate input line feature class. input_lines_bbox = validate_input_line_feature_class(inlines) extents.append(input_lines_bbox) # Validate input point feature class if required. input_points_bbox = validate_input_point_feature_class( inpoints) if len(arcpy.GetParameterAsText(0)) > 0 else None curve_ratio = default_curve_ratio if curve_ratio_txt is None and curve_ratio_txt == '' and curve_ratio_txt == '#': curve_ratio = float(curve_ratio_txt) if curve_ratio < 1: raise Exception( 'Invalid curve ratio. It must be greater than 1. Current value: {}' .format(curve_ratio)) ################################################################################## # REMOVE FEATURE CLASSES ################################################################################## for fc in [ inroads_split, inroads_split_line, os.path.join(out_workspace, outpoints), os.path.join(out_workspace, outsegments), os.path.join(out_workspace, outpolygons) ]: delete_feature_class(fc) ################################################################################## # COMPUTING THE BOUNDING BOX ################################################################################## # Invoke pyvoronoi pv = pyvoronoi.Pyvoronoi(factor) arcpy.AddMessage("Add points to voronoi") point_identifiers = [] if input_points_bbox is not None: extents.append(input_points_bbox) for point in arcpy.da.SearchCursor(inpoints, ['SHAPE@X', 'SHAPE@Y', 'OID@']): point_identifiers.append(point[2]) pv.AddPoint([point[0], point[1]]) arcpy.AddMessage("Computing bounding box outlines") final_bounding_box = merge_extent(extents) final_bounding_box_expended = arcpy.Extent(final_bounding_box.XMin - 1, final_bounding_box.YMin - 1, final_bounding_box.XMax + 1, final_bounding_box.YMax + 1) bbox_line = [ arcpy.Array([ arcpy.Point(final_bounding_box.XMin, final_bounding_box.YMin), arcpy.Point(final_bounding_box.XMax, final_bounding_box.YMin) ]), arcpy.Array([ arcpy.Point(final_bounding_box.XMin, final_bounding_box.YMin), arcpy.Point(final_bounding_box.XMin, final_bounding_box.YMax) ]), arcpy.Array([ arcpy.Point(final_bounding_box.XMax, final_bounding_box.YMax), arcpy.Point(final_bounding_box.XMin, final_bounding_box.YMax) ]), arcpy.Array([ arcpy.Point(final_bounding_box.XMax, final_bounding_box.YMax), arcpy.Point(final_bounding_box.XMax, final_bounding_box.YMin) ]), arcpy.Array([ arcpy.Point(final_bounding_box_expended.XMin, final_bounding_box_expended.YMin), arcpy.Point(final_bounding_box_expended.XMax, final_bounding_box_expended.YMin) ]), arcpy.Array([ arcpy.Point(final_bounding_box_expended.XMin, final_bounding_box_expended.YMin), arcpy.Point(final_bounding_box_expended.XMin, final_bounding_box_expended.YMax) ]), arcpy.Array([ arcpy.Point(final_bounding_box_expended.XMax, final_bounding_box_expended.YMax), arcpy.Point(final_bounding_box_expended.XMin, final_bounding_box_expended.YMax) ]), arcpy.Array([ arcpy.Point(final_bounding_box_expended.XMax, final_bounding_box_expended.YMax), arcpy.Point(final_bounding_box_expended.XMax, final_bounding_box_expended.YMin) ]) ] arcpy.AddMessage("Bounding Box Info: {0},{1} | {2},{3}".format( final_bounding_box.XMin, final_bounding_box.YMin, final_bounding_box.XMax, final_bounding_box.YMax)) ################################################################################## # FORMAT INPUT. NEED TO MAKE SURE LINE ARE SPLIT AT VERTICES AND THAT THERE ARE NO OVERLAPS ################################################################################## arcpy.AddMessage("Format lines") arcpy.AddMessage("Split lines at vertices") arcpy.SplitLine_management(in_features=inlines, out_feature_class=inroads_split) arcpy.AddMessage("Add bounding box") with arcpy.da.InsertCursor(inroads_split, ['SHAPE@', inroads_identifier]) as op: for pointArray in bbox_line: arcpy.AddMessage("{0},{1} - {2},{3}".format( pointArray[0].X, pointArray[0].Y, pointArray[1].X, pointArray[1].Y)) op.insertRow([arcpy.Polyline(pointArray), None]) del op arcpy.AddMessage("Split lines at intersections") arcpy.FeatureToLine_management(inroads_split, inroads_split_line, '#', 'ATTRIBUTES') ################################################################################## # SEND LINE INPUT TO VORONOI AND CONSTRUCT THE GRAPH ################################################################################## arcpy.AddMessage("Add lines to voronoi") line_identifier = [] for road in arcpy.da.SearchCursor( inroads_split_line, ['SHAPE@', 'OID@', 'SHAPE@LENGTH', inroads_identifier]): if road[2] > 0: line_identifier.append(road[3]) pv.AddSegment([[road[0].firstPoint.X, road[0].firstPoint.Y], [road[0].lastPoint.X, road[0].lastPoint.Y]]) arcpy.AddMessage("Construct voronoi") pv.Construct() count_cells = pv.CountCells() ################################################################################## # CREATE THE OUTPUT FEATURE CLASSES ################################################################################## arcpy.AddMessage("Construct output point feature class") if len(outpoints) > 0: arcpy.CreateFeatureclass_management( out_workspace, outpoints, 'POINT', spatial_reference=spatial_reference) arcpy.AddField_management(outpoints, 'IDENTIFIER', "LONG") fields = ['IDENTIFIER', 'SHAPE@X', 'SHAPE@Y'] with arcpy.da.InsertCursor(outpoints, fields) as cursor: count_vertex = pv.CountVertices() for vIndex in xrange(count_vertex): v = pv.GetVertex(vIndex) cursor.insertRow([vIndex, v.X, v.Y]) arcpy.AddMessage("Construct output segment feature class") if len(outsegments) > 0: arcpy.CreateFeatureclass_management( out_workspace, outsegments, 'POLYLINE', spatial_reference=spatial_reference) arcpy.AddField_management(outsegments, 'EdgeIndex', "LONG") arcpy.AddField_management(outsegments, 'Start', "LONG") arcpy.AddField_management(outsegments, 'End', "LONG") arcpy.AddField_management(outsegments, 'IsLinear', "SHORT") arcpy.AddField_management(outsegments, 'IsPrimary', "SHORT") arcpy.AddField_management(outsegments, 'Cell', "LONG") arcpy.AddField_management(outsegments, 'Twin', "LONG") fields = [ 'EdgeIndex', 'Start', 'End', 'IsLinear', 'IsPrimary', 'Cell', 'Twin', 'SHAPE@' ] with arcpy.da.InsertCursor(outsegments, fields) as cursor: for cIndex in xrange(count_cells): cell = pv.GetCell(cIndex) if not cell.is_open: if cIndex % 5000 == 0 and cIndex > 0: arcpy.AddMessage("Cell Index: {0}".format(cIndex)) for i in range(len(cell.edges)): e = pv.GetEdge(cell.edges[i]) start_vertex = pv.GetVertex(e.start) end_vertex = pv.GetVertex(e.end) max_distance = pyvoronoi.Distance( [start_vertex.X, start_vertex.Y], [end_vertex.X, end_vertex.Y]) / 10 array = arcpy.Array() if start_vertex != -1 and end_vertex != -1: if e.is_linear: array = arcpy.Array([ arcpy.Point(start_vertex.X, start_vertex.Y), arcpy.Point(end_vertex.X, end_vertex.Y) ]) else: try: points = pv.DiscretizeCurvedEdge( cell.edges[i], max_distance, 1 / curve_ratio) for p in points: array.append( arcpy.Point(p[0], p[1])) except pyvoronoi.FocusOnDirectixException: arcpy.AddMessage( "FocusOnDirectixException at: {5}. The drawing has been defaulted from a curved line to a straight line. Length {0} - From: {1}, {2} To: {3}, {4}" .format(max_distance, start_vertex.X, start_vertex.Y, end_vertex.X, end_vertex.Y, cell.edges[i])) array = arcpy.Array([ arcpy.Point( start_vertex.X, start_vertex.Y), arcpy.Point( end_vertex.X, end_vertex.Y) ]) except pyvoronoi.UnsolvableParabolaEquation: edge = pv.outputEdges[cell.edges[i]] sites = pv.ReturnCurvedSiteInformation( edge) point_site = sites[0] segment_site = sites[1] edge_start_vertex = pv.outputVertices[ edge.start] edge_end_vertex = pv.outputVertices[ edge.end] arcpy.AddWarning( "Input Point: {0}".format( point_site)) arcpy.AddWarning( "Input Segment: {0}".format( segment_site)) arcpy.AddWarning( "Parabola Start: {0}".format([ edge_start_vertex.X, edge_start_vertex.Y ])) arcpy.AddWarning( "Parabola End: {0}".format([ edge_end_vertex.X, edge_end_vertex.Y ])) arcpy.AddWarning( "Distance: {0}".format( max_distance)) arcpy.AddWarning( "UnsolvableParabolaEquation exception at: {5}. The drawing has been defaulted from a curved line to a straight line. Length {0} - From: {1}, {2} To: {3}, {4}" .format(max_distance, start_vertex.X, start_vertex.Y, end_vertex.X, end_vertex.Y, cell.edges[i])) array = arcpy.Array([ arcpy.Point( start_vertex.X, start_vertex.Y), arcpy.Point( end_vertex.X, end_vertex.Y) ]) except Exception as e: print "Exception happened at cell '{0}'".format( i) raise e polyline = arcpy.Polyline(array) cursor.insertRow( (cell.edges[i], e.start, e.end, e.is_linear, e.is_primary, e.cell, e.twin, polyline)) arcpy.AddMessage("Construct output cells feature class") if len(outpolygons) > 0: arcpy.CreateFeatureclass_management( out_workspace, outpolygons, 'POLYGON', spatial_reference=spatial_reference) arcpy.AddField_management(outpolygons, 'CELL_ID', "LONG") arcpy.AddField_management(outpolygons, 'CONTAINS_POINT', "SHORT") arcpy.AddField_management(outpolygons, 'CONTAINS_SEGMENT', "SHORT") arcpy.AddField_management(outpolygons, 'SITE', "LONG") arcpy.AddField_management(outpolygons, 'SOURCE_CATEGORY', "SHORT") arcpy.AddField_management(outpolygons, 'INPUT_TYPE', "TEXT") arcpy.AddField_management(outpolygons, 'INPUT_ID', "LONG") fields = [ 'CELL_ID', 'CONTAINS_POINT', 'CONTAINS_SEGMENT', 'SHAPE@', 'SITE', 'SOURCE_CATEGORY', 'INPUT_TYPE', 'INPUT_ID' ] with arcpy.da.InsertCursor(outpolygons, fields) as cursor: for cIndex in xrange(count_cells): try: cell = pv.GetCell(cIndex) if not cell.is_open and not cell.is_degenerate: if cIndex % 5000 == 0 and cIndex > 0: arcpy.AddMessage( "Cell Index: {0}".format(cIndex)) cell_points_array = arcpy.Array() previous_vertex_index = -1 for edge_index in cell.edges: e = pv.GetEdge(edge_index) start_vertex = pv.GetVertex(e.start) end_vertex = pv.GetVertex(e.end) max_distance = pyvoronoi.Distance( [start_vertex.X, start_vertex.Y], [end_vertex.X, end_vertex.Y]) / 10 points = [] if e.is_linear: points.append( [start_vertex.X, start_vertex.Y]) points.append([end_vertex.X, end_vertex.Y]) else: try: curved_points = pv.DiscretizeCurvedEdge( edge_index, max_distance, 1 / curve_ratio) points.extend(curved_points) except Exception as e: arcpy.AddError( "Exception happened at cell '{0}'". format(i)) points.append( [start_vertex.X, start_vertex.Y]) points.append( [end_vertex.X, end_vertex.Y]) start_index = 1 if previous_vertex_index == e.start else 0 for index in range(start_index, len(points)): point = points[index] cell_points_array.append( arcpy.Point(point[0], point[1])) input_type = 'LINE' if cell.site >= len( point_identifiers) else 'POINT' input_id = line_identifier[ cell.site - len(point_identifiers)] if cell.site >= len( point_identifiers) else point_identifiers[ cell.site] polygon = arcpy.Polygon(cell_points_array) cursor.insertRow( (cell.cell_identifier, cell.contains_point, cell.contains_segment, polygon, cell.site, cell.source_category, input_type, input_id)) except Exception as e: print "Failed on cell {0}".format(cIndex) raise Exception(e) except Exception: tb = sys.exc_info()[2] tbInfo = traceback.format_tb(tb)[-1] arcpy.AddError('PYTHON ERRORS:\n%s\n%s: %s\n' % (tbInfo, sys.exc_type, sys.exc_value)) arcpy.AddMessage('PYTHON ERRORS:\n%s\n%s: %s\n' % (tbInfo, sys.exc_type, sys.exc_value)) gp_errors = arcpy.GetMessages(2) if gp_errors: arcpy.AddError('GP ERRORS:\n%s\n' % gp_errors)