Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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)
    ]
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
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]
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
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]
Ejemplo n.º 8
0
    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])
Ejemplo n.º 9
0
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)
Ejemplo n.º 10
0
    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)
Ejemplo n.º 11
0
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)
Ejemplo n.º 12
0
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
Ejemplo n.º 13
0
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)
Ejemplo n.º 14
0
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
Ejemplo n.º 15
0
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
Ejemplo n.º 16
0
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
Ejemplo n.º 17
0
    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)
Ejemplo n.º 19
0
    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
Ejemplo n.º 21
0
    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
Ejemplo n.º 22
0
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)
Ejemplo n.º 24
0
 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))
Ejemplo n.º 25
0
            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)
Ejemplo n.º 26
0
  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()
Ejemplo n.º 27
0
    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
Ejemplo n.º 28
0
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()
Ejemplo n.º 29
0
 def test_lines(self):
     polys = triangulate(self.p, edges=True)
     self.assertEqual(len(polys), 5)
     for p in polys:
         self.assertTrue(isinstance(p, LineString))
Ejemplo n.º 30
0
 def test_point(self):
     p = Point(1,1)
     polys = triangulate(p)
     self.assertEqual(len(polys), 0)
Ejemplo n.º 31
0
 def test_polys(self):
     polys = triangulate(self.p)
     self.assertEqual(len(polys), 2)
     for p in polys:
         self.assertTrue(isinstance(p, Polygon))
Ejemplo n.º 32
0
 def test_point(self):
     p = Point(1,1)
     polys = triangulate(p)
     self.assertEqual(len(polys), 0)
Ejemplo n.º 33
0
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")
Ejemplo n.º 34
0
 def _triangulate(polygon):
     return [
         tri_face for tri_face in triangulate(polygon)
         if tri_face.centroid.within(polygon)
     ]
Ejemplo n.º 35
0
 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}