コード例 #1
0
def intersect_sphere_line(center, radius, radiussq, direction, edge):
    # make a plane by sliding the line along the direction (1)
    d = edge.dir
    n = pcross(d, direction)
    if pnorm(n) == 0:
        # no contact point, but should check here if sphere *always* intersects
        # line...
        return (None, None, INFINITE)
    n = pnormalized(n)

    # calculate the distance from the sphere center to the plane
    dist = -pdot(center, n) + pdot(edge.p1, n)
    if abs(dist) > radius - epsilon:
        return (None, None, INFINITE)
    # this gives us the intersection circle on the sphere

    # now take a plane through the edge and perpendicular to the direction (2)
    # find the center on the circle closest to this plane

    # which means the other component is perpendicular to this plane (2)
    n2 = pnormalized(pcross(n, d))

    # the contact point is on a big circle through the sphere...
    dist2 = sqrt(radiussq - dist * dist)

    # ... and it's on the plane (1)
    ccp = padd(center, padd(pmul(n, dist), pmul(n2, dist2)))

    # now intersect a line through this point with the plane (2)
    plane = Plane(edge.p1, n2)
    (cp, l) = plane.intersect_point(direction, ccp)
    return (ccp, cp, l)
コード例 #2
0
def intersect_torus_point(center, axis, majorradius, minorradius,
                          majorradiussq, minorradiussq, direction, point):
    dist = 0
    if (direction[0] == 0) and (direction[1] == 0):
        # drop
        minlsq = (majorradius - minorradius)**2
        maxlsq = (majorradius + minorradius)**2
        l_sq = (point[0] - center[0])**2 + (point[1] - center[1])**2
        if (l_sq < minlsq + epsilon) or (l_sq > maxlsq - epsilon):
            return (None, None, INFINITE)
        l_len = sqrt(l_sq)
        z_sq = minorradiussq - (majorradius - l_len)**2
        if z_sq < 0:
            return (None, None, INFINITE)
        z = sqrt(z_sq)
        ccp = (point[0], point[1], center[2] - z)
        dist = ccp[2] - point[2]
    elif direction[2] == 0:
        # push
        z = point[2] - center[2]
        if abs(z) > minorradius - epsilon:
            return (None, None, INFINITE)
        l_len = majorradius + sqrt(minorradiussq - z * z)
        n = pcross(axis, direction)
        d = pdot(n, point) - pdot(n, center)
        if abs(d) > l_len - epsilon:
            return (None, None, INFINITE)
        a = sqrt(l_len * l_len - d * d)
        ccp = padd(padd(center, pmul(n, d)), pmul(direction, a))
        ccp = (ccp[0], ccp[1], point[2])
        dist = pdot(psub(point, ccp), direction)
    else:
        # general case
        x = psub(point, center)
        v = pmul(direction, -1)
        x_x = pdot(x, x)
        x_v = pdot(x, v)
        x1 = (x[0], x[1], 0)
        v1 = (v[0], v[1], 0)
        x1_x1 = pdot(x1, x1)
        x1_v1 = pdot(x1, v1)
        v1_v1 = pdot(v1, v1)
        r2_major = majorradiussq
        r2_minor = minorradiussq
        a = 1.0
        b = 4 * x_v
        c = 2 * (x_x + 2 * x_v**2 +
                 (r2_major - r2_minor) - 2 * r2_major * v1_v1)
        d = 4 * (x_x * x_v + x_v *
                 (r2_major - r2_minor) - 2 * r2_major * x1_v1)
        e = ((x_x)**2 + 2 * x_x * (r2_major - r2_minor) +
             (r2_major - r2_minor)**2 - 4 * r2_major * x1_x1)
        r = poly4_roots(a, b, c, d, e)
        if not r:
            return (None, None, INFINITE)
        else:
            l_len = min(r)
        ccp = padd(point, pmul(direction, -l_len))
        dist = l_len
    return (ccp, point, dist)
