Пример #1
0
 def _projection(self, widget=None):
     models = self._get_projectable_models()
     if not models:
         return
     progress = self.core.get("progress")
     progress.update(text="Calculating 2D projection")
     progress.set_multiple(len(models), "Model")
     for model_dict in models:
         model = model_dict.model
         for objname, z_level in (
             ("ProjectionModelTop", model.maxz),
             ("ProjectionModelMiddle", (model.minz + model.maxz) / 2.0),
             ("ProjectionModelBottom", model.minz),
             ("ProjectionModelCustom",
              self.gui.get_object("ProjectionZLevel").get_value())):
             if self.gui.get_object(objname).get_active():
                 plane = Plane(Point(0, 0, z_level), Vector(0, 0, 1))
                 self.log.info("Projecting 3D model at level z=%g" %
                               plane.p.z)
                 new_model = model.get_waterline_contour(
                     plane, callback=progress.update)
                 if new_model:
                     self.core.get("models").add_model(
                         new_model, name_template="Projected model #%d")
                 else:
                     self.log.warn("The 2D projection at z=%g is empty. Aborted." % \
                             plane.p.z)
                 break
         progress.update_multiple()
     progress.finish()
Пример #2
0
class _BridgeCorner(object):
    # currently we only use the xy plane
    up_vector = Vector(0, 0, 1)
    def __init__(self, barycenter, location, p1, p2, p3):
        self.location = location
        self.position = p2
        self.direction = pycam.Geometry.get_bisector(p1, p2, p3,
                self.up_vector).normalized()
        preferred_direction = p2.sub(barycenter).normalized()
        # direction_factor: 0..1 (bigger -> better)
        direction_factor = (preferred_direction.dot(self.direction) + 1) / 2
        angle = pycam.Geometry.get_angle_pi(p1, p2, p3,
                self.up_vector, pi_factor=True)
        # angle_factor: 0..1 (bigger -> better)
        if angle > 0.5:
            # use only angles > 90 degree
            angle_factor = angle / 2.0
        else:
            angle_factor = 0
        # priority: 0..1 (bigger -> better)
        self.priority = angle_factor * direction_factor
    def get_position_priority(self, other_location, average_distance):
        return self.priority / (1 + self.get_distance(other_location) / \
                average_distance)
    def get_distance(self, other_location):
        return min(abs(other_location - self.location),
                abs(1 + other_location - self.location))
    def __str__(self):
        return "%s (%s) - %s" % (self.position, self.location, self.priority)
Пример #3
0
 def __init__(self, point, normal=None):
     super(Plane, self).__init__()
     if normal is None:
         normal = Vector(0, 0, 1)
     self.p = point
     self.n = normal
     if not isinstance(self.n, Vector):
         self.n = self.n.get_vector()
Пример #4
0
def get_support_distributed(model,
                            z_plane,
                            average_distance,
                            min_bridges_per_polygon,
                            thickness,
                            height,
                            length,
                            bounds,
                            start_at_corners=False):
    if (average_distance == 0) or (length == 0) or (thickness == 0) \
            or (height == 0):
        return
    result = Model()
    if not hasattr(model, "get_polygons"):
        model = model.get_waterline_contour(
            Plane(Point(0, 0, max(model.minz, z_plane)), Vector(0, 0, 1)))
    if model:
        model = model.get_flat_projection(
            Plane(Point(0, 0, z_plane), Vector(0, 0, 1)))
    if model:
        model = model.get_cropped_model_by_bounds(bounds)
    if model:
        polygons = model.get_polygons()
    else:
        return None
    # minimum required distance between two bridge start points
    avoid_distance = 1.5 * (abs(length) + thickness)
    if start_at_corners:
        bridge_calculator = _get_corner_bridges
    else:
        bridge_calculator = _get_edge_bridges
    for polygon in polygons:
        # no grid for _small_ inner polygons
        # TODO: calculate a reasonable factor (see below)
        if polygon.is_closed and (not polygon.is_outer()) \
                and (abs(polygon.get_area()) < 25000 * thickness ** 2):
            continue
        bridges = bridge_calculator(polygon, z_plane, min_bridges_per_polygon,
                                    average_distance, avoid_distance)
        for pos, direction in bridges:
            _add_cuboid_to_model(result, pos, direction.mul(length), height,
                                 thickness)
    return result
