def points_in_shape(geom, population): """ plot n points randomly within a shapely geom first, cut the shape into triangles then, give each triangle a portion of points based on relative area within each triangle, distribute points using a weighted average return a list of (x, y) coordinates """ triangles = [t for t in triangulate(geom) if t.within(geom)] points = [] offset = -1 * population # count up as we go for triangle in triangles: ratio = triangle.area / geom.area n = round(ratio * population) offset += n vertices = triangle.exterior.coords[:3] if n > 0: points.extend(points_on_triangle(vertices, n)) # too many points if offset > 0: return points[:-offset] # not enough, cycle through triangles until we do triangles = itertools.cycle(triangles) while offset < 0: triangle = next(triangles) vertices = triangle.exterior.coords[:3] points.extend(points_on_triangle(vertices, 1)) offset += 1 return points
def triangulate_polygon(polygon: Polygon): """Attempts to convert a polygon into triangles.""" # XXX: shapely.ops.triangulate current creates a convex fill of triangles. return [ tri_face for tri_face in triangulate(polygon) if tri_face.centroid.within(polygon) ]
def from_threat_zones( cls, threat_zones: ThreatZones, theater: ConflictTheater ) -> NavMesh: # Simplify the threat poly to reduce the number of nav zones. Increase # the size of the zone and then simplify it with the buffer size as the # error margin. This will create a simpler poly around the threat zone. buffer = nautical_miles(10).meters threat_poly = threat_zones.all.buffer(buffer).simplify(buffer) # Threat zones can be disconnected. Create a list of threat zones. if isinstance(threat_poly, MultiPolygon): polys = list(threat_poly.geoms) else: polys = [threat_poly] # Subtract the threat zones from the whole-map poly to build a navmesh # for the *safe* areas. Navigation within threatened regions is always # a straight line to the target or out of the threatened region. bounds = cls.map_bounds(theater) for poly in polys: bounds = bounds.difference(poly) # Triangulate the safe-region to build the navmesh. navpolys = cls.create_navpolys(triangulate(bounds), threat_zones) cls.associate_neighbors(navpolys) return cls(navpolys)
def tesselate(shape): """ shape -- shapely.geometry.Geometry returns a list of triangles """ triangles = [s for s in ops.triangulate(shape)] if 0 == len(triangles): triangles = [ transform_polygon(IRET, s) for s in ops.triangulate(transform_multipolygon(RET, shape)) ] contained_triangles = filter( lambda s: shape.contains( geometry.Point(get_triangle_center(triangle_from_shape(s)))), triangles) return [triangle_from_shape(s) for s in triangles]
def generate_random_triang_method(shape, num_points: int, country: str): """ It generates 'points' (ex. 1, 5, 10, 1000) random latitude-longitude pairs using triangulation and affine transformation :param shape: shape in which you want to fit your coordinates . Polygon and MultiPolygon are the only shapes accepted :param num_points: how many random latitude-longitude pairs do you want to generate :param country: country name :return: list of features (geojson) containing the random points generated by the method """ areas = [] transforms = [] points_in = [] for t in triangulate(shape): areas.append(t.area) (x0, y0), (x1, y1), (x2, y2), _ = t.exterior.coords transforms.append([x1 - x0, x2 - x0, y2 - y0, y1 - y0, x0, y0]) points = [] list_of_points = [] counter = 0 for transform in random.choices(transforms, weights=areas, k=num_points): x, y = [random.random() for _ in range(2)] if x + y > 1: p = geom_shapely.Point(1 - x, 1 - y) else: p = geom_shapely.Point(x, y) points.append(affine_transform(p, transform)) # checking if all the points generated are contained in shape for p in points: if shape.contains(p): points_in.append(p) else: new_p = regenerate_random_point(shape) while not(new_p.within(shape)): new_p = regenerate_random_point(shape) points_in.append(new_p) for p in points_in: ran_point = { "type": "Feature", "geometry": { "type": "Point", "coordinates": [p.xy[0][0], p.xy[1][0]] }, "properties": { "point": counter + 1, "country": str(country) } } list_of_points.append(ran_point) counter += 1 return list_of_points
def prepPolygon(poly): THRESHOLD = 10e-6 toSample = poly prepped = prep(poly) raw = triangulate(toSample) triangles = [ x for x in raw if prepped.contains_properly(x.buffer(-THRESHOLD)) ] areas = [t.area for t in triangles] totalArea = sum(areas) numSamples = [(int)(ceil((x / totalArea) * SAMPLES)) for x in areas] paired = zip(numSamples, triangles) return paired, prepped
def MinkowskiSum(first, second): startTime = time.time() n, m = len(first), len(second) first = SPolygon(first) second = SPolygon(second) mem = getsizeof(first) + getsizeof(second) fp = triangulate(first) sp = triangulate(second) mem += getsizeof(fp) + getsizeof(sp) fpp, spp = [], [] for polygon in fp: points = list(mapping(polygon)["coordinates"][0][:-1]) if first.contains(polygon): fpp.append(points) for polygon in sp: points = list(mapping(polygon)["coordinates"][0][:-1]) if second.contains(polygon): spp.append(points) mem += getsizeof(fpp) + getsizeof(spp) sums = [] for f in fpp: for s in spp: sums.append(ConvexMinkowskiSum(f, s)) pp = [] for polygon in sums: pp.append(SPolygon(polygon)) result = cascaded_union(pp) mem += getsizeof(pp) + getsizeof(sums) + getsizeof(result) print("Minkowski sum (n={}, m={}): {:f} ms, {} bytes".format( n, m, (time.time() - startTime) * 1000, mem)) return list(mapping(result)["coordinates"][0])[:-1]
def __init__(self, vertices=[(0, 0), (1, 0), (1, 1), (0, 1)]): polygon = Polygon(vertices) # setup polygon and triangulate it self.vertices = vertices self.areas = [] self.transforms = [] self.triangles = [] for t in triangulate(polygon): self.areas.append(t.area) (x0, y0), (x1, y1), (x2, y2), _ = t.exterior.coords self.triangles.append([[x0, x1, x2, x0], [y0, y1, y2, y0]]) #print((x0, y0), (x1, y1), (x2, y2)) self.transforms.append( [x2 - x0, x1 - x0, y2 - y0, y1 - y0, x0, y0])
def points_in_shape(geom, population): """ plot n points randomly within a shapely geom first, cut the shape into triangles then, give each triangle a portion of points based on relative area within each triangle, distribute points using a weighted average yield each set of points (one yield per triangle) """ triangles = triangulate(geom) for triangle in triangles: ratio = triangle.area / geom.area n = round(ratio * population) vertices = triangle.exterior.coords[:3] if n > 0: yield points_on_triangle(vertices, n)
def __init__(self, raster_mask, no_data_value=None, ignore_labels=None): if ignore_labels is None: ignore_labels = [] self.geometries = [{'label': int(label), 'polygon': Polygon(LinearRing(shp['coordinates'][0]), [LinearRing(pts) for pts in shp['coordinates'][1:]])} for index, (shp, label) in enumerate(shapes(raster_mask, mask=None)) if (int(label) is not no_data_value) and (int(label) not in ignore_labels)] self.areas = np.asarray([entry['polygon'].area for entry in self.geometries]) self.decomposition = [triangulate(entry['polygon']) for entry in self.geometries] self.label2cc = collections.defaultdict(list) for index, entry in enumerate(self.geometries): self.label2cc[entry['label']].append(index)
def generate_3d_mesh(debugger: MyDebugger, output_filename: str, input_folder: str, thickness: float): """ generate a 3D mesh of the given contour with the given thickness :param debugger: the debugger to provide directory for obj to be stored :param output_filename: filename (excluding the extension) :param contour: the contour to create 3d object with :param thickness: the thickness of 3d object mesh :return: None """ filename_path = os.path.abspath(input_folder) assert os.path.isfile(filename_path) contour = read_2d_obj(input_folder) if output_filename[-4:] != '.obj': output_filename = output_filename + '.obj' destination = debugger.file_path(output_filename) with open(destination, 'w') as obj_file: point_to_vertex = {} for index, point in enumerate(contour): point_to_vertex[tuple(point)] = (index * 2 + 1, index * 2 + 2) print(f'v {point[0]} {point[1]} 0', file=obj_file) print(f'v {point[0]} {point[1]} {thickness}', file=obj_file) contour_poly = Polygon(contour) triangles = triangulate(contour_poly) for triangle in triangles: if len(triangles) > 1: triangle_bound = LineString(triangle.exterior) if not triangle_bound.within(contour_poly): continue *points, _ = triangle.exterior.coords face_1, face_2 = zip(*[point_to_vertex[point] for point in points]) for face in (face_1[::-1], face_2): print('f ' + ' '.join([str(i) for i in face]), file=obj_file) for index, point in enumerate(contour): lower_point, upper_point = point_to_vertex[tuple(point)] lower_prev, upper_prev = point_to_vertex[tuple(contour[index - 1])] print('f ' + ' '.join([ str(point) for point in (upper_prev, lower_point, upper_point) ]), file=obj_file) print('f ' + ' '.join([ str(point) for point in (upper_prev, lower_prev, lower_point) ]), file=obj_file)
def random_points_in_polygon(polygon, k): "Return list of k points chosen uniformly at random inside the polygon." areas = [] transforms = [] for t in triangulate(polygon): areas.append(t.area) (x0, y0), (x1, y1), (x2, y2), _ = t.exterior.coords transforms.append([x1 - x0, x2 - x0, y2 - y0, y1 - y0, x0, y0]) points = [] for transform in random.choices(transforms, weights=areas, k=k): x, y = [random.random() for _ in range(2)] if x + y > 1: p = Point(1 - x, 1 - y) else: p = Point(x, y) points.append(affine_transform(p, transform)) return points
def simplify_geom(geom_in, crs="EPSG:4326"): geom = geom_in # Pick biggest polygon from multipolygon if geom.type == "MultiPolygon": geom = max(geom, key=lambda x: x.area) # Triangulate rawtriangles = list(triangulate(geom.geom)) triangles = list( filter( lambda x: geom_in.geom.contains(x.representative_point()) and x. area / geom.area > 0.1, rawtriangles, )) geom = unary_union(triangles) if geom.type == "MultiPolygon": geom = max(geom, key=lambda x: x.area) return Geometry(geom, crs=crs)
def uniform_sample(poly, n=100): """ Uniformly sample the Delaunay triangulation of a polygon. If the polygon is convex, this will uniformly sample its area. Parameters ---------- poly: Shapely Polygon n: Number of points Returns ------- [n x 2] numpy array of x-y coordinates that are uniformly distributed over the Delaunay triangulation. """ polys = triangulate(poly) # Normalize the areas areas = np.array([p.area for p in polys]) areas /= areas.sum() # Randomly select a triangle weighted by area # t_inds is the index of the chosen triangle t_inds = np.searchsorted(np.cumsum(areas), np.random.random(n)) # Randomly sample the area of each triangle according to # P = (1-sqrt(r1))A + (sqrt(r1)(1-r2))B + (sqrt(r1)r2)C # where r1, r2 are sampled uniform [0, 1] and A, B, C are the triangle # vertices # http://math.stackexchange.com/questions/18686/uniform-random-point-in-triangle # Compute the coefficients sr1 = np.sqrt(np.random.random(n)) # sr1 is sqrt(r1) above r2 = np.random.random(n) c0 = 1 - sr1 c1 = sr1 * (1 - r2) c2 = sr1 * r2 # Grab the triangle vertices. # v is a 3-element list where each element is [len(polys) x 2] # array of each triangle vertex. It represents, A, B, C above. v = [np.array([p.exterior.coords[i] for p in polys]) for i in range(3)] # Compute the points. v[i] is [N x 2] and the coefficients are [N x 1] P = (c0[:, np.newaxis] * v[0][t_inds, :] + c1[:, np.newaxis] * v[1][t_inds, :] + c2[:, np.newaxis] * v[2][t_inds, :]) return P
def mesh2D(poly): pp = sg.Polygon(poly) xmin, ymin, xmax, ymax = pp.bounds points = np.array(poly) if xmax - xmin > ymax - ymin: dis = (xmax - xmin) / 5 else: dis = (ymax - ymin) / 5 x, y = np.meshgrid(np.arange(xmin - 1, xmax + 1, dis / 8), np.arange(ymin - 1, ymax + 1, dis / 8)) pgrid = np.c_[x.ravel(), y.ravel()] for p in pgrid: p11 = sg.Point(p) if p11.within(pp) and min(np.linalg.norm(points - p, axis=1)) > dis: points = np.vstack([points, p]) ppoints = sg.MultiPoint(points) tri = so.triangulate(ppoints) ff = [a for a in tri if a.within(pp)] vert = [list(b.exterior.coords) for b in ff] return vert, points
def test_total_area(): f = feature(0, population=100) geom = geometry.shape(f.geometry) triangles = [t for t in triangulate(geom) if t.within(geom)] ratios = [t.area / geom.area for t in triangles] counts = [r * f.properties["population"] for r in ratios] # account for floats tolerance = 0.0001 # should match assert geom.area == sum(t.area for t in triangles) # make sure we get close assert 1 - sum(ratios) < tolerance # should add up assert abs(sum(counts) - f.properties["population"]) < tolerance
def generate(self, timestamp=None): triangles = triangulate(self.polygon) areas = [triangle.area for triangle in triangles] areas_normalized = [ triangle.area / sum(areas) for triangle in triangles ] t = np.random.choice(triangles, p=areas_normalized) a, b = sorted([random.random(), random.random()]) coords = t.exterior.coords lat = a * coords[0][0] + (b - a) * coords[1][0] + (1 - b) * coords[2][0] long = a * coords[0][1] + (b - a) * coords[1][1] + (1 - b) * coords[2][1] return Point(latitude=lat, longitude=long)
def spatop_joint_delaunay(): with self.flask_app.app_context(): esh = get_handler() active_es_id = get_session('active_es_id') es = esh.get_energy_system(active_es_id) sub_area_shape_list = get_session('sub_area_shape_list') top_area_shape = get_session('top_area_shape') list_of_shapely_points = list() # to feed the delaunay triangulation algorithm mapping_centroid_wkt_to_joint = dict() # to find the joints at both sides of all edges for ar in sub_area_shape_list: list_of_shapely_points.append(ar['shape_centroid'].shape) mapping_centroid_wkt_to_joint[ar['shape_centroid_wkt']] = ar['esdl_joint'] shapely_multipoint = MultiPoint(list_of_shapely_points) edges = triangulate(shapely_multipoint, edges=True) self.create_pipes(edges, top_area_shape, mapping_centroid_wkt_to_joint)
def as_mesh(self): if self._image is None: PCG_RESOURCES_ROOT_DIR.error( 'No image found for description of heightmap') return None vertices = np.zeros((np.size(self._image), 3)) index_x, index_y = np.meshgrid( np.linspace(0, self._image.shape[0] - 1, self._image.shape[0]), np.linspace(0, self._image.shape[1] - 1, self._image.shape[1])) vertices[:, 0] = np.reshape(index_x, -1) vertices[:, 1] = np.reshape(index_y, -1) faces = list() polygons = triangulate( MultiPoint([(xi, yi) for xi, yi in zip(index_x.flatten(), index_y.flatten()) ])) for i in range(len(polygons)): triangle = list() for j in range(3): point = polygons[i].boundary.coords[j] index = np.nonzero( np.logical_and(vertices[:, 0] == point[0], vertices[:, 1] == point[1]))[0] triangle.append(index[0]) faces.append(triangle) faces = np.array(faces) vertices[:, 0] = vertices[:, 0] / vertices[:, 0].max() * \ self._size[0] - self._size[0] / 2 + self._pos[0] vertices[:, 1] = vertices[:, 1] / vertices[:, 1].max() * \ self._size[1] - self._size[1] / 2 + self._pos[1] vertices[:, 2] = self._size[2] * \ np.reshape(self._image / 255.0, -1) + \ self._pos[2] return Mesh.from_mesh(trimesh.Trimesh(vertices=vertices, faces=faces), scale=[1, 1, 1])
def wavefront_meshing(polygon, edge_size, graphic=None): # visualize wavefront on selected segment ext = polygon.exterior.xy coords = [[ext[0][i], ext[1][i]] for i in range(len(ext[0]))] wavefront_init = regularize_contour(coords, edge_size) front = advancing_front(wavefront_init, stepsize=edge_size, min_step=edge_size / 1.5, graphic=graphic) triangles = triangulate(MultiPoint(front["node_coords"])) """ keep = [np.column_stack(triangle.exterior.xy) for triangle in triangles if triangle.within(self.segments[self.selected_segment]["polygon"])] """ # triangles can leave the boundary as long as it is less than 1/4 of their area that is outside keep = [ np.column_stack(triangle.exterior.xy) for triangle in triangles if triangle.intersection(polygon).area > triangle.area / 4 ] #convert coords into indices for triangles indices = [] for tr in keep: a = [ i for i in range(len(front["node_coords"])) if np.array_equal(front["node_coords"][i], tr[0]) ][0] b = [ i for i in range(len(front["node_coords"])) if np.array_equal(front["node_coords"][i], tr[1]) ][0] c = [ i for i in range(len(front["node_coords"])) if np.array_equal(front["node_coords"][i], tr[2]) ][0] indices.append([a, b, c]) indices = np.array(indices) return front["node_coords"], indices
def randomPatchPointOld(self): "Return a point chosen uniformly at random inside polygon." areas = [] transforms = [] for t in triangulate(Polygon(self.vertices)): areas.append(t.area) (x0, y0), (x1, y1), (x2, y2), _ = t.exterior.coords transforms.append([x1 - x0, x2 - x0, y2 - y0, y1 - y0, x0, y0]) weights = [areas[ii] / sum(areas) for ii in range(len(areas))] transform = numpy.random.choice(range(len(transforms)), 1, p=weights) x, y = [random.random() for _ in range(2)] if x + y > 1: p = Point(1 - x, 1 - y) else: p = Point([x, y]) pointPoints = affine_transform(p, transforms[transform[0]]).coords.xy point = [pointPoints[ii][0] for ii in range(2)] return point
def prepPolygonSafe(poly): THRESHOLD = 10e-6 toSample = Polygon(poly.exterior) prepped = prep(toSample) raw = [] try: raw = triangulate(toSample) except: logger.error( "prepPolygonSafe failed to triangulate a polygon, dumping to failedTriangulation.json." ) open("failedTriangulation.json", "wb").write(json.dumps(mapping(poly))) exit triangles = [ x for x in raw if prepped.contains_properly(x.buffer(-THRESHOLD)) ] areas = [t.area for t in triangles] totalArea = sum(areas) numSamples = [(int)(ceil((x / totalArea) * SAMPLES)) for x in areas] paired = zip(numSamples, triangles) return paired, prep(poly)
def spatop_joint_delaunay(): with self.flask_app.app_context(): esh = get_handler() active_es_id = get_session('active_es_id') es = esh.get_energy_system(active_es_id) area = es.instance[0].area list_of_shapely_points = list() # to feed the delaunay triangulation algorithm mapping_centroid_wkt_to_joint = dict() # to find the joints at both sides of all edges for obj in area.eAllContents(): if isinstance(obj, esdl.Joint): geom = obj.geometry sh_geom = Shape.create(geom) list_of_shapely_points.append(sh_geom.shape) mapping_centroid_wkt_to_joint[sh_geom.get_wkt()] = obj if len(list_of_shapely_points): shapely_multipoint = MultiPoint(list_of_shapely_points) edges = triangulate(shapely_multipoint, edges=True) self.create_pipes(edges, None, mapping_centroid_wkt_to_joint)
def __init__( self, vertices: MultiPoint, max_length_filter_gen, min_length_filter_gen, buffer_size_gen, cap_style=None, join_style=None, buffer_individually=True, ): self.vertices = vertices self.max_length_filter_gen = max_length_filter_gen self.min_length_filter_gen = min_length_filter_gen self.buffer_size_gen = buffer_size_gen self.buffer_individually = buffer_individually if cap_style is None: self._cs = make_callable(2) if join_style is None: self._js = make_callable(3) self.edges = MultiLineString(so.triangulate(vertices, edges=True))
return True return False if __name__ == '__main__': # Create plot fig = pyplot.figure(1, figsize=SIZE, dpi=90) ax = fig.add_subplot(121) set_limits(ax, 0, 5, 0, 5) # Create polygon array = [[1, 2], [5, 3], [3, 3], [3, 4]] polygon = Polygon(array) points = MultiPoint([(1, 2), (5, 3), (3, 3), (3, 4), (1, 4)]) triangles = triangulate(points) # Display triangles for triangle in triangles: patch = PolygonPatch(triangle, alpha=0.5, zorder=2) ax.add_patch(patch) # Display polygon # patch = PolygonPatch(polygon, alpha=0.5, zorder=2) # ax.add_patch(patch) # Create and display point point1 = Point(2.5, 3) ax.scatter(point1.x, point1.y) point2 = Point(1, 1)
plotGeometry(shape, np.random.rand(3, 1)) plt.show() # --- part 2 --- from shapely.ops import triangulate import shapely.wkt import numpy as np import matplotlib.pyplot as plt from descartes.patch import PolygonPatch data = shapely.wkt.loads( "POLYGON((-5 -5, -5 5, 5 5, 5 -5, -5 -5)," "(1 -1, 4 -1, 4 1, 1 1, 1 4, -1 4, -1 1, -4 1, -4 -1, -1 -1, -1 -4, 1 -4, 1 -1))") triangles = triangulate(data) filtered = [] for tr in triangles: if data.contains(tr): filtered.append(tr) for tr in filtered: patch = PolygonPatch(tr, fc=(0.9, 0.9, 1.0), ec=(0, 0, 0), lw=1, alpha=0.8, zorder=4) plt.axes().add_patch(patch) plt.axis("equal") plotPolygonFilled(data, (0, 0, 0)) plt.plot() plt.show()
def get_footprint_polygon(self, z_limits=None, use_global_frame=False, origin=None, plane_normal=[0, 0, 1], transform=None, offset=[0, 0, 0], use_bounding_box=False): assert len( plane_normal) == 3, 'Plane normal vector' \ ' must have three components' assert np.sum( plane_normal) == 1, 'Plane normal vector must be a unit vector' assert len(offset) == 3, 'Offset vector must have three components' if origin is not None: assert len(origin) == 3, 'Origin vector must have three components' if transform is not None: assert transform.shape == ( 4, 4), 'The transform matrix must be (4, 4)' if not self.load_mesh(): PCG_ROOT_LOGGER.error( 'Cannot calculate footprint, filename={}'.format( self.filename)) return None footprint = None for m in self.get_meshes(): mesh = m.copy() if transform is not None: # Apply transformation matrix to mesh before sectioning it mesh.apply_transform(transform) if offset is not None: mesh.apply_translation(offset) step = 0.01 if z_limits is None: PCG_ROOT_LOGGER.info('Section mesh along the Z limit={},' ' filename={}'.format( mesh.bounds[:, 2].flatten(), self.filename)) z_limits = mesh.bounds[:, 2].flatten() if (z_limits[1] - z_limits[0]) < step: step = (z_limits[1] - z_limits[0]) / 10 z_levels = np.arange(0, z_limits[1] - z_limits[0] + step, step) if origin is None: origin = deepcopy(mesh.bounds[0, :]) else: if z_limits[0] >= mesh.bounds[1, 2]: PCG_ROOT_LOGGER.warning( 'Lower Z limit provided is outside of mesh range,' ' no footprint for this range, min_z_limit={},' ' max_z_bound={}'.format(z_limits[0], mesh.bounds[1, 2])) return None if z_limits[1] <= mesh.bounds[0, 2]: PCG_ROOT_LOGGER.warning( 'Upper Z limit provided is outside of mesh range,' ' no footprint for this range, max_z_limit={},' ' min_z_bound={}'.format(z_limits[1], mesh.bounds[0, 2])) return None z_limits[0] = max(z_limits[0], mesh.bounds[0, 2]) z_limits[1] = min(z_limits[1], mesh.bounds[1, 2]) if np.abs(z_limits[1] - z_limits[0]) < 10 * step: step = np.abs(z_limits[1] - z_limits[0]) / 10 z_levels = np.arange(0, z_limits[1] - z_limits[0] + step, step) if origin is None: origin = deepcopy(mesh.bounds[0, :]) origin[2] = z_limits[0] PCG_ROOT_LOGGER.info('Sections will be acquired in the' ' following Z heights={}'.format(z_levels)) polys = list() # List of lines for the rest of the forms found in the sections # that do not form a closed polygon lines = list() # Since trimesh computes the Path2D objects for the section # contours in a different coordinate system to the mesh # itself, store the lower bound to correct the position later fp_offset = [mesh.bounds[0, 0], mesh.bounds[0, 1]] if mesh.is_empty: PCG_ROOT_LOGGER.warning( 'Mesh is empty after slicing in interval={}'.format( z_limits)) return None if use_bounding_box: mesh = mesh.bounding_box_oriented try: closed_polys, combined_section = self._get_combined_sections( mesh, origin, plane_normal, z_levels) if None in [closed_polys, combined_section]: PCG_ROOT_LOGGER.warning( 'No slices found for mesh provided limits,' ' z_limits={}, filename={}'.format( z_limits, self._filename)) return None except ValueError as ex: PCG_ROOT_LOGGER.warning( 'Mesh sectioning failed, using the vertices' ' bounding box instead, filename={}, message={}'.format( self.filename, str(ex))) vertices = np.unique(mesh.vertices, axis=0) return MultiPoint([(vertices[i, 0], vertices[i, 1]) for i in range(vertices.shape[0]) ]).convex_hull # combined_section.show() # Retrieve all vertices, Path2D provides the index for the point vertices = combined_section.vertices # Get all remaining lines that are not included in any of the # polygons for trimesh_line in combined_section.entities: if trimesh_line.closed: continue line = translate(LineString(vertices[trimesh_line.points]), fp_offset[0], fp_offset[1]) has_similar_line = False for cur_line in lines: if cur_line.almost_equals(line, decimal=3): has_similar_line = True break if not has_similar_line: lines.append(line) if footprint is None: footprint = deepcopy(closed_polys) else: footprint = unary_union([footprint] + closed_polys) PCG_ROOT_LOGGER.info('Closed polys found in the sections,' ' area={}, filename={}'.format( footprint.area, self.filename)) # Create list of open polygons to be processed open_polys = list() if len(lines) > 0: PCG_ROOT_LOGGER.info( 'Processing remaining section lines into closed' ' polygons, filename={}'.format(self.filename)) def has_intersection(lines): for i in range(len(lines)): for j in range(len(lines)): if i == j: continue line_i = lines[i] line_j = lines[j] if line_i.intersects(line_j): return i, j return None while has_intersection(lines) is not None: i, j = has_intersection(lines) line_i = lines[i] line_j = lines[j] if line_i.almost_equals(line_j, decimal=3): new_line = line_i else: new_line = unary_union([line_i, line_j]) lines.remove(line_i) lines.remove(line_j) lines.append(new_line) for line in lines: if isinstance(line, LineString) or line.is_empty: continue polys = list() try: polys = polys + list(polygonize(line)) except ValueError as ex: PCG_ROOT_LOGGER.error( 'Could not polygonize lines, message={},' ' filename={}'.format(ex, self.filename)) try: # Use Delaunay triangulation on the remaining # intersecting lines polys = polys + \ triangulate(MultiPoint( self._multiline2points(line))) except ValueError as ex: PCG_ROOT_LOGGER.error( 'Could not triangulate lines, message={},' ' filename={}'.format(ex, self.filename)) if len(polys) == 0: PCG_ROOT_LOGGER.error( 'Polygon list is empty, using convex' ' hull of all lines,' ' filename={}'.format(self.filename)) polys = [line.convex_hull] for poly in polys: if poly.is_empty or poly.area <= 1e-4 or \ not poly.is_valid or \ (not isinstance(poly, Polygon) and not isinstance(poly, MultiPolygon)): continue # Calculate the difference between the closed # polygons and the new triangle to avoid the # polygon's interior try: poly = poly.difference(closed_polys) except BaseException: continue if poly.is_empty or poly.area <= 1e-4 or \ not poly.is_valid or \ (not isinstance(poly, Polygon) and not isinstance(poly, MultiPolygon)): continue # Use ray tracing to see if the polygon's # centroid crosses the mesh at some point ray_origins = np.array([[ poly.centroid.x, poly.centroid.y, mesh.bounds[0, 2] ]]) ray_directions = np.array([[0, 0, 1]]) locations, index_ray, index_tri = \ mesh.ray.intersects_location( ray_origins=ray_origins, ray_directions=ray_directions) if len(locations) > 0: open_polys.append(poly.buffer(0.001)) footprint = unary_union([footprint] + open_polys) # Dilate and erode the polygon to get rid of small gaps footprint = footprint.buffer(0.005).buffer(-0.005) PCG_ROOT_LOGGER.info('Removing internal polygons from ' 'footprint, filename={}'.format( self.filename)) # Remove interior polygons if isinstance(footprint, Polygon): for interior_poly in footprint.interiors: interior_poly = Polygon(interior_poly) footprint = footprint.union(interior_poly) elif isinstance(footprint, MultiPolygon): for geo in footprint.geoms: for interior_poly in geo.interiors: interior_poly = Polygon(interior_poly) geo = geo.union(interior_poly) PCG_ROOT_LOGGER.info( 'Footprint final area, area={}, filename={}'.format( footprint.area, self.filename)) return footprint
from shapely.geometry import MultiPoint from shapely.ops import triangulate from matplotlib import pyplot from descartes.patch import PolygonPatch from figures import SIZE, BLUE, GRAY points = MultiPoint([(0, 0), (1, 1), (0, 2), (2, 2), (3, 1), (1, 0)]) triangles = triangulate(points) fig = pyplot.figure(1, figsize=SIZE, dpi=90) fig.set_frameon(True) ax = fig.add_subplot(111) for triangle in triangles: patch = PolygonPatch(triangle, facecolor=BLUE, edgecolor=BLUE, alpha=0.5, zorder=2) ax.add_patch(patch) for point in points: pyplot.plot(point.x, point.y, 'o', color=GRAY) pyplot.xlim(-0.5, 3.5) pyplot.ylim(-0.5, 2.5) pyplot.show()
def test_lines(self): polys = triangulate(self.p, edges=True) self.assertEqual(len(polys), 5) for p in polys: self.assertTrue(isinstance(p, LineString))
def test_point(self): p = Point(1,1) polys = triangulate(p) self.assertEqual(len(polys), 0)
def test_polys(self): polys = triangulate(self.p) self.assertEqual(len(polys), 2) for p in polys: self.assertTrue(isinstance(p, Polygon))
def main(): # Command Line Arguments parser = argparse.ArgumentParser() parser.add_argument("-i", "--input", const=str, nargs="?") parser.add_argument("-a", "--algorithm", nargs="+") args = parser.parse_args() log.info("Loading Data") log.debug("Arguments") log.debug(args) configData = core.getConfig() globaldata = core.getKeyVal("globaldata") hashtable = {} if globaldata == None: file1 = open(args.input or "preprocessorfile.txt", "r") data = file1.read() globaldata = ["start"] splitdata = data.split("\n") splitdata = splitdata[:-1] log.info("Processed Pre-Processor File") log.info("Converting to readable format") for _, itm in enumerate(tqdm(splitdata)): itm = itm.split(" ") itm.pop(-1) entry = itm hashtable["{},{}".format(entry[1], entry[2])] = int(entry[0]) globaldata.append(entry) else: globaldata.insert(0,"start") hashtable = core.generateHashtable(globaldata) # globaldata = core.cleanNeighbours(globaldata) wallpts = core.getWallPointArray(globaldata) algo1,algo2,algo3 = True,True,True if len(args.algorithm) == 3: algo = list(map(core.ConvertStringToBool,args.algorithm)) algo1 = algo[0] algo2 = algo[1] algo3 = algo[2] log.info("Generating Wall Polygons for Aerochecks") wallpts = core.generateWallPolygons(wallpts) log.info("Detected " + str(len(wallpts)) + " geometry(s).") log.info("Wall Polygon Generation Complete") log.info("Deleting Unneeded Wall Points (Except Left and Right Points)") globaldata = core.cleanWallPoints(globaldata) badPoints = [] with np.errstate(divide='ignore', invalid='ignore'): if algo1 == True: log.info("Triangulating") interiorpts = [] interiorpts.extend(range(1, len(globaldata))) interiorpts = core.convertPointToShapelyPoint(core.convertIndexToPoints(interiorpts,globaldata)) interiorpts = MultiPoint(interiorpts) interiortriangles = triangulate(interiorpts) log.info("Generated " + str(len(interiortriangles)) + " triangle(s).") polydata = balance.getPolygon(interiortriangles) log.info("Running Connectivity Check") globaldata,badPoints = core.connectivityCheck(globaldata, badPoints, configData, quick=True) log.info("Connectivity Check Done") log.info("Running Triangulation Balancing using Nischay's Triangle Neighbours") globaldata = balance.triangleBalance(globaldata, polydata, wallpts, configData, badPoints) log.info("Triangle Balancing Done") if algo2 == True: log.info("Running Connectivity Check") globaldata,badPoints = core.connectivityCheck(globaldata, badPoints, configData, quick=True) log.info("Connectivity Recheck Done") log.info("Running Triangulation Balancing using Kumar's Neighbours (Left and Right Mode)") globaldata = balance.triangleBalance2(globaldata, wallpts, configData, badPoints, hashtable) if algo3 == True: log.info("Running Connectivity Check") globaldata,badPoints = core.connectivityCheck(globaldata, badPoints, configData, quick=True) log.info("Running Triangulation Balancing using Kumar's Neighbours (General)") globaldata = balance.triangleBalance3(globaldata, wallpts, configData, badPoints, hashtable) log.info("Running Connectivity Recheck") globaldata,badPoints = core.connectivityCheck(globaldata, badPoints, configData, quick=True) log.warning("Total Number of Points unable to be fixed: {}".format(len(badPoints))) # log.info("Writing Deletion Points") # problempts = findDeletionPoints(globaldata) # globaldata = core.cleanNeighbours(globaldata) # core.writeConditionValuesForWall(globaldata, configData) globaldata.pop(0) core.setKeyVal("globaldata",globaldata) # with open("removal_points.txt", "w") as text_file: # for item1 in problempts: # text_file.writelines(["%s " % item1]) # text_file.writelines("\n") log.info("Writing Preprocessor File") with open("preprocessorfile_triangulate.txt", "w") as text_file: for item1 in globaldata: text_file.writelines(["%s " % item for item in item1]) text_file.writelines("\n") log.info("Done")
def _triangulate(polygon): return [ tri_face for tri_face in triangulate(polygon) if tri_face.centroid.within(polygon) ]
def forward(self, data): points = self.rescale_points(data["points"], data["image"].shape[1::-1]) if not isinstance(points, MultiPoint): points = MultiPoint(points) triangles = triangulate(points) return {"polygons": triangles}