コード例 #3
0
ファイル: MotionGrid.py プロジェクト: TurBoss/pycam
def get_lines_layer(lines,
                    z,
                    last_z=None,
                    step_width=None,
                    milling_style=MillingStyle.CONVENTIONAL):
    get_proj_point = lambda proj_point: (proj_point[0], proj_point[1], z)
    projected_lines = []
    for line in lines:
        if (last_z is not 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[2]) / (line.p2[2] - line.p1[2])
            plane_point = padd(line.p1, pmul(line.vector, factor))
            if line.p1[2] < 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((0, 0, last_z), (0, 0, 1, 'v'))
            cp = plane.intersect_point(line.dir, line.p1)[0]
            # we can be sure that there is an intersection
            if line.p1[2] > 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 = padd(line.p1, pmul(line.dir, step))
                points.append(next_point)
        yield points
コード例 #4
0
def intersect_sphere_plane(center, radius, direction, triangle):
    # let n be the normal to the plane
    n = triangle.normal
    if pdot(n, direction) == 0:
        return (None, None, INFINITE)
    # the cutter contact point is on the sphere, where the surface normal is n
    if pdot(n, direction) < 0:
        ccp = psub(center, pmul(n, radius))
    else:
        ccp = padd(center, pmul(n, radius))
    # intersect the plane with a line through the contact point
    (cp, d) = triangle.plane.intersect_point(direction, ccp)
    return (ccp, cp, d)
コード例 #5
0
def intersect_cylinder_point(center, axis, radius, radiussq, direction, point):
    # take a plane along direction and axis
    n = pnormalized(pcross(direction, axis))
    # distance of the point to this plane
    d = pdot(n, point) - pdot(n, center)
    if abs(d) > radius - epsilon:
        return (None, None, INFINITE)
    # ccl is on cylinder
    d2 = sqrt(radiussq - d * d)
    ccl = padd(padd(center, pmul(n, d)), pmul(direction, d2))
    # take plane through ccl and axis
    plane = Plane(ccl, direction)
    # intersect point with plane
    (ccp, l) = plane.intersect_point(direction, point)
    return (ccp, point, -l)
コード例 #6
0
ファイル: Filters.py プロジェクト: patyork/pycam
 def filter_toolpath(self, toolpath):
     feedrate = min_feedrate = 1
     new_path = []
     last_pos = None
     limit = self.settings["timelimit"]
     duration = 0
     for move_type, args in toolpath:
         if move_type in (MOVE_STRAIGHT, MOVE_STRAIGHT_RAPID):
             if last_pos:
                 new_distance = pdist(args, last_pos)
                 new_duration = new_distance / max(feedrate, min_feedrate)
                 if (new_duration > 0) and (duration + new_duration >
                                            limit):
                     partial = (limit - duration) / new_duration
                     destination = padd(last_pos,
                                        pmul(psub(args, last_pos), partial))
                     duration = limit
                 else:
                     destination = args
                     duration += new_duration
             else:
                 destination = args
             new_path.append((move_type, destination))
             last_pos = args
         if (move_type == MACHINE_SETTING) and (args[0] == "feedrate"):
             feedrate = args[1]
         if duration >= limit:
             break
     return new_path
コード例 #7
0
ファイル: OpenGLViewModel.py プロジェクト: jayMcBee/pycam
 def calc_normal(main, normals):
     suitable = (0, 0, 0, 'v')
     for normal, weight in normals:
         dot = pdot(main, normal)
         if dot > 0:
             suitable = padd(suitable, pmul(normal, weight * dot))
     return pnormalized(suitable)
