示例#1
0
def _filter_groups_from_poly_node(tree, groups, is_outer_perimeter=None):
    """ Recursively parses clippers <PyPolyTree> for island contours
    Fills #islands parameter with collections of paths that represent islands.
    Path element is <Point>

    if is_outer_perimeter is None -> we don't know what is it
    The first child that has non-empty .contour is considered as outer perimeter

    """
    if is_outer_perimeter is None:
        is_outer_perimeter = True if tree.Contour else False

    if is_outer_perimeter:
        """
        Structure of the tree:


            [Island root].contour = outer perimeter
                `-> [Island child].contour = inner perimeter
                    `-> [Island root] ...
                `-> [Island child].contour = inner perimeter

        """

        paths = [to_ndarray(tree.Contour)]
        groups.append(paths)
        for child in tree.Childs:
            paths.append(to_ndarray(child.Contour))
            _filter_groups_from_poly_node(child, groups, False)
    else:
        for child in tree.Childs:
            _filter_groups_from_poly_node(child, groups, True)
示例#2
0
    def import_contents(self, progress):

        progress.set_size(self.vertex_nr)

        normal_kw = 'facet normal'
        vertex_kw = 'vertex'
        end_facet_kw = 'endfacet'
        for line_number, line in enumerate(self.contents.splitlines()):
            if normal_kw in line:
                normal = to_ndarray([
                    DEFAULT_COORDINATE_TYPE(x)
                    for x in line.strip().split()[-3:]
                ])
                if np.array_equal(normal, NULL_VECTOR):
                    raise ValueError("missing normal in line " +
                                     str(line_number))
            if vertex_kw in line:
                # parse vector coordinates
                vector = to_ndarray(
                    [float(x) for x in line.strip().split()[-3:]])
                self.merger.add(vector)

                progress.inc()
            if end_facet_kw in line:
                self.merger.set_last_face_normal(normal)

        self.merger.finalize()

        progress.done()

        return self.tm
示例#3
0
    def import_contents(self, progress):

        progress.set_size(self.vertex_nr)

        normal_kw = 'facet normal'
        vertex_kw = 'vertex'
        end_facet_kw = 'endfacet'
        for line_number, line in enumerate(self.contents.splitlines()):
            if normal_kw in line:
                normal = to_ndarray([DEFAULT_COORDINATE_TYPE(x) for x in line.strip().split()[-3:]])
                if np.array_equal(normal, NULL_VECTOR):
                    raise ValueError("missing normal in line "+str(line_number))
            if vertex_kw in line:
                # parse vector coordinates
                vector = to_ndarray([float(x) for x in line.strip().split()[-3:]])
                self.merger.add(vector)

                progress.inc()
            if end_facet_kw in line:
                self.merger.set_last_face_normal(normal)

        self.merger.finalize()

        progress.done()

        return self.tm
示例#4
0
    def __init__(self, cell_size, dim=3):
        super(MergingSpatialHash, self).__init__(cell_size)
        self.dim = dim
        self.cell_radius = cell_size / 2

        # moves to all neighbor cells
        self._moves = to_ndarray(list(product([0, self.cell_radius, -self.cell_radius], repeat=dim)))
示例#5
0
    def import_contents(self, progress):

        progress.set_size(self.vertex_nr)

        byte_idx = 84

        for face_idx in range(self._get_face_nr()):
            normal = self._parse_vector(byte_idx)
            if normal == [0.0, 0.0, 0.0]:
                raise ValueError("missing normal in face " + str(face_idx))
            for vertex_idx in range(1, 4):
                vector = to_ndarray(
                    self._parse_vector(byte_idx + 12 * vertex_idx))
                self.merger.add(vector)

                progress.inc()

            self.merger.set_last_face_normal(normal)
            byte_idx += 50

        self.merger.finalize()

        progress.done()

        return self.tm
示例#6
0
    def center(self, width, length):
        aabb = self.aabb

        # center X, Y
        x = width / 2.0
        y = length / 2.0
        z = aabb.center[2] - aabb.min[2]
        self.mx += to_ndarray([x, y, z]) - aabb.center
示例#7
0
def execute(delta, nr, aabb, initial_delta=0):
    initial_delta += delta * nr
    contour = to_ndarray([(aabb.min - initial_delta)[:2],
                          [aabb.min[0] - initial_delta, aabb.max[1] + initial_delta],
                          (aabb.max + initial_delta)[:2],
                          [aabb.max[0] + initial_delta, aabb.min[1] - initial_delta]])
    offsets = offset.execute([contour], -abs(delta), nr)
    return [o[0] for o in offsets]
