Ejemplo n.º 1
0
def offset_bbox_xy(pts, dist):
    bbox = pca_numpy(pts)
    frame1 = Frame(bbox[0], bbox[1][0], bbox[1][1])
    xform = Transformation.from_frame_to_frame(frame1, Frame.worldXY())
    pts = transform_points(pts, xform)
    bbox = bounding_box_xy(pts)
    bbox = offset_polygon(bbox, dist)
    return bbox, xform
def offset_polygon_xy(points, dist, planarize=False):
    if len(points) < 3:
        return None
    frame = Frame.from_plane(
        Plane.from_three_points(points[0], points[1], points[2]))
    xform = Transformation.from_frame_to_frame(frame, Frame.worldXY())
    if planarize:
        points = [point_on_plane(point, frame) for point in points]
    points = transform_points(points, xform)
    points = offset_polygon(points, dist)
    points = transform_points(points, xform.inverse())
    return points
Ejemplo n.º 3
0
def test_offset_polygon(polygon, distance, tol, output_polygon):
    output_polygon = [v for v in output_polygon]
    assert allclose(offset_polygon(polygon, distance, tol), output_polygon)
    frame = Frame(origin, xaxis, yaxis)

    if yaxis[2] > 0:
        offset = scale_vector(zaxis, -0.050)
    else:
        offset = scale_vector(zaxis, +0.050)

    points_xy = [
        frame.represent_point_in_local_coordinates(point) for point in points
    ]
    box_xy = bounding_box_xy(points_xy)
    box = [
        frame.represent_point_in_global_coordinates(corner_xy)[:]
        for corner_xy in box_xy
    ]
    box1 = offset_polygon(box, -0.025)
    box2 = [add_vectors(point, offset) for point in box1]

    POLYGONS.append({'points': box1 + box1[:1], 'color': (0, 0, 0)})

    POLYGONS.append({'points': box2 + box2[:1], 'color': (0, 0, 0)})

    POLYGONS.append({
        'points': [box1[0], box1[3], box2[3], box2[0], box1[0]],
        'color': (0, 0, 0)
    })

    POLYGONS.append({
        'points': [box1[1], box2[1], box2[2], box1[2], box1[1]],
        'color': (0, 0, 0)
    })
Ejemplo n.º 5
0
#     path = os.path.join(DATA, 'FABRIC', 'unrolled', SIDE, "{}.json".format(mesh.attributes['name']))
#     mesh.to_json(path)

# for mesh in NW_unrolled:
#     path = os.path.join(DATA, 'FABRIC', 'unrolled', SIDE, "{}.json".format(mesh.attributes['name']))
#     mesh.to_json(path)

# ==============================================================================
# Visualize
# ==============================================================================

ARTIST = ShellArtist(None)

for mesh in SOUTH_unrolled:
    points = [
        mesh.vertex_coordinates(key)
        for key in mesh.vertices_on_boundary(ordered=True)
    ]
    polygon = offset_polygon(points, SEEM)
    polygons = [{'points': polygon + polygon[:1]}]

    ARTIST.mesh = mesh
    ARTIST.layer = "Unrolled::{}::{}".format(SIDE, mesh.attributes['name'])
    ARTIST.clear_layer()
    ARTIST.draw_faces()
    ARTIST.draw_facelabels(text={
        key: "{}".format(attr['count'])
        for key, attr in mesh.faces(True)
    })
    ARTIST.draw_polygons(polygons)
    fkey = mesh.get_any_face()
    panel = mesh.get_face_attribute(fkey, 'panel')
    strip = mesh.get_face_attribute(fkey, 'strip')
    mesh.attributes['name'] = '{}-{}'.format(panel, strip.zfill(2))

# ==============================================================================
# Visualize
# ==============================================================================

mesh = RING_unrolled[3]

points = [
    mesh.vertex_coordinates(key)
    for key in mesh.vertices_on_boundary(ordered=True)
]
polygons = [{'points': offset_polygon(points, SEEM)}]

fkey = list(mesh.faces_where({'count': 0}))[0]
facecolor = {fkey: COLOR}

PLOTTER = MeshPlotter(mesh, figsize=(10, 7))
PLOTTER.draw_polygons(polygons)
PLOTTER.draw_faces(text={
    fkey: "{}".format(str(attr['count']).zfill(2))
    for fkey, attr in mesh.faces(True)
},
                   facecolor=facecolor)