コード例 #8
0
ファイル: x3d.py プロジェクト: valeriob01/pycam
def get_x3d_cone(start: tuple, end: tuple, position: float, length: float, radius: float,
                 color: tuple):
    # by default the X3D cone points along the y axis
    original_vector = (0, 1, 0)
    line_vector = psub(end, start)
    line_normalized = pnormalized(line_vector)
    # the cone position is at its bottom
    bottom_position = padd(start, pmul(line_vector, position))
    # handling of corner cases
    if pnormsq(pcross(original_vector, line_normalized)) == 0:
        # Both vectors are aligned - but maybe point into different directions.
        rotation_axis = (1, 0, 0)
        rotation_angle = math.pi if original_vector != line_normalized else 0
    else:
        # Both vectors are not aligned.  Use a normal rotation.
        # Rotate around the vector in the vector in the middle by 180 degrees.
        rotation_axis = padd(original_vector, line_normalized)
        rotation_angle = math.pi
    yield ('<Transform translation="{:f} {:f} {:f}" rotation="{:f} {:f} {:f} {:f}">'
           .format(*bottom_position, *rotation_axis, rotation_angle))
    yield "<Shape>"
    yield "<Appearance>"
    yield ('<Material diffuseColor="{:f} {:f} {:f}" transparency="{:f}" />'
           .format(color["red"], color["green"], color["blue"], 1 - color["alpha"]))
    yield "</Appearance>"
    yield '<Cone bottomRadius="{:f}" topRadius="0" height="{:f}" />'.format(radius, length)
    yield "</Shape>"
    yield "</Transform>"
コード例 #9
0
ファイル: Filters.py プロジェクト: stevegt/pycam
 def filter_toolpath(self, toolpath):
     feedrate = min_feedrate = 1
     new_path = []
     last_pos = None
     limit = self.settings["timelimit"]
     duration = 0
     for move_type, args in toolpath:
         if move_type in (MOVE_STRAIGHT, MOVE_STRAIGHT_RAPID):
             if last_pos:
                 new_distance = pdist(args, last_pos)
                 new_duration = new_distance / max(feedrate, min_feedrate)
                 if (new_duration > 0) and (duration + new_duration > limit):
                     partial = (limit - duration) / new_duration
                     destination = padd(last_pos, pmul(psub(args, last_pos), partial))
                     duration = limit
                 else:
                     destination = args
                     duration += new_duration
             else:
                 destination = args
             new_path.append((move_type, destination))
             last_pos = args
         if (move_type == MACHINE_SETTING) and (args[0] == "feedrate"):
             feedrate = args[1]
         if duration >= limit:
             break
     return new_path
コード例 #10
0
 def closest_point(self, p):
     v = self.dir
     if v is None:
         # for zero-length lines
         return self.p1
     dist = pdot(self.p1, v) - pdot(p, v)
     return psub(self.p1, pmul(v, dist))
コード例 #11
0
ファイル: Filters.py プロジェクト: jtpedersen/pycam
 def filter_toolpath(self, toolpath):
     feedrate = min_feedrate = 1
     new_path = []
     last_pos = None
     limit = self.settings["timelimit"]
     duration = 0
     for step in toolpath:
         if step.action in MOVES_LIST:
             if last_pos:
                 new_distance = pdist(step.position, last_pos)
                 new_duration = new_distance / max(feedrate, min_feedrate)
                 if (new_duration > 0) and (duration + new_duration > limit):
                     partial = (limit - duration) / new_duration
                     destination = padd(last_pos, pmul(psub(step.position, last_pos), partial))
                     duration = limit
                 else:
                     destination = step.position
                     duration += new_duration
             else:
                 destination = step.position
             new_path.append(ToolpathSteps.get_step_class_by_action(step.action)(destination))
             last_pos = step.position
         if (step.action == MACHINE_SETTING) and (step.key == "feedrate"):
             feedrate = step.value
         if duration >= limit:
             break
     return new_path
コード例 #12
0
def intersect_circle_plane(center, radius, direction, triangle):
    # let n be the normal to the plane
    n = triangle.normal
    if pdot(n, direction) == 0:
        return (None, None, INFINITE)
    # project onto z=0
    n2 = (n[0], n[1], 0)
    if pnorm(n2) == 0:
        (cp, d) = triangle.plane.intersect_point(direction, center)
        ccp = psub(cp, pmul(direction, d))
        return (ccp, cp, d)
    n2 = pnormalized(n2)
    # the cutter contact point is on the circle, where the surface normal is n
    ccp = padd(center, pmul(n2, -radius))
    # intersect the plane with a line through the contact point
    (cp, d) = triangle.plane.intersect_point(direction, ccp)
    return (ccp, cp, d)