示例#8
0
    def center(self, width, length):
        aabb = self.aabb

        # center X, Y
        x = width / 2.0
        y = length / 2.0
        z = aabb.center[2] - aabb.min[2]
        self.mx += to_ndarray([x, y, z]) - aabb.center
示例#9
0
    def __init__(self, cell_size, dim=3):
        super(MergingSpatialHash, self).__init__(cell_size)
        self.dim = dim
        self.cell_radius = cell_size / 2

        # moves to all neighbor cells
        self._moves = to_ndarray(
            list(product([0, self.cell_radius, -self.cell_radius],
                         repeat=dim)))
示例#10
0
    def slice(self, progress):
        self._init_slicing_positions()

        progress.set_size(len(self._slicing_positions))

        self._init_edge_height_map()

        for i, h in enumerate(sorted(self._edge_map.keys())):

            contours = []

            # edges that need to be visited on this height
            to_visit = self._edge_map[h]
            while len(to_visit) > 0:
                # 2D path - z coordinate is omitted as it is represented as height
                contour = []

                prev_face = None
                edge = self.tm.edges[to_visit.pop()]

                while True:

                    # intersect the edge
                    intersection = _edge_2d_intersection(edge, h)
                    contour.append(intersection)

                    to_visit.discard(edge.mxid)

                    # march
                    if prev_face is None:
                        # doesn't matter which face
                        prev_face = edge.face_a
                    else:
                        # select the opposite from the one we came
                        prev_face = edge.face_b if prev_face is edge.face_a else edge.face_a

                    # select edge from edges of a face that has not yet been worked on
                    edge = next(
                        (e for e in prev_face.edges if e.mxid in to_visit),
                        None)

                    # contour is finished when there is no more edges to cut
                    # WARNING: if the topology of the model is not manifold (holes in mesh)
                    # it might happen that the contour will be closed too soon
                    if edge is None:
                        break

                # All contours are closed
                contours.append(to_ndarray(contour))

            if contours:
                self.add_layer(contours, h, i)

            progress.inc()

        progress.done()
示例#11
0
def execute(delta, nr, aabb, initial_delta=0):
    initial_delta += delta * nr
    contour = to_ndarray([
        (aabb.min - initial_delta)[:2],
        [aabb.min[0] - initial_delta, aabb.max[1] + initial_delta],
        (aabb.max + initial_delta)[:2],
        [aabb.max[0] + initial_delta, aabb.min[1] - initial_delta]
    ])
    offsets = offset.execute([contour], -abs(delta), nr)
    return [o[0] for o in offsets]
示例#12
0
    def slice(self, progress):
        self._init_slicing_positions()

        progress.set_size(len(self._slicing_positions))

        self._init_edge_height_map()

        for i, h in enumerate(sorted(self._edge_map.keys())):

            contours = []

            # edges that need to be visited on this height
            to_visit = self._edge_map[h]
            while len(to_visit) > 0:
                # 2D path - z coordinate is omitted as it is represented as height
                contour = []

                prev_face = None
                edge = self.tm.edges[to_visit.pop()]

                while True:

                    # intersect the edge
                    intersection = _edge_2d_intersection(edge, h)
                    contour.append(intersection)

                    to_visit.discard(edge.mxid)

                    # march
                    if prev_face is None:
                        # doesn't matter which face
                        prev_face = edge.face_a
                    else:
                        # select the opposite from the one we came
                        prev_face = edge.face_b if prev_face is edge.face_a else edge.face_a

                    # select edge from edges of a face that has not yet been worked on
                    edge = next((e for e in prev_face.edges if e.mxid in to_visit), None)

                    # contour is finished when there is no more edges to cut
                    # WARNING: if the topology of the model is not manifold (holes in mesh)
                    # it might happen that the contour will be closed too soon
                    if edge is None:
                        break

                # All contours are closed
                contours.append(to_ndarray(contour))

            if contours:
                self.add_layer(contours, h, i)

            progress.inc()

        progress.done()
示例#13
0
    def __init__(self, model, settings, gcode_file):
        self.model = model
        self.s = settings
        self.gcode_file = gcode_file
        self.coder = None

        self.home = to_ndarray([0, 0])
        self.start = self.home

        self.change_layer = True
        self.height = 0
        self.y = 0

        self._model_center = model.get_center()