PLOTTER.draw_edges()
PLOTTER.show()

# ==============================================================================
# make a block for every face
# leave a 3cm gap between adjacent blocks
blocks = []
for fkey in edos.faces():
    vertices = edos.face_vertices(fkey)

    if len(vertices) != 4:
        continue

    # normals of the cablenet
    # coordinates of the extrados
    normals = [mesh.vertex_normal(key) for key in vertices]
    points = [edos.vertex_coordinates(key) for key in vertices]

    # bottom face coordinates offset from vertex coordinates
    bottom = offset_polygon(points, 0.015)

    top = []
    for point, normal in zip(bottom, normals):
        x = point[0] + 0.1 * normal[0]
        y = point[1] + 0.1 * normal[1]
        z = point[2] + 0.1 * normal[2]
        top.append([x, y, z])

    # vertices and faces of the block
    vertices = bottom[::-1] + top
    faces = [[0, 1, 2, 3], [4, 5, 6, 7], [4, 3, 2, 5], [5, 2, 1, 6],
             [6, 1, 0, 7], [7, 0, 3, 4]]

    block = Mesh.from_vertices_and_faces(vertices, faces)
    block.name = "Block.{}".format(fkey)
        # # Transform the local coordinates to world coordinates to make it an axis-aligned
        # # problem.
        # # ==============================================================================

        X = Transformation.from_frame_to_frame(frame, Frame.worldXY())
        points = transform_points(points, X)

        # # ==============================================================================
        # # Compute the axis aligned bounding box in world coordinates, ignoring the Z
        # # components of the points. Add some padding to the bounding box to avoid having
        # # vertices on the boundaries of the box. Convert the box back to the local
        # # coordinate system.
        # # ==============================================================================

        front = bounding_box_xy(points)
        front = offset_polygon(front, -PADDING)
        front = transform_points(front, X.inverse())

        # # ==============================================================================
        # # Check if boundary normal and local normal have the same direction, if not reverse
        # # list of vertices. Create a 3D box by moving the vertices of the found 2D bounding
        # # box along the z-axis of the boundary coordinate system.
        # # ==============================================================================

        back = []
        angle = angles_vectors(frame.zaxis, frame_0.zaxis, deg=False)

        if angle[0] != 0:
            front.reverse()

        for v in front:
Ejemplo n.º 9
0
def test_offset_colinear_polygon(polygon, distance, tol, output_polygon):
    output_polygon = [pytest.approx(v) for v in output_polygon]
    assert offset_polygon(polygon, distance, tol) == output_polygon
# # ==============================================================================
# # Generate the formwork blocks.
# # ==============================================================================

blocks = []

for fkey in cablenet.faces():
    
    vertices = cablenet.face_vertices(fkey)
    points = cablenet.get_vertices_attributes('xyz', keys=vertices)

    # the edges of the bottom face polygon have to be offset to create space
    # for the ribs.

    bottom = offset_polygon(points, OFFSET)

    # the vertices of the top face are the intersection points of the face normal
    # placed at each (offset) bottom vertex and a plane perpendicular to the 
    # face normal placed at a distance THICKNESS along the face normal from the
    # face centroid.

    # define the plane
    origin = cablenet.face_centroid(fkey)
    normal = cablenet.face_normal(fkey, unitized=True)

    plane = add_vectors(origin, scale_vector(normal, THICKNESS)), normal

    top = []
    for a in bottom:
        b = add_vectors(a, normal)