コード例 #13
0
def _add_cuboid_to_model(model, start, direction, height, width):
    up = pmul((0, 0, 1, 'v'), height)
    ortho_dir = pnormalized(pcross(direction, up))
    start1 = padd(start, pmul(ortho_dir, -width / 2))
    start2 = padd(start1, up)
    start3 = padd(start2, pmul(ortho_dir, width))
    start4 = psub(start3, up)
    end1 = padd(start1, direction)
    end2 = padd(start2, direction)
    end3 = padd(start3, direction)
    end4 = padd(start4, 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)
コード例 #14
0
ファイル: SphericalCutter.py プロジェクト: valeriob01/pycam
 def intersect_sphere_point(self, direction, point, start=None):
     if start is None:
         start = self.location
     (ccp, cp, l) = intersect_sphere_point(padd(psub(start, self.location), self.center),
                                           self.distance_radius, self.distance_radiussq,
                                           direction, point)
     # offset intersection
     cl = None
     if cp:
         cl = padd(start, pmul(direction, l))
     return (cl, ccp, cp, l)
コード例 #15
0
def intersect_torus_plane(center, axis, majorradius, minorradius, direction,
                          triangle):
    # take normal to the plane
    n = triangle.normal
    if pdot(n, direction) == 0:
        return (None, None, INFINITE)
    if pdot(n, axis) == 1:
        return (None, None, INFINITE)
    # find place on torus where surface normal is n
    b = pmul(n, -1)
    z = axis
    a = psub(b, pmul(z, pdot(z, b)))
    a_sq = pnormsq(a)
    if a_sq <= 0:
        return (None, None, INFINITE)
    a = pdiv(a, sqrt(a_sq))
    ccp = padd(padd(center, pmul(a, majorradius)), pmul(b, minorradius))
    # find intersection with plane
    (cp, l) = triangle.plane.intersect_point(direction, ccp)
    return (ccp, cp, l)
コード例 #16
0
 def get_shifted_vertex(self, index, offset):
     p1 = self._points[index]
     p2 = self._points[(index + 1) % len(self._points)]
     cross_offset = pnormalized(pcross(psub(p2, p1), self.plane.n))
     bisector_normalized = self.get_bisector(index)
     factor = pdot(cross_offset, bisector_normalized)
     if factor != 0:
         bisector_sized = pmul(bisector_normalized, offset / factor)
         return padd(p1, bisector_sized)
     else:
         return p2
コード例 #17
0
 def intersect_cylinder_point(self, direction, point, start=None):
     if start is None:
         start = self.location
     (ccp, cp, l) = intersect_cylinder_point(
         padd(psub(start, self.location), self.center), self.axis,
         self.distance_radius, self.distance_radiussq, direction, point)
     # offset intersection
     if ccp:
         cl = padd(start, pmul(direction, l))
         return (cl, ccp, cp, l)
     return (None, None, None, INFINITE)
コード例 #18
0
ファイル: Plane.py プロジェクト: zancas/pycam
 def intersect_point(self, direction, point):
     if (direction is not None) and (pnorm(direction) != 1):
         # calculations will go wrong, if the direction is not a unit vector
         direction = pnormalized(direction)
     if direction is None:
         return (None, INFINITE)
     denom = pdot(self.n, direction)
     if denom == 0:
         return (None, INFINITE)
     l = -(pdot(self.n, point) - pdot(self.n, self.p)) / denom
     cp = padd(point, pmul(direction, l))
     return (cp, l)