示例#14
0
    def move(self, vertex=None, x=None, y=None, z=None, e=None, ce=False, f=None):
        if vertex is not None:
            x = vertex[0]
            y = vertex[1]

        if ce:
            # calculate e
            e = euclidean_dist(self.start, vertex if vertex is not None else to_ndarray([x, y])) * self.e_per_mm

        if e:
            self.add_e(e)
            e = self.e_pos

        self.coder.move(x, y, z, e, f)
示例#15
0
    def __init__(self, model, settings, gcode_file):
        self.model = model
        self.s = settings
        self.gcode_file = gcode_file
        self.coder = None

        self.home = to_ndarray([0, 0])
        self.start = self.home

        self.change_layer = True
        self.height = 0
        self.y = 0

        self._model_center = model.get_center()
示例#16
0
    def __init__(self, model, settings, gcode_file):
        self.model = model
        self.s = settings
        self.coder = None
        self.gcode_file = gcode_file

        self.home = to_ndarray([0, 0])
        self.start = self.home

        self.change_layer = True
        self.height = 0

        self.e_per_mm = None
        self.e_pos = 0
        self.e_len = 0
示例#17
0
    def __init__(self, model, settings, gcode_file):
        self.model = model
        self.s = settings
        self.coder = None
        self.gcode_file = gcode_file

        self.home = to_ndarray([0, 0])
        self.start = self.home

        self.change_layer = True
        self.height = 0

        self.e_per_mm = None
        self.e_pos = 0
        self.e_len = 0
示例#18
0
def get_aabb_lines(aabb, delta):
    # get max aabb for this area so that it is independent
    # of rotation
    d = euclidean_dist(aabb.center[:2], aabb.max[:2])
    min_v, max_v = aabb.min - d, aabb.max + d

    x_l, x_r = min_v[0], max_v[0]

    y_positions = np_range(min_v[1], max_v[1], delta)

    lines = []
    for y in y_positions:
        lines.append(to_ndarray([[x_l, y], [x_r, y]]))

    return lines
示例#19
0
    def import_contents(self, progress):

        progress.set_size(self.vertex_nr)

        vertex_kw = 'vertex'
        for line in self.contents.splitlines():
            if vertex_kw in line:
                # parse vector coordinates
                vector = to_ndarray([float(x) for x in line.strip().split()[-3:]])
                self.merger.add(vector)

                progress.inc()

        self.merger.finalize()

        progress.done()

        return self.tm
示例#20
0
    def import_contents(self, progress):

        progress.set_size(self.vertex_nr)

        byte_idx = 84

        for face_idx in range(self._get_face_nr()):
            for vertex_idx in range(1, 4):
                vector = to_ndarray(self._parse_vector(byte_idx + 12 * vertex_idx))
                self.merger.add(vector)

                progress.inc()

            byte_idx += 50

        self.merger.finalize()

        progress.done()

        return self.tm
示例#21
0
def _closest_path(segments, point, paths_dict, order_path):
    min_path, min_point, min_point_id, min_d, min_segment = None, None, None, None, None
    for segment in segments:
        path = paths_dict[segment[0]]
        point_id = None
        if _is_closed_segment(segment):
            # segment
            p, d, point_id = closest_point_on_edge(path[segment[1]],
                                                   path[segment[2]], point)
        else:
            # point
            p = path[segment[1]]
            d = euclidean_dist_square(p, point)
        if min_d is None or d < min_d:
            min_path, min_point, min_d, min_segment, min_point_id = path, p, d, segment, point_id

    if order_path:
        if _is_closed_segment(min_segment):
            if min_point_id is 2:
                # order contour so that the projection point is the starting point
                min_path = np.concatenate(
                    (to_ndarray([min_point]), min_path[min_segment[2]:],
                     min_path[:min_segment[2]]))
            else:
                # closest point is part of the path, rotate the path
                # around that point
                if min_segment[1] is 0:
                    # proper contour start, do nothing
                    pass
                else:
                    min_path = np.roll(min_path,
                                       min_segment[min_point_id],
                                       axis=0)

        elif min_segment[1] < 0:
            # reverse open path if it ends on the end point denoted as -1
            min_path = min_path[::-1]

    return min_path, min_segment[0]
示例#22
0
    def move(self,
             vertex=None,
             x=None,
             y=None,
             z=None,
             e=None,
             ce=False,
             f=None):
        if vertex is not None:
            x = vertex[0]
            y = vertex[1]

        if ce:
            # calculate e
            e = euclidean_dist(
                self.start, vertex
                if vertex is not None else to_ndarray([x, y])) * self.e_per_mm

        if e:
            self.add_e(e)
            e = self.e_pos

        self.coder.move(x, y, z, e, f)