Пример #5
0
def get_lines_layer(lines, z, last_z=None, step_width=None,
        milling_style=MILLING_STYLE_CONVENTIONAL):
    get_proj_point = lambda proj_point: Point(proj_point.x, proj_point.y, z)
    projected_lines = []
    for line in lines:
        if (not last_z is None) and (last_z < line.minz):
            # the line was processed before
            continue
        elif line.minz < z < line.maxz:
            # Split the line at the point at z level and do the calculation
            # for both point pairs.
            factor = (z - line.p1.z) / (line.p2.z - line.p1.z)
            plane_point = line.p1.add(line.vector.mul(factor))
            if line.p1.z < z:
                p1 = get_proj_point(line.p1)
                p2 = line.p2
            else:
                p1 = line.p1
                p2 = get_proj_point(line.p2)
            projected_lines.append(Line(p1, plane_point))
            yield Line(plane_point, p2)
        elif line.minz < last_z < line.maxz:
            plane = Plane(Point(0, 0, last_z), Vector(0, 0, 1))
            cp = plane.intersect_point(line.dir, line.p1)[0]
            # we can be sure that there is an intersection
            if line.p1.z > last_z:
                p1, p2 = cp, line.p2
            else:
                p1, p2 = line.p1, cp
            projected_lines.append(Line(p1, p2))
        else:
            if line.maxz <= z:
                # the line is completely below z
                projected_lines.append(Line(get_proj_point(line.p1),
                        get_proj_point(line.p2)))
            elif line.minz >= z:
                projected_lines.append(line)
            else:
                log.warn("Unexpected condition 'get_lines_layer': " + \
                        "%s / %s / %s / %s" % (line.p1, line.p2, z, last_z))
    # process all projected lines
    for line in projected_lines:
        points = []
        if step_width is None:
            points.append(line.p1)
            points.append(line.p2)
        else:
            if isiterable(step_width):
                steps = step_width
            else:
                steps = floatrange(0.0, line.len, inc=step_width)
            for step in steps:
                next_point = line.p1.add(line.dir.mul(step))
                points.append(next_point)
        yield points
Пример #6
0
 def GenerateToolPathLinePush(self, pa, line, z, previous_z,
         draw_callback=None):
     if previous_z <= line.minz:
         # the line is completely above the previous level
         pass
     elif line.minz < z < line.maxz:
         # Split the line at the point at z level and do the calculation
         # for both point pairs.
         factor = (z - line.p1.z) / (line.p2.z - line.p1.z)
         plane_point = line.p1.add(line.vector.mul(factor))
         self.GenerateToolPathLinePush(pa, Line(line.p1, plane_point), z,
                 previous_z, draw_callback=draw_callback)
         self.GenerateToolPathLinePush(pa, Line(plane_point, line.p2), z,
                 previous_z, draw_callback=draw_callback)
     elif line.minz < previous_z < line.maxz:
         plane = Plane(Point(0, 0, previous_z), Vector(0, 0, 1))
         cp = plane.intersect_point(line.dir, line.p1)[0]
         # we can be sure that there is an intersection
         if line.p1.z > previous_z:
             p1, p2 = cp, line.p2
         else:
             p1, p2 = line.p1, cp
         self.GenerateToolPathLinePush(pa, Line(p1, p2), z, previous_z,
                 draw_callback=draw_callback)
     else:
         if line.maxz <= z:
             # the line is completely below z
             p1 = Point(line.p1.x, line.p1.y, z)
             p2 = Point(line.p2.x, line.p2.y, z)
         elif line.minz >= z:
             p1 = line.p1
             p2 = line.p2
         else:
             log.warn("Unexpected condition EC_GTPLP: %s / %s / %s / %s" % \
                     (line.p1, line.p2, z, previous_z))
             return
         # no model -> no possible obstacles
         # model is completely below z (e.g. support bridges) -> no obstacles
         relevant_models = [m for m in self.models if m.maxz >= z]
         if not relevant_models:
             points = [p1, p2]
         elif self.physics:
             points = get_free_paths_ode(self.physics, p1, p2)
         else:
             points = get_free_paths_triangles(relevant_models, self.cutter,
                     p1, p2)
         if points:
             for point in points:
                 pa.append(point)
             if draw_callback:
                 draw_callback(tool_position=points[-1], toolpath=pa.paths)