コード例 #19
0
 def get_intersection(self, line, infinite_lines=False):
     """ Get the point of intersection between two lines. Intersections
     outside the length of these lines are ignored.
     Returns (None, None) if no valid intersection was found.
     Otherwise the result is (CollisionPoint, distance). Distance is between
     0 and 1.
     """
     x1, x2, x3, x4 = self.p1, self.p2, line.p1, line.p2
     a = psub(x2, x1)
     b = psub(x4, x3)
     c = psub(x3, x1)
     # see http://mathworld.wolfram.com/Line-LineIntersection.html (24)
     try:
         factor = pdot(pcross(c, b), pcross(a, b)) / pnormsq(pcross(a, b))
     except ZeroDivisionError:
         # lines are parallel
         # check if they are _one_ line
         if pnorm(pcross(a, c)) != 0:
             # the lines are parallel with a distance
             return None, None
         # the lines are on one straight
         candidates = []
         if self.is_point_inside(x3):
             candidates.append((x3, pnorm(c) / pnorm(a)))
         elif self.is_point_inside(x4):
             candidates.append((x4, pdist(line.p2, self.p1) / pnorm(a)))
         elif line.is_point_inside(x1):
             candidates.append((x1, 0))
         elif line.is_point_inside(x2):
             candidates.append((x2, 1))
         else:
             return None, None
         # return the collision candidate with the lowest distance
         candidates.sort(key=lambda collision: collision[1])
         return candidates[0]
     if infinite_lines or (-epsilon <= factor <= 1 + epsilon):
         intersec = padd(x1, pmul(a, factor))
         # check if the intersection is between x3 and x4
         if infinite_lines:
             return intersec, factor
         elif ((min(x3[0], x4[0]) - epsilon <= intersec[0] <=
                max(x3[0], x4[0]) + epsilon)
               and (min(x3[1], x4[1]) - epsilon <= intersec[1] <=
                    max(x3[1], x4[1]) + epsilon)
               and (min(x3[2], x4[2]) - epsilon <= intersec[2] <=
                    max(x3[2], x4[2]) + epsilon)):
             return intersec, factor
         else:
             # intersection outside of the length of line(x3, x4)
             return None, None
     else:
         # intersection outside of the length of line(x1, x2)
         return None, None
コード例 #20
0
 def draw_direction_cone_mesh(self,
                              p1,
                              p2,
                              position=0.5,
                              precision=12,
                              size=0.1):
     distance = psub(p2, p1)
     length = pnorm(distance)
     direction = pnormalized(distance)
     if direction is None or length < 0.5:
         # zero-length line
         return []
     cone_length = length * size
     cone_radius = cone_length / 3.0
     bottom = padd(p1, pmul(psub(p2, p1), position - size / 2))
     top = padd(p1, pmul(psub(p2, p1), position + size / 2))
     # generate a a line perpendicular to this line, cross product is good at this
     cross = pcross(direction, (0, 0, -1))
     conepoints = []
     if pnorm(cross) != 0:
         # The line direction is not in line with the z axis.
         conep1 = padd(bottom, pmul(cross, cone_radius))
         conepoints = [
             self._rotate_point(conep1, bottom, direction, x)
             for x in numpy.linspace(0, 2 * math.pi, precision)
         ]
     else:
         # Z axis
         # just add cone radius to the x axis and rotate the point
         conep1 = (bottom[0] + cone_radius, bottom[1], bottom[2])
         conepoints = [
             self._rotate_point(conep1, p1, direction, x)
             for x in numpy.linspace(0, 2 * math.pi, precision)
         ]
     triangles = [(top, conepoints[idx], conepoints[idx + 1])
                  for idx in range(len(conepoints) - 1)]
     return triangles
コード例 #21
0
def intersect_cylinder_line(center, axis, radius, radiussq, direction, edge):
    d = edge.dir
    # take a plane throught the line and along the cylinder axis (1)
    n = pcross(d, axis)
    if pnorm(n) == 0:
        # no contact point, but should check here if cylinder *always*
        # intersects line...
        return (None, None, INFINITE)
    n = pnormalized(n)
    # the contact line between the cylinder and this plane (1)
    # is where the surface normal is perpendicular to the plane
    # so line := ccl + \lambda * axis
    if pdot(n, direction) < 0:
        ccl = psub(center, pmul(n, radius))
    else:
        ccl = padd(center, pmul(n, radius))
    # now extrude the contact line along the direction, this is a plane (2)
    n2 = pcross(direction, axis)
    if pnorm(n2) == 0:
        # no contact point, but should check here if cylinder *always*
        # intersects line...
        return (None, None, INFINITE)
    n2 = pnormalized(n2)
    plane1 = Plane(ccl, n2)
    # intersect this plane with the line, this gives us the contact point
    (cp, l) = plane1.intersect_point(d, edge.p1)
    if not cp:
        return (None, None, INFINITE)
    # now take a plane through the contact line and perpendicular to the
    # direction (3)
    plane2 = Plane(ccl, direction)
    # the intersection of this plane (3) with the line through the contact point
    # gives us the cutter contact point
    (ccp, l) = plane2.intersect_point(direction, cp)
    cp = padd(ccp, pmul(direction, -l))
    return (ccp, cp, -l)