Ejemplo n.º 11
0
def mesh_subdivide_frames(mesh, offset, add_windows=False):
    """Subdivide a mesh by creating offset frames and windows on its faces.

    Parameters
    ----------
    mesh : :class:`compas.datastructures.Mesh`
        The mesh object to be subdivided.
    offset : float | dict[int, float]
        The offset distance to create the frames.
        A single value will result in a constant offset everywhere.
        A dictionary mapping faces to offset values will be processed accordingly.
    add_windows : bool, optional
        If True, add a window face in the frame opening.

    Returns
    -------
    :class:`compas.datastructures.Mesh`
        A new subdivided mesh.

    """
    cls = type(mesh)
    SubdMesh = subd_factory(cls)

    subd = SubdMesh()

    # 0. pre-compute offset distances
    if not isinstance(offset, dict):
        distances = iterable_like(mesh.faces(), [offset], offset)
        offset = {fkey: od for fkey, od in zip(mesh.faces(), distances)}

    # 1. add vertices
    newkeys = {}
    for vkey, attr in mesh.vertices(True):
        newkeys[vkey] = subd.add_vertex(*mesh.vertex_coordinates(vkey))

    # 2. add faces
    for fkey in mesh.faces():
        face = [newkeys[vkey] for vkey in mesh.face_vertices(fkey)]
        d = offset.get(fkey)

        # 2a. add face and break if no offset is found
        if d is None:
            subd.add_face(face)
            continue

        polygon = offset_polygon(mesh.face_coordinates(fkey), d)

        # 2a. add offset vertices
        window = []
        for xyz in polygon:
            x, y, z = xyz
            new_vkey = subd.add_vertex(x=x, y=y, z=z)
            window.append(new_vkey)

        # 2b. frame faces
        face = face + face[:1]
        window = window + window[:1]
        for sa, sb in zip(pairwise(face), pairwise(window)):
            subd.add_face([sa[0], sa[1], sb[1], sb[0]])

        # 2c. window face
        if add_windows:
            subd.add_face(window)

    return cls.from_data(subd.data)
for fkey in cablenet.faces():

    #fkey = cablenet.get_any_face()

    vertices = cablenet.face_vertices(fkey)
    points = cablenet.get_vertices_attributes('xyz', keys=vertices)
    normals = [cablenet.vertex_normal(key) for key in vertices]

    bottom = points[:]
    top = []
    for point, normal in zip(points, normals):
        xyz = add_vectors(point, scale_vector(normal, OFFSET))
        top.append(xyz)

    bottom = offset_polygon(bottom, 0.01)
    top = offset_polygon(top, 0.05)

    vertices = bottom + top
    faces = [[0, 3, 2, 1], [4, 5, 6, 7], [3, 0, 4, 7], [0, 1, 5, 4],
             [1, 2, 6, 5], [1, 2, 6, 5], [2, 3, 7, 6]]

    block = Mesh.from_vertices_and_faces(vertices, faces)
    blocks.append(block)

# ==============================================================================
# Visualize
# ==============================================================================