示例#23
0
    def import_contents(self, progress):

        progress.set_size(self.vertex_nr)

        byte_idx = 84

        for face_idx in range(self._get_face_nr()):
            normal = self._parse_vector(byte_idx)
            if normal == [0.0, 0.0, 0.0]:
                raise ValueError("missing normal in face "+str(face_idx))
            for vertex_idx in range(1, 4):
                vector = to_ndarray(self._parse_vector(byte_idx + 12 * vertex_idx))
                self.merger.add(vector)

                progress.inc()

            self.merger.set_last_face_normal(normal)
            byte_idx += 50

        self.merger.finalize()

        progress.done()

        return self.tm
示例#24
0
def _closest_path(segments, point, paths_dict, order_path):
    min_path, min_point, min_point_id, min_d, min_segment = None, None, None, None, None
    for segment in segments:
        path = paths_dict[segment[0]]
        point_id = None
        if _is_closed_segment(segment):
            # segment
            p, d, point_id = closest_point_on_edge(path[segment[1]], path[segment[2]], point)
        else:
            # point
            p = path[segment[1]]
            d = euclidean_dist_square(p, point)
        if min_d is None or d < min_d:
            min_path, min_point, min_d, min_segment, min_point_id = path, p, d, segment, point_id

    if order_path:
        if _is_closed_segment(min_segment):
            if min_point_id is 2:
                # order contour so that the projection point is the starting point
                min_path = np.concatenate((to_ndarray([min_point]),
                                           min_path[min_segment[2]:],
                                           min_path[:min_segment[2]]))
            else:
                # closest point is part of the path, rotate the path
                # around that point
                if min_segment[1] is 0:
                    # proper contour start, do nothing
                    pass
                else:
                    min_path = np.roll(min_path, min_segment[min_point_id], axis=0)

        elif min_segment[1] < 0:
            # reverse open path if it ends on the end point denoted as -1
            min_path = min_path[::-1]

    return min_path, min_segment[0]
示例#25
0
def convert(contours=None,
            lines=None,
            polylines=None,
            outputfile=None,
            display=False):
    lines = _get_list(lines)
    contours = _get_list(contours)
    polylines = _get_list(polylines)
    all_elements = [lines, contours, polylines]
    all_l = sum(len(l) for l in all_elements)
    colors = _get_colors(all_l)
    info = {}

    text_width = 120
    default_width = text_width + 15 * all_l
    line_height = 15
    extra_height = 3 * line_height

    aabb = get_aabb(
        np.concatenate([np.concatenate(x) for x in all_elements
                        if len(x) > 0]))

    add_x = -aabb.min[0]
    add_y = -aabb.min[1]

    add_v = to_ndarray([add_x, add_y])

    result = "\n<svg width=\"800\" height=\"600\" viewbox=\"{} {} {} {}\">".format(
        0, 0,
        int(aabb.max[0] - aabb.min[0]) + 10,
        int(aabb.max[1] - aabb.min[1]) + 10)

    for contour in contours:
        contour = contour + add_v
        color = colors.pop()
        result += "\n\t<polygon points=\"{}\" style=\"fill:none;stroke:{};stroke-width:0.1\" />".format(
            _format_polygon(contour), color)
        info.setdefault('Contours', []).append(color)

    for line in lines:
        line = line + add_v
        color = colors.pop()
        result += "\n\t<line x1=\"{}\" y1=\"{}\" x2=\"{}\" y2=\"{}\" style=\"stroke:{};stroke-width:0.1\" />".format(
            line[0][0], line[0][1], line[-1][0], line[-1][1], color)
        info.setdefault('Lines', []).append(color)

    for polyline in polylines:
        polyline = polyline + add_v
        color = colors.pop()
        result += "\n\t<polyline points=\"{}\" style=\"fill:none;stroke:{};stroke-width:0.1\" />".format(
            _format_polygon(polyline), color)
        info.setdefault('Polylines', []).append(color)
    result += "\n</svg>"
    result += "\n<br /><svg width=\"{}\" height=\"{}\">".format(
        default_width, extra_height)
    i = 0
    for k, v in info.items():
        x, y = 0, extra_height - (i * line_height)
        result += "\n\t<text x=\"{}\" y=\"{}\" font-family=\"sans-serif\" font-size=\"{}\" fill=\"black\">{} ({})</text>".format(
            x, y, line_height, k, len(v))

        for j, color in enumerate(v):
            result += "\n\t<rect x=\"{}\" y=\"{}\" width=\"10\" height=\"10\" style=\"fill:{};stroke-width:0;\"/>".format(
                text_width + (j * 15), y - 10, color)
        i += 1
    result += "\n</svg>"

    return result