コード例 #22
0
ファイル: OpenGLWindow.py プロジェクト: yummyburger/pycam
 def auto_adjust_distance(self):
     v = self.view
     # adjust the distance to get a view of the whole object
     low_high = list(zip(*self._get_low_high_dims()))
     if (None, None) in low_high:
         return
     max_dim = max([high - low for low, high in low_high])
     distv = pnormalized((v["distance"][0], v["distance"][1], v["distance"][2]))
     # The multiplier "1.25" is based on experiments. 1.414 (sqrt(2)) should
     # be roughly sufficient for showing the diagonal of any model.
     distv = pmul(distv, (max_dim * 1.25) / number(math.sin(v["fovy"] / 2)))
     self.view["distance"] = distv
     # Adjust the "far" distance for the camera to make sure, that huge
     # models (e.g. x=1000) are still visible.
     self.view["zfar"] = 100 * max_dim
コード例 #23
0
ファイル: utils.py プロジェクト: yummyburger/pycam
def get_bisector(p1, p2, p3, up_vector):
    """ Calculate the bisector between p1, p2 and p3, whereas p2 is the origin
    of the angle.
    """
    d1 = pnormalized(psub(p2, p1))
    d2 = pnormalized(psub(p2, p3))
    bisector_dir = pnormalized(padd(d1, d2))
    if bisector_dir is None:
        # the two vectors pointed to opposite directions
        bisector_dir = pnormalized(pcross(d1, up_vector))
    else:
        skel_up_vector = pcross(bisector_dir, psub(p2, p1))
        if pdot(up_vector, skel_up_vector) < 0:
            # reverse the skeleton vector to point outwards
            bisector_dir = pmul(bisector_dir, -1)
    return bisector_dir
コード例 #24
0
ファイル: ContourFollow.py プロジェクト: yummyburger/pycam
def get_shifted_waterline(up_vector, waterline, cutter_location):
    # Project the waterline and the cutter location down to the slice plane.
    # This is necessary for calculating the horizontal distance between the
    # cutter and the triangle waterline.
    plane = Plane(cutter_location, up_vector)
    wl_proj = plane.get_line_projection(waterline)
    if wl_proj.len < epsilon:
        return None
    offset = wl_proj.dist_to_point(cutter_location)
    if offset < epsilon:
        return wl_proj
    # shift both ends of the waterline towards the cutter location
    shift = psub(cutter_location, wl_proj.closest_point(cutter_location))
    # increase the shift width slightly to avoid "touch" collisions
    shift = pmul(shift, 1.0 + epsilon)
    shifted_waterline = Line(padd(wl_proj.p1, shift), padd(wl_proj.p2, shift))
    return shifted_waterline
コード例 #25
0
def get_support_distributed(model,
                            z_plane,
                            average_distance,
                            min_bridges_per_polygon,
                            thickness,
                            height,
                            length,
                            bounds=None,
                            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((0, 0, max(model.minz, z_plane)), (0, 0, 1, 'v')))
    if model:
        model = model.get_flat_projection(
            Plane((0, 0, z_plane), (0, 0, 1, 'v')))
    if model and bounds:
        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, pmul(direction, length), height,
                                 thickness)
    return result