Пример #7
0
 def __init__(self, plane=None):
     super(ContourModel, self).__init__()
     self.name = "contourmodel%d" % self.id
     if plane is None:
         # the default plane points upwards along the z axis
         plane = Plane(Point(0, 0, 0), Vector(0, 0, 1))
     self._plane = plane
     self._line_groups = []
     self._item_groups.append(self._line_groups)
     # there is always just one plane
     self._plane_groups = [self._plane]
     self._item_groups.append(self._plane_groups)
     self._cached_offset_models = {}
     self._export_function = \
             pycam.Exporters.SVGExporter.SVGExporterContourModel
Пример #8
0
 def __init__(self, model, cutter):
     self.model = model
     self.diameter = 2 * cutter.radius
     self.height = self.diameter  # TODO: enfoncement
     self.nb_layers = ceil(
         (model.maxz - model.minz) / self.height) + 1  # TODO: +1 skypocket
     self.layers = []
     #self.heights = Grid.floatrange(model.minz, model.maxz, self.height, False)
     self.heights = [
         model.minz + i * self.height for i in range(self.nb_layers)
     ]
     self.minx, self.miny, self.minz = model.minx, model.miny, model.minz
     self.maxx, self.maxy, self.maxz = model.maxx, model.maxy, model.maxz
     self.up_vector = Vector(0, 0, 1)
     self.Box = GridBox(self)
     self.do_pavement()
Пример #9
0
 def __init__(self, path_processor, physics=None):
     self.pa = path_processor
     self._up_vector = Vector(0, 0, 1)
     self.physics = physics
     self._processed_triangles = []
     if self.physics:
         accuracy = 20
         max_depth = 16
         # TODO: migrate to new interface
         maxx = max([m.maxx for m in self.models])
         minx = max([m.minx for m in self.models])
         maxy = max([m.maxy for m in self.models])
         miny = max([m.miny for m in self.models])
         model_dim = max(abs(maxx - minx), abs(maxy - miny))
         depth = math.log(accuracy * model_dim / self.cutter.radius) / \
                 math.log(2)
         self._physics_maxdepth = min(max_depth, max(ceil(depth), 4))
Пример #10
0
def _add_cuboid_to_model(model, start, direction, height, width):
    up = Vector(0, 0, 1).mul(height)
    ortho_dir = direction.cross(up).normalized()
    start1 = start.add(ortho_dir.mul(-width/2))
    start2 = start1.add(up)
    start3 = start2.add(ortho_dir.mul(width))
    start4 = start3.sub(up)
    end1 = start1.add(direction)
    end2 = start2.add(direction)
    end3 = start3.add(direction)
    end4 = start4.add(direction)
    faces = ((start1, start2, start3, start4), (start1, end1, end2, start2),
            (start2, end2, end3, start3), (start3, end3, end4, start4),
            (start4, end4, end1, start1), (end4, end3, end2, end1))
    for face in faces:
        t1, t2 = _get_triangles_for_face(face)
        model.append(t1)
        model.append(t2)
Пример #11
0
    t = None
    p1 = None
    p2 = None
    p3 = None

    if binary:
        for i in range(1, numfacets + 1):
            if callback and callback():
                log.warn("STLImporter: load model operation cancelled")
                return None
            a1 = unpack("<f", f.read(4))[0]
            a2 = unpack("<f", f.read(4))[0]
            a3 = unpack("<f", f.read(4))[0]

            n = Vector(float(a1), float(a2), float(a3))

            v11 = unpack("<f", f.read(4))[0]
            v12 = unpack("<f", f.read(4))[0]
            v13 = unpack("<f", f.read(4))[0]

            p1 = UniqueVertex(float(v11), float(v12), float(v13))

            v21 = unpack("<f", f.read(4))[0]
            v22 = unpack("<f", f.read(4))[0]
            v23 = unpack("<f", f.read(4))[0]

            p2 = UniqueVertex(float(v21), float(v22), float(v23))

            v31 = unpack("<f", f.read(4))[0]
            v32 = unpack("<f", f.read(4))[0]