示例#26
0
def _to_ndarrays(clipper_paths):
    paths = []
    for clipper_path in clipper_paths:
        paths.append(to_ndarray(clipper_path))
    return paths
示例#27
0
import numpy as np
from quadtree import Quadtree

from grslicer.util.np import get_aabb, to_ndarray, euclidean_dist_square, closest_point_on_edge


POINT_AABB = to_ndarray([[-10, -10], [10, 10]])


def follow(paths, get_start_func, closed=True):
    """ Iterate through paths as they follow by closeness. Yields
    the closest path that starts on the closest point, and the
    ending point of the path.
    """
    if len(paths) is 0:
        # TODO: check this
        return

    tree, segment_mapping = _get_tree(paths, closed)

    todo_path_mapping = dict([(id(path), path) for path in paths])

    while len(todo_path_mapping) > 0:
        path, path_id = _query(tree, segment_mapping, get_start_func(), todo_path_mapping)

        del todo_path_mapping[path_id]

        if closed:
            start = path[0]
        else:
            start = path[-1]
示例#28
0
from struct import unpack

import vertexmerger
from grslicer.model import TopoModel, DEFAULT_COORDINATE_TYPE
from grslicer.util.np import to_ndarray, np
from grslicer.importers.base import ModelImporter
from grslicer.util.progress import progress_log

NULL_VECTOR = to_ndarray([0.0, 0.0, 0.0])


class StlAsciiImporter(ModelImporter, vertexmerger.VertexMerger):
    @staticmethod
    def can_import(contents):
        return all(
            [kw in contents for kw in ('solid', 'vertex', 'facet normal')])

    def __init__(self, *args, **kwargs):
        super(StlAsciiImporter, self).__init__(*args, **kwargs)

        self.vertex_nr = self._get_face_nr() * 3

        self.merger = vertexmerger.VertexMerger(
            TopoModel(shape=(self.vertex_nr * 3, 3)),
            DEFAULT_COORDINATE_TYPE(self.settings.roundOffError))

    def _get_face_nr(self):
        return self.contents.count('facet normal')

    @property
    def tm(self):
示例#29
0
def convert(contours=None, lines=None, polylines=None, outputfile=None, display=False):
    lines = _get_list(lines)
    contours = _get_list(contours)
    polylines = _get_list(polylines)
    all_elements = [lines, contours, polylines]
    all_l = sum(len(l) for l in all_elements)
    colors = _get_colors(all_l)
    info = {}

    text_width = 120
    default_width = text_width + 15 * all_l
    line_height = 15
    extra_height = 3 * line_height

    aabb = get_aabb(np.concatenate([np.concatenate(x) for x in
                                    all_elements if len(x) > 0]))

    add_x = -aabb.min[0]
    add_y = -aabb.min[1]

    add_v = to_ndarray([add_x, add_y])

    result = "\n<svg width=\"800\" height=\"600\" viewbox=\"{} {} {} {}\">".format(
        0, 0,
        int(aabb.max[0] - aabb.min[0]) + 10, int(aabb.max[1] - aabb.min[1]) + 10)

    for contour in contours:
        contour = contour + add_v
        color = colors.pop()
        result += "\n\t<polygon points=\"{}\" style=\"fill:none;stroke:{};stroke-width:0.1\" />".format(
            _format_polygon(contour), color)
        info.setdefault('Contours', []).append(color)

    for line in lines:
        line = line + add_v
        color = colors.pop()
        result += "\n\t<line x1=\"{}\" y1=\"{}\" x2=\"{}\" y2=\"{}\" style=\"stroke:{};stroke-width:0.1\" />".format(
            line[0][0], line[0][1], line[-1][0], line[-1][1], color)
        info.setdefault('Lines', []).append(color)

    for polyline in polylines:
        polyline = polyline + add_v
        color = colors.pop()
        result += "\n\t<polyline points=\"{}\" style=\"fill:none;stroke:{};stroke-width:0.1\" />".format(
            _format_polygon(polyline), color)
        info.setdefault('Polylines', []).append(color)
    result += "\n</svg>"
    result += "\n<br /><svg width=\"{}\" height=\"{}\">".format(default_width, extra_height)
    i = 0
    for k, v in info.items():
        x, y = 0, extra_height - (i * line_height)
        result += "\n\t<text x=\"{}\" y=\"{}\" font-family=\"sans-serif\" font-size=\"{}\" fill=\"black\">{} ({})</text>".format(
            x, y, line_height, k, len(v))

        for j, color in enumerate(v):
            result += "\n\t<rect x=\"{}\" y=\"{}\" width=\"10\" height=\"10\" style=\"fill:{};stroke-width:0;\"/>".format(
                text_width + (j * 15), y - 10, color)
        i += 1
    result += "\n</svg>"

    return result