コード例 #26
0
def intersect_sphere_point(center, radius, radiussq, direction, point):
    # line equation
    # (1) x = p_0 + \lambda * d
    # sphere equation
    # (2) (x-x_0)^2 = R^2
    # (1) in (2) gives a quadratic in \lambda
    p0_x0 = psub(center, point)
    a = pnormsq(direction)
    b = 2 * pdot(p0_x0, direction)
    c = pnormsq(p0_x0) - radiussq
    d = b * b - 4 * a * c
    if d < 0:
        return (None, None, INFINITE)
    if a < 0:
        l = (-b + sqrt(d)) / (2 * a)
    else:
        l = (-b - sqrt(d)) / (2 * a)
    # cutter contact point
    ccp = padd(point, pmul(direction, -l))
    return (ccp, point, l)
コード例 #27
0
def intersect_circle_line(center, axis, radius, radiussq, direction, edge):
    # make a plane by sliding the line along the direction (1)
    d = edge.dir
    if pdot(d, axis) == 0:
        if pdot(direction, axis) == 0:
            return (None, None, INFINITE)
        plane = Plane(center, axis)
        (p1, l) = plane.intersect_point(direction, edge.p1)
        (p2, l) = plane.intersect_point(direction, edge.p2)
        pc = Line(p1, p2).closest_point(center)
        d_sq = pnormsq(psub(pc, center))
        if d_sq >= radiussq:
            return (None, None, INFINITE)
        a = sqrt(radiussq - d_sq)
        d1 = pdot(psub(p1, pc), d)
        d2 = pdot(psub(p2, pc), d)
        ccp = None
        cp = None
        if abs(d1) < a - epsilon:
            ccp = p1
            cp = psub(p1, pmul(direction, l))
        elif abs(d2) < a - epsilon:
            ccp = p2
            cp = psub(p2, pmul(direction, l))
        elif ((d1 < -a + epsilon) and (d2 > a - epsilon)) \
                or ((d2 < -a + epsilon) and (d1 > a - epsilon)):
            ccp = pc
            cp = psub(pc, pmul(direction, l))
        return (ccp, cp, -l)
    n = pcross(d, direction)
    if pnorm(n) == 0:
        # no contact point, but should check here if circle *always* intersects
        # line...
        return (None, None, INFINITE)
    n = pnormalized(n)
    # take a plane through the base
    plane = Plane(center, axis)
    # intersect base with line
    (lp, l) = plane.intersect_point(d, edge.p1)
    if not lp:
        return (None, None, INFINITE)
    # intersection of 2 planes: lp + \lambda v
    v = pcross(axis, n)
    if pnorm(v) == 0:
        return (None, None, INFINITE)
    v = pnormalized(v)
    # take plane through intersection line and parallel to axis
    n2 = pcross(v, axis)
    if pnorm(n2) == 0:
        return (None, None, INFINITE)
    n2 = pnormalized(n2)
    # distance from center to this plane
    dist = pdot(n2, center) - pdot(n2, lp)
    distsq = dist * dist
    if distsq > radiussq - epsilon:
        return (None, None, INFINITE)
    # must be on circle
    dist2 = sqrt(radiussq - distsq)
    if pdot(d, axis) < 0:
        dist2 = -dist2
    ccp = psub(center, psub(pmul(n2, dist), pmul(v, dist2)))
    plane = Plane(edge.p1, pcross(pcross(d, direction), d))
    (cp, l) = plane.intersect_point(direction, ccp)
    return (ccp, cp, l)