flag = False
for i in blocks:
Ejemplo n.º 13
0
def generate_raft(slicer,
                  raft_offset=10,
                  distance_between_paths=10,
                  direction="xy_diagonal",
                  raft_layers=1,
                  raft_layer_height=None):
    """Creates a raft.

    Parameters
    ----------
    slicer: :class:`compas_slicer.slicers.BaseSlicer`
        An instance of one of the compas_slicer.slicers.BaseSlicer classes.
    raft_offset: float
        Distance (in mm) that the raft should be offsetted from the first layer. Defaults to 10mm
    distance_between_paths: float
        Distance (in mm) between the printed lines of the raft. Defaults to 10mm
    direction: str
        x_axis: Create a raft aligned with the x_axis
        y_axis: Create a raft aligned with the y_axis
        xy_diagonal: Create a raft int the diagonal direction in the xy_plane
    raft_layers: int
        Number of raft layers to add. Defaults to 1
    raft_layer_height: float
        Layer height of the raft layers. Defaults to same value as used in the slicer.
    """

    # check if a raft_layer_height is specified, if not, use the slicer.layer_height value
    if not raft_layer_height:
        raft_layer_height = slicer.layer_height

    logger.info("Generating raft")

    # find if slicer has vertical or horizontal layers, and select which paths are to be offset.
    if isinstance(slicer.layers[0], compas_slicer.geometry.VerticalLayer):  # Vertical layers
        # then find all paths that lie on the print platform and make them brim.
        paths_to_offset, _ = slicer.find_vertical_layers_with_first_path_on_base()

    else:  # Horizontal layers
        # then replace the first layer with a raft layer.
        paths_to_offset = slicer.layers[0].paths

    # get flat lists of points in bottom layer
    all_pts = []
    for path in paths_to_offset:
        for pt in path.points:
            all_pts.append(pt)

    # get xy bounding box of bottom layer and create offset
    bb_xy = bounding_box_xy(all_pts)
    bb_xy_offset = offset_polygon(bb_xy, -raft_offset)
    # bring points in the xy_offset to the correct height
    for pt in bb_xy_offset:
        pt[2] = slicer.layers[0].paths[0].points[0][2]

    # calculate x range, y range, and number of steps
    x_range = abs(bb_xy_offset[0][0] - bb_xy_offset[1][0])
    y_range = abs(bb_xy_offset[0][1] - bb_xy_offset[3][1])

    # get maximum values of the bounding box
    bb_max_x_right = bb_xy_offset[1][0]
    bb_max_y_top = bb_xy_offset[3][1]

    # get point in bottom left corner as raft start point
    raft_start_pt = Point(bb_xy_offset[0][0], bb_xy_offset[0][1], bb_xy_offset[0][2])

    # create starting line for diagonal direction
    if direction == "xy_diagonal":
        c = math.sqrt(2*(distance_between_paths**2))

        pt1 = Point(raft_start_pt[0] + c, raft_start_pt[1], raft_start_pt[2])
        pt2 = Point(pt1[0] - y_range, pt1[1] + y_range, pt1[2])
        line = Line(pt1, pt2)

    # move all points in the slicer up so that raft layers can be inserted
    for i, layer in enumerate(slicer.layers):
        for j, path in enumerate(layer.paths):
            for k, pt in enumerate(path.points):
                slicer.layers[i].paths[j].points[k] = Point(pt[0], pt[1], pt[2] + (raft_layers)*raft_layer_height)

    for i in range(raft_layers):

        iter = 0
        raft_points = []

        # create raft points depending on the chosen direction
        while iter < 9999:  # to avoid infinite while loop in case something is not correct
            # ===============
            # VERTICAL RAFT
            # ===============
            if direction == "y_axis":
                raft_pt1 = Point(raft_start_pt[0] + iter*distance_between_paths, raft_start_pt[1], raft_start_pt[2] + i*raft_layer_height)
                raft_pt2 = Point(raft_start_pt[0] + iter*distance_between_paths, raft_start_pt[1] + y_range, raft_start_pt[2] + i*raft_layer_height)

                if raft_pt2[0] > bb_max_x_right or raft_pt1[0] > bb_max_x_right:
                    break

            # ===============
            # HORIZONTAL RAFT
            # ===============
            elif direction == "x_axis":
                raft_pt1 = Point(raft_start_pt[0], raft_start_pt[1] + iter*distance_between_paths, raft_start_pt[2] + i*raft_layer_height)
                raft_pt2 = Point(raft_start_pt[0] + x_range, raft_start_pt[1] + iter*distance_between_paths, raft_start_pt[2] + i*raft_layer_height)

                if raft_pt2[1] > bb_max_y_top or raft_pt1[1] > bb_max_y_top:
                    break

            # ===============
            # DIAGONAL RAFT
            # ===============
            elif direction == "xy_diagonal":
                # create offset of the initial diagonal line
                offset_l = offset_line(line, iter*distance_between_paths, Vector(0, 0, -1))

                # get intersections for the initial diagonal line with the left and bottom of the bb
                int_left = intersection_line_line(offset_l, [bb_xy_offset[0], bb_xy_offset[3]])
                int_bottom = intersection_line_line(offset_l, [bb_xy_offset[0], bb_xy_offset[1]])

                # get the points at the intersections
                raft_pt1 = Point(int_left[0][0], int_left[0][1], int_left[0][2] + i*raft_layer_height)
                raft_pt2 = Point(int_bottom[0][0], int_bottom[0][1], int_bottom[0][2] + i*raft_layer_height)

                # if the intersection goes beyond the height of the left side of the bounding box:
                if int_left[0][1] > bb_max_y_top:
                    # create intersection with the top side
                    int_top = intersection_line_line(offset_l, [bb_xy_offset[3], bb_xy_offset[2]])
                    raft_pt1 = Point(int_top[0][0], int_top[0][1], int_top[0][2] + i*raft_layer_height)

                    # if intersection goes beyond the length of the top side, break
                    if raft_pt1[0] > bb_max_x_right:
                        break

                # if the intersection goes beyond the length of the bottom side of the bounding box:
                if int_bottom[0][0] > bb_max_x_right:
                    # create intersection with the right side
                    int_right = intersection_line_line(offset_l, [bb_xy_offset[1], bb_xy_offset[2]])
                    raft_pt2 = Point(int_right[0][0], int_right[0][1], int_right[0][2] + i*raft_layer_height)

                    # if intersection goes beyond the height of the right side, break
                    if raft_pt2[1] > bb_xy_offset[2][1]:
                        break

            # append to list alternating
            if iter % 2 == 0:
                raft_points.extend((raft_pt1, raft_pt2))
            else:
                raft_points.extend((raft_pt2, raft_pt1))

            iter += 1

        # create raft layer
        raft_layer = Layer([Path(raft_points, is_closed=False)])
        raft_layer.is_raft = True
        # insert raft layer in the correct position into the slicer
        slicer.layers.insert(i, raft_layer)