示例#30
0
def _intersect_face_line(face, scanline_point, scanline_direction):
    SMALL_NUM = 0.00000001 # anything that avoids division overflow
    # dot product (3D) which allows vector operations in arguments
    #define dot(u,v)   ((u).x * (v).x + (u).y * (v).y + (u).z * (v).z)
    # intersect3D_RayTriangle(): find the 3D intersection of a ray with a triangle
    #    Input:  a ray R, and a triangle T
    #    Output: *I = intersection point (when it exists)
    #    Return: -1 = triangle is degenerate (a segment or point)
    #             0 =  disjoint (no intersect)
    #             1 =  intersect in unique point I1
    #             2 =  are in the same plane
    # int intersect3D_RayTriangle( Ray R, Triangle T, Point* I )

    #    Vector    u, v, n;              // triangle vectors
    #    Vector    dir, w0, w;           // ray vectors
    #    float     r, a, b;              // params to calc ray-plane intersect

    # get triangle edge vectors and plane normal
    va = face.vertex_a.vector
    vb = face.vertex_b.vector
    vc = face.vertex_c.vector
    u = vb - va #u = T.V1 - T.V0;
    v = vc - va #v = T.V2 - T.V0;
    n2 = np.cross(u, v) #n = u * v;              // cross product
    n = face.normal

    if n[0] == DEFAULT_COORDINATE_TYPE(0) and n[1] == DEFAULT_COORDINATE_TYPE(0) and n[2] == DEFAULT_COORDINATE_TYPE(0): # // triangle is degenerate
        return (-1, None)                   #// do not deal with this case

    dir = to_ndarray(scanline_direction) #dir = R.P1 - R.P0; // ray direction vector
    w0 = to_ndarray(scanline_point) - va # w0 = R.P0 - T.V0;
    a = - np.dot(n, w0) # a = -dot(n,w0);
    b = np.dot(n, dir) # b = dot(n,dir);
    if abs(b) < DEFAULT_COORDINATE_TYPE(SMALL_NUM): #if (fabs(b) < SMALL_NUM) {     // ray is  parallel to triangle plane
        if a == DEFAULT_COORDINATE_TYPE(0): #    if (a == 0)                 // ray lies in triangle plane
            return (2, None)
        else:
            return (0, None) #              // ray disjoint from plane
    # }

    # // get intersect point of ray with triangle plane
    r = a / b # r = a / b;
    if r < DEFAULT_COORDINATE_TYPE(0.0): # if (r < 0.0)                    // ray goes away from triangle
        return (0, None) #                  // => no intersect
    # // for a segment, also test if (r > 1.0) => no intersect

    I = to_ndarray([scanline_point[0]+r, scanline_point[1], scanline_point[2], np.dot(n, dir)/abs(np.dot(n, dir))]) #*I = R.P0 + r * dir;            // intersect point of ray and plane

    # // is I inside T?
    # float    uu, uv, vv, wu, wv, D;
    uu = np.dot(u, u) # uu = dot(u,u);
    uv = np.dot(u, v) # uv = dot(u,v);
    vv = np.dot(v, v) # vv = dot(v,v);
    w = I[0:3] - va # w = *I - T.V0;
    wu = np.dot(w, u) # wu = dot(w,u);
    wv = np.dot(w, v) # wv = dot(w,v);
    D = uv * uv - uu * vv # D = uv * uv - uu * vv;

    if D == DEFAULT_COORDINATE_TYPE(0.0):
        return (0, None)

    # // get and test parametric coords
    # float s, t;
    s = (uv * wv - vv * wu) / D # s = (uv * wv - vv * wu) / D;
    if s < DEFAULT_COORDINATE_TYPE(0.0) or s > DEFAULT_COORDINATE_TYPE(1.0): # if (s < 0.0 || s > 1.0)         // I is outside T
        return (0, None)
    t = (uv * wu - uu * wv) / D # t = (uv * wu - uu * wv) / D;
    if t < DEFAULT_COORDINATE_TYPE(0.0) or (s+t) > DEFAULT_COORDINATE_TYPE(1.0): # if (t < 0.0 || (s + t) > 1.0)  // I is outside T
        return (0, None)

    return (1, I) #                      // I is in T