コード例 #28
0
ファイル: MotionGrid.py プロジェクト: TurBoss/pycam
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 = psub(end, start)
                # TODO: ellipse would be better than arc
                offset = pmul(pnormalized(edge_vector), radius)
                if previous:
                    start = padd(start, offset)
                    center = padd(previous, offset)
                    up_vector = pnormalized(
                        pcross(psub(previous, center), psub(start, center)))
                    north = padd(center, (1.0, 0.0, 0.0, 'v'))
                    angle_start = get_angle_pi(
                        north, center, previous, up_vector,
                        pi_factor=True) * 180.0
                    angle_end = 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[2] < 0:
                        angle_start, angle_end = -angle_end, -angle_start
                    arc_points = get_points_of_arc(center, radius, angle_start,
                                                   angle_end)
                    if up_vector[2] < 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 = (p1_coord[0], p1_coord[1], z)
                        p2 = (p2_coord[0], p2_coord[1], z)
                        rounded_lines.append((p1, p2))
                if index != len(lines) - 1:
                    end = psub(end, 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 = padd(line.p1, pmul(line.dir, step))
                    points.append(next_point)
            if reverse:
                points.reverse()
            yield points
コード例 #29
0
ファイル: Model.py プロジェクト: songwenbin247/pycam
 def _shift_to_origin(self, position, callback=None):
     if position != Point3D(0, 0, 0):
         self.shift(*(pmul(position, -1)), callback=callback)
コード例 #30
0
ファイル: utils.py プロジェクト: yummyburger/pycam
def get_bezier_lines(points_with_bulge, segments=32):
    # TODO: add a recursive algorithm for more than two points
    if len(points_with_bulge) != 2:
        return []
    else:
        result_points = []
        p1, bulge1 = points_with_bulge[0]
        p2, bulge2 = points_with_bulge[1]
        if not bulge1 and not bulge2:
            # straight line
            return [Line(p1, p2)]
        straight_dir = pnormalized(psub(p2, p1))
        bulge1 = math.atan(bulge1)
        rot_matrix = Matrix.get_rotation_matrix_axis_angle((0, 0, 1),
                                                           -2 * bulge1,
                                                           use_radians=True)
        dir1_mat = Matrix.multiply_vector_matrix(
            (straight_dir[0], straight_dir[1], straight_dir[2]), rot_matrix)
        dir1 = (dir1_mat[0], dir1_mat[1], dir1_mat[2], 'v')
        if bulge2 is None:
            bulge2 = bulge1
        else:
            bulge2 = math.atan(bulge2)
        rot_matrix = Matrix.get_rotation_matrix_axis_angle((0, 0, 1),
                                                           2 * bulge2,
                                                           use_radians=True)
        dir2_mat = Matrix.multiply_vector_matrix(
            (straight_dir[0], straight_dir[1], straight_dir[2]), rot_matrix)
        dir2 = (dir2_mat[0], dir2_mat[1], dir2_mat[2], 'v')
        # interpretation of bulge1 and bulge2:
        # /// taken from http://paulbourke.net/dataformats/dxf/dxf10.html ///
        # The bulge is the tangent of 1/4 the included angle for an arc
        # segment, made negative if the arc goes clockwise from the start
        # point to the end point; a bulge of 0 indicates a straight segment,
        # and a bulge of 1 is a semicircle.
        alpha = 2 * (abs(bulge1) + abs(bulge2))
        dist = pdist(p2, p1)
        # calculate the radius of the circumcircle - avoiding divide-by-zero
        if (abs(alpha) < epsilon) or (abs(math.pi - alpha) < epsilon):
            radius = dist / 2.0
        else:
            # see http://en.wikipedia.org/wiki/Law_of_sines
            radius = abs(dist / math.sin(alpha / 2.0)) / 2.0
        # The calculation of "factor" is based on random guessing - but it
        # seems to work well.
        factor = 4 * radius * math.tan(alpha / 4.0)
        dir1 = pmul(dir1, factor)
        dir2 = pmul(dir2, factor)
        for index in range(segments + 1):
            # t: 0..1
            t = float(index) / segments
            # see: http://en.wikipedia.org/wiki/Cubic_Hermite_spline
            p = padd(
                pmul(p1, 2 * t**3 - 3 * t**2 + 1),
                padd(
                    pmul(dir1, t**3 - 2 * t**2 + t),
                    padd(pmul(p2, -2 * t**3 + 3 * t**2),
                         pmul(dir2, t**3 - t**2))))
            result_points.append(p)
        # create lines
        result = []
        for index in range(len(result_points) - 1):
            result.append(Line(result_points[index], result_points[index + 1]))
        return result
コード例 #31
0
 def point_with_length_multiply(self, l):
     return padd(self.p1, pmul(self.dir, l * self.len))