Ejemplo n.º 14
0
# Make block
# ==============================================================================
blocks = []


all_vertices = []
all_faces = []


for fkey in cablenet.faces():
#fkey = cablenet.get_any_face()
    vertices = cablenet.face_vertices(fkey)
    points = cablenet.get_vertices_attributes("xyz", keys=vertices)
    
    polygon = cg. Polygon(points)
    offset_polygon = cg.offset_polygon(points, OFFSET)
    
    normals= [cablenet.vertex_normal(key) for key in vertices]
    
    bottom = offset_polygon[:]
    top = []
    for point, normal in zip(offset_polygon, normals):
        xyz = add_vectors(point, scale_vector(normal, OFFSET))
        top.append(xyz)
    vertices= bottom+top
    faces = [[0, 3, 2, 1], [4, 5, 6, 7], [4, 0, 1, 5], [2, 6, 5, 1], [6, 2, 3, 7], [0, 4, 7, 3]]
    block = Mesh.from_vertices_and_faces(vertices, faces)
    blocks.append(block)
    
    
    all_vertices.extend(vertices)
Ejemplo n.º 15
0
def test_offset_colinear_polygon(polygon, distance, tol, output_polygon):
    assert allclose(offset_polygon(polygon, distance, tol), output_polygon)
Ejemplo n.º 16
0
# Transform the local coordinates to world coordinates to make it an axis-aligned
# problem.
# ==============================================================================

X = Transformation.from_frame_to_frame(frame1, Frame.worldXY())
points = transform_points(points, X)

# ==============================================================================
# Compute the axis aligned bounding box in world coordinates, ignoring the Z
# components of the points. Add some padding to the bounding box to avoid having
# vertices on the boundaries of the box. Convert the box back to the local
# coordinate system.
# ==============================================================================

bbox = bounding_box_xy(points)
bbox = offset_polygon(bbox, -PADDING)
bbox = transform_points(bbox, X.inverse())

# ==============================================================================
# Convert the box to a mesh for visualisation.
# ==============================================================================

bbox = Mesh.from_vertices_and_faces(bbox, [[0, 1, 2, 3]])

# ==============================================================================
# Use a frame artist to visualize the boundary frame.
# ==============================================================================

artist = FrameArtist(frame, layer="SOUTH::Frame", scale=0.3)
artist.clear_layer()
artist.draw()
Ejemplo n.º 17
0
def mesh_subdivide_frames(mesh, offset, add_windows=False):
    """Subdivide a mesh by creating offset frames and windows on its faces.

    Parameters
    ----------
    mesh : Mesh
        The mesh object to be subdivided.
    offset : float or dict
        The offset distance to create the frames.
        A single value will result in a constant offset everywhere.
        A dictionary mapping facekey: offset will be processed accordingly.
    add_windows : boolean
        Optional. Flag to add window face. Default is ``False``.

    Returns
    -------
    Mesh
        A new subdivided mesh.

    Examples
    --------
    >>>

    """

    subd = SubdMesh()

    # 0. pre-compute offset distances
    if not isinstance(offset, dict):
        distances = iterable_like(mesh.faces(), [offset], offset)
        offset = {fkey: od for fkey, od in zip(mesh.faces(), distances)}

    # 1. add vertices
    newkeys = {}
    for vkey, attr in mesh.vertices(True):
        newkeys[vkey] = subd.add_vertex(*mesh.vertex_coordinates(vkey))

    # 2. add faces
    for fkey in mesh.faces():
        face = [newkeys[vkey] for vkey in mesh.face_vertices(fkey)]
        d = offset.get(fkey)

        # 2a. add face and break if no offset is found
        if d is None:
            subd.add_face(face)
            continue

        polygon = offset_polygon(mesh.face_coordinates(fkey), d)

        # 2a. add offset vertices
        window = []
        for xyz in polygon:
            x, y, z = xyz
            new_vkey = subd.add_vertex(x=x, y=y, z=z)
            window.append(new_vkey)

        # 2b. frame faces
        face = face + face[:1]
        window = window + window[:1]
        for sa, sb in zip(pairwise(face), pairwise(window)):
            subd.add_face([sa[0], sa[1], sb[1], sb[0]])

        # 2c. window face
        if add_windows:
            subd.add_face(window)

    return subd