示例#31
0
from struct import unpack

import vertexmerger
from grslicer.model import TopoModel, DEFAULT_COORDINATE_TYPE
from grslicer.util.np import to_ndarray, np
from grslicer.importers.base import ModelImporter
from grslicer.util.progress import progress_log

NULL_VECTOR = to_ndarray([0.0, 0.0, 0.0])

class StlAsciiImporter(ModelImporter, vertexmerger.VertexMerger):
    @staticmethod
    def can_import(contents):
        return all([kw in contents for kw in ('solid', 'vertex', 'facet normal')])

    def __init__(self, *args, **kwargs):
        super(StlAsciiImporter, self).__init__(*args, **kwargs)

        self.vertex_nr = self._get_face_nr() * 3

        self.merger = vertexmerger.VertexMerger(TopoModel(shape=(self.vertex_nr * 3, 3)),
                                                DEFAULT_COORDINATE_TYPE(self.settings.roundOffError))

    def _get_face_nr(self):
        return self.contents.count('facet normal')

    @property
    def tm(self):
        return self.merger.tm

    @progress_log('Importing ASCII STL file contents')
示例#32
0
def _intersect_face_line(face, scanline_point, scanline_direction):
    SMALL_NUM = 0.00000001  # anything that avoids division overflow
    # dot product (3D) which allows vector operations in arguments
    #define dot(u,v)   ((u).x * (v).x + (u).y * (v).y + (u).z * (v).z)
    # intersect3D_RayTriangle(): find the 3D intersection of a ray with a triangle
    #    Input:  a ray R, and a triangle T
    #    Output: *I = intersection point (when it exists)
    #    Return: -1 = triangle is degenerate (a segment or point)
    #             0 =  disjoint (no intersect)
    #             1 =  intersect in unique point I1
    #             2 =  are in the same plane
    # int intersect3D_RayTriangle( Ray R, Triangle T, Point* I )

    #    Vector    u, v, n;              // triangle vectors
    #    Vector    dir, w0, w;           // ray vectors
    #    float     r, a, b;              // params to calc ray-plane intersect

    # get triangle edge vectors and plane normal
    va = face.vertex_a.vector
    vb = face.vertex_b.vector
    vc = face.vertex_c.vector
    u = vb - va  #u = T.V1 - T.V0;
    v = vc - va  #v = T.V2 - T.V0;
    n2 = np.cross(u, v)  #n = u * v;              // cross product
    n = face.normal

    if n[0] == DEFAULT_COORDINATE_TYPE(0) and n[1] == DEFAULT_COORDINATE_TYPE(
            0) and n[2] == DEFAULT_COORDINATE_TYPE(
                0):  # // triangle is degenerate
        return (-1, None)  #// do not deal with this case

    dir = to_ndarray(
        scanline_direction)  #dir = R.P1 - R.P0; // ray direction vector
    w0 = to_ndarray(scanline_point) - va  # w0 = R.P0 - T.V0;
    a = -np.dot(n, w0)  # a = -dot(n,w0);
    b = np.dot(n, dir)  # b = dot(n,dir);
    if abs(b) < DEFAULT_COORDINATE_TYPE(
            SMALL_NUM
    ):  #if (fabs(b) < SMALL_NUM) {     // ray is  parallel to triangle plane
        if a == DEFAULT_COORDINATE_TYPE(
                0
        ):  #    if (a == 0)                 // ray lies in triangle plane
            return (2, None)
        else:
            return (0, None)  #              // ray disjoint from plane
    # }

    # // get intersect point of ray with triangle plane
    r = a / b  # r = a / b;
    if r < DEFAULT_COORDINATE_TYPE(
            0.0
    ):  # if (r < 0.0)                    // ray goes away from triangle
        return (0, None)  #                  // => no intersect
    # // for a segment, also test if (r > 1.0) => no intersect

    I = to_ndarray([
        scanline_point[0] + r, scanline_point[1], scanline_point[2],
        np.dot(n, dir) / abs(np.dot(n, dir))
    ])  #*I = R.P0 + r * dir;            // intersect point of ray and plane

    # // is I inside T?
    # float    uu, uv, vv, wu, wv, D;
    uu = np.dot(u, u)  # uu = dot(u,u);
    uv = np.dot(u, v)  # uv = dot(u,v);
    vv = np.dot(v, v)  # vv = dot(v,v);
    w = I[0:3] - va  # w = *I - T.V0;
    wu = np.dot(w, u)  # wu = dot(w,u);
    wv = np.dot(w, v)  # wv = dot(w,v);
    D = uv * uv - uu * vv  # D = uv * uv - uu * vv;

    if D == DEFAULT_COORDINATE_TYPE(0.0):
        return (0, None)

    # // get and test parametric coords
    # float s, t;
    s = (uv * wv - vv * wu) / D  # s = (uv * wv - vv * wu) / D;
    if s < DEFAULT_COORDINATE_TYPE(0.0) or s > DEFAULT_COORDINATE_TYPE(
            1.0):  # if (s < 0.0 || s > 1.0)         // I is outside T
        return (0, None)
    t = (uv * wu - uu * wv) / D  # t = (uv * wu - uu * wv) / D;
    if t < DEFAULT_COORDINATE_TYPE(0.0) or (s + t) > DEFAULT_COORDINATE_TYPE(
            1.0):  # if (t < 0.0 || (s + t) > 1.0)  // I is outside T
        return (0, None)

    return (1, I)  #                      // I is in T