Пример #12
0
    t = None
    p1 = None
    p2 = None
    p3 = None

    if binary:
        for i in range(1, numfacets + 1): 
            if callback and callback():
                log.warn("STLImporter: load model operation cancelled")
                return None
            a1 = unpack("<f", f.read(4))[0] 
            a2 = unpack("<f", f.read(4))[0] 
            a3 = unpack("<f", f.read(4))[0] 

            n = Vector(float(a1), float(a2), float(a3))
            
            v11 = unpack("<f", f.read(4))[0] 
            v12 = unpack("<f", f.read(4))[0] 
            v13 = unpack("<f", f.read(4))[0] 

            p1 = UniqueVertex(float(v11), float(v12), float(v13))
            
            v21 = unpack("<f", f.read(4))[0] 
            v22 = unpack("<f", f.read(4))[0] 
            v23 = unpack("<f", f.read(4))[0] 

            p2 = UniqueVertex(float(v21), float(v22), float(v23))
            
            v31 = unpack("<f", f.read(4))[0] 
            v32 = unpack("<f", f.read(4))[0] 
Пример #13
0
 def __init__(self, radius, **kwargs):
     BaseCutter.__init__(self, radius, **kwargs)
     self.axis = Vector(0, 0, 1)
Пример #14
0
def get_spiral_layer(minx, maxx, miny, maxy, z, line_distance, step_width,
        grid_direction, start_position, rounded_corners, reverse):
    current_location = _get_position(minx, maxx, miny, maxy, z,
            start_position)
    if line_distance > 0:
        line_steps_x = math.ceil((float(maxx - minx) / line_distance))
        line_steps_y = math.ceil((float(maxy - miny) / line_distance))
        line_distance_x = (maxx - minx) / line_steps_x
        line_distance_y = (maxy - miny) / line_steps_y
        lines = get_spiral_layer_lines(minx, maxx, miny, maxy, z,
                line_distance_x, line_distance_y, grid_direction,
                start_position, current_location)
        if reverse:
            lines.reverse()
        # turn the lines into steps
        if rounded_corners:
            rounded_lines = []
            previous = None
            for index, (start, end) in enumerate(lines):
                radius = 0.5 * min(line_distance_x, line_distance_y)
                edge_vector = end.sub(start)
                # TODO: ellipse would be better than arc
                offset = edge_vector.normalized().mul(radius)
                if previous:
                    start = start.add(offset)
                    center = previous.add(offset)
                    up_vector = previous.sub(center).cross(start.sub(center)).normalized()
                    north = center.add(Vector(1.0, 0.0, 0.0))
                    angle_start = pycam.Geometry.get_angle_pi(north, center, previous, up_vector, pi_factor=True) * 180.0
                    angle_end = pycam.Geometry.get_angle_pi(north, center, start, up_vector, pi_factor=True) * 180.0
                    # TODO: remove these exceptions based on up_vector.z (get_points_of_arc does not respect the plane, yet)
                    if up_vector.z < 0:
                        angle_start, angle_end = -angle_end, -angle_start
                    arc_points = pycam.Geometry.get_points_of_arc(center, radius, angle_start, angle_end)
                    if up_vector.z < 0:
                        arc_points.reverse()
                    for arc_index in range(len(arc_points) - 1):
                        p1_coord = arc_points[arc_index]
                        p2_coord = arc_points[arc_index + 1]
                        p1 = Point(p1_coord[0], p1_coord[1], z)
                        p2 = Point(p2_coord[0], p2_coord[1], z)
                        rounded_lines.append((p1, p2))
                if index != len(lines) - 1:
                    end = end.sub(offset)
                previous = end
                rounded_lines.append((start, end))
            lines = rounded_lines
        for start, end in lines:
            points = []
            if step_width is None:
                points.append(start)
                points.append(end)
            else:
                line = Line(start, end)
                if isiterable(step_width):
                    steps = step_width
                else:
                    steps = floatrange(0.0, line.len, inc=step_width)
                for step in steps:
                    next_point = line.p1.add(line.dir.mul(step))
                    points.append(next_point)
            if reverse:
                points.reverse()
            yield points