Ejemplo n.º 18
0
def GetBoundingBox(pca_numpy, intersections, PADDING, start, end, frame):

    points = intersections[start:end]
    width = 0.1

    bbox = []

    if ((end - start == 2)):

        #print("2Points")

        vector = subtract_vectors(points[0], points[1])
        vector90 = cross_vectors(frame.zaxis, vector)

        X0 = Translation(
            scale_vector([vector90[0], vector90[1], vector90[2]], width))
        X1 = Translation(
            scale_vector([vector90[0], vector90[1], vector90[2]], -width))

        pointsMoved0 = [points[0], points[1]]
        pointsMoved0 = transform_points(pointsMoved0, X0)
        pointsMoved1 = [points[0], points[1]]
        pointsMoved1 = transform_points(pointsMoved1, X1)

        bbox = [
            pointsMoved0[0], pointsMoved0[1], pointsMoved1[1], pointsMoved1[0]
        ]

        poly = Polygon(bbox)
        #print(poly)
        offset = offset_polygon(poly.points, -PADDING)
        X = Translation((0, 0, 0))

        bbox_ = transform_points(offset, X)
        # bbox = bbox_
        #print(bbox)
        #print(bbox_)

        frame_1 = Frame(points[0], vector, vector90)
        vectorLen = length_vector(vector)
        vectorSmall = subtract_vectors(bbox[1], bbox[2])
        vectorLenSmall = length_vector(vectorSmall)

    else:

        #print("N+2Points")

        origin, axes, values = pca_numpy([list(point) for point in points])
        frame_1 = Frame(origin, axes[0], axes[1])

        X = Transformation.from_frame_to_frame(frame_1, Frame.worldXY())

        points2 = transform_points(points, X)
        bbox = bounding_box_xy(points2)
        bbox = offset_polygon(bbox, -PADDING)
        bbox = transform_points(bbox, X.inverse())

        vector = subtract_vectors(bbox[0], bbox[1])
        vectorLen = length_vector(vector)
        vectorSmall = subtract_vectors(bbox[1], bbox[2])
        vectorLenSmall = length_vector(vectorSmall)

    #Unify box
    pt0 = Point(bbox[0][0], bbox[0][1], bbox[0][2])
    pt1 = Point(bbox[1][0], bbox[1][1], bbox[1][2])
    pt2 = Point(bbox[2][0], bbox[2][1], bbox[2][2])
    pt3 = Point(bbox[3][0], bbox[3][1], bbox[3][2])

    pt03 = Point((bbox[0][0] + bbox[3][0]) * 0.5,
                 (bbox[0][1] + bbox[3][1]) * 0.5,
                 (bbox[0][2] + bbox[3][2]) * 0.5)
    pt12 = Point((bbox[1][0] + bbox[2][0]) * 0.5,
                 (bbox[1][1] + bbox[2][1]) * 0.5,
                 (bbox[1][2] + bbox[2][2]) * 0.5)

    vectorSmall = normalize_vector(vectorSmall)

    X0 = Translation(scale_vector(vectorSmall, width * 0.5))
    X1 = Translation(scale_vector(vectorSmall, -width * 0.5))

    pt01 = transform_points([pt03, pt12], X0)
    pt23 = transform_points([pt03, pt12], X1)
    bbox[0] = pt01[0]
    bbox[1] = pt01[1]
    bbox[2] = pt23[1]
    bbox[3] = pt23[0]

    bbox = Mesh.from_vertices_and_faces(bbox, [[0, 1, 2, 3]])

    return [frame_1, bbox, vectorLen, vectorLenSmall]