示例#33
0
def _connect_lines(lines, delta, theta, center, max_connection_dist):
    # lines are np arrays of np arrays tha represent vertices
    connected_lines = []

    # lines should be aligned left-right and be parallel to X-axis
    lines_by_y = {}
    d_lines = []
    for line in lines:

        # align left to right
        if line[0][0] > line[-1][0]:
            line = line[::-1]

        # line should be a list of np arrays that represent vertices
        line = list(line)
        d_lines.append(line)
        lines_by_y.setdefault(line[0][1], []).append(line)

    y_positions = sorted(lines_by_y.keys())
    dist_squared = max_connection_dist ** 2

    while len(lines_by_y) > 0:
        prev_y = y_positions[0]

        # line has to be a list, not a np array
        # because points will be added to it
        line = lines_by_y[prev_y].pop()

        # used y-positions to be removed from line collections
        used_ys = [prev_y]

        for y in y_positions[1:]:
            if not prev_y < y < prev_y + (2 * delta):  # > prev_y and np.isclose(y, prev_y + delta):
                break

            # find if any of lines at the next y is close enough to connect
            next_line_connection_side = 0 if ((len(line) % 4) is 0) else -1
            current_line_connection_vertex = line[-1]

            for line_idx, l in enumerate(lines_by_y[y]):
                next_line_vertex = l[next_line_connection_side]

                # TODO: maybe do a clip in the square between points and if resulting number of polygons
                # is 1 than we cont need the euclidean dist -> just put that polygon into line
                if euclidean_dist_square(current_line_connection_vertex, next_line_vertex) < dist_squared:

                    del lines_by_y[y][line_idx]
                    used_ys.append(y)

                    # properly orient the line
                    if next_line_connection_side is -1:
                        l = l[::-1]
                    line.extend(list(l))

                    # go for next y position
                    break

            prev_y = y

        for y in used_ys:
            if len(lines_by_y[y]) is 0:
                del lines_by_y[y]
                y_positions.remove(y)

        # convert back to np array
        connected_lines.append(rotate_xy(to_ndarray(line), theta, center))
    return connected_lines
示例#34
0
import numpy as np
from quadtree import Quadtree

from grslicer.util.np import get_aabb, to_ndarray, euclidean_dist_square, closest_point_on_edge

POINT_AABB = to_ndarray([[-10, -10], [10, 10]])


def follow(paths, get_start_func, closed=True):
    """ Iterate through paths as they follow by closeness. Yields
    the closest path that starts on the closest point, and the
    ending point of the path.
    """
    if len(paths) is 0:
        # TODO: check this
        return

    tree, segment_mapping = _get_tree(paths, closed)

    todo_path_mapping = dict([(id(path), path) for path in paths])

    while len(todo_path_mapping) > 0:
        path, path_id = _query(tree, segment_mapping, get_start_func(),
                               todo_path_mapping)

        del todo_path_mapping[path_id]

        if closed:
            start = path[0]
        else:
            start = path[-1]