예제 #1
0
파일: Model.py 프로젝트: zancas/pycam
 def calculate_point_height(self, x, y, func):
     point = (x, y, self.outer.minz)
     if not self.outer.is_point_inside(point):
         return None
     for poly in self.inner:
         if poly.is_point_inside(point):
             return None
     point = (x, y, self.outer.minz)
     line_distances = []
     for line in self.lines:
         cross_product = pcross(line.dir, psub(point, line.p1))
         if cross_product[2] > 0:
             close_points = []
             close_point = line.closest_point(point)
             if not line.is_point_inside(close_point):
                 close_points.append(line.p1)
                 close_points.append(line.p2)
             else:
                 close_points.append(close_point)
             for p in close_points:
                 direction = psub(point, p)
                 dist = pnorm(direction)
                 line_distances.append(dist)
         elif cross_product[2] == 0:
             # the point is on the line
             line_distances.append(0.0)
             # no other line can get closer than this
             break
         else:
             # the point is in the left of this line
             pass
     line_distances.sort()
     return self.z_level + func(line_distances[0])
예제 #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
파일: utils.py 프로젝트: yummyburger/pycam
def get_angle_pi(p1, p2, p3, up_vector, pi_factor=False):
    """ calculate the angle between three points
    Visualization:
            p3
           /
          /
         /\
        /  \
      p2--------p1
    The result is in a range between 0 and 2*PI.
    """
    d1 = pnormalized(psub(p2, p1))
    d2 = pnormalized(psub(p2, p3))
    if (d1 is None) or (d2 is None):
        return 2 * math.pi
    angle = math.acos(pdot(d1, d2))
    # check the direction of the points (clockwise/anti)
    # The code is taken from Polygon.get_area
    value = [0, 0, 0]
    for (pa, pb) in ((p1, p2), (p2, p3), (p3, p1)):
        value[0] += pa[1] * pb[2] - pa[2] * pb[1]
        value[1] += pa[2] * pb[0] - pa[0] * pb[2]
        value[2] += pa[0] * pb[1] - pa[1] * pb[0]
    area = up_vector[0] * value[0] + up_vector[1] * value[1] + up_vector[
        2] * value[2]
    if area > 0:
        # The points are in anti-clockwise order. Thus the angle is greater
        # than 180 degree.
        angle = 2 * math.pi - angle
    if pi_factor:
        # the result is in the range of 0..2
        return angle / math.pi
    else:
        return angle
예제 #4
0
 def reset_cache(self):
     self.minx = min(self.p1[0], self.p2[0], self.p3[0])
     self.miny = min(self.p1[1], self.p2[1], self.p3[1])
     self.minz = min(self.p1[2], self.p2[2], self.p3[2])
     self.maxx = max(self.p1[0], self.p2[0], self.p3[0])
     self.maxy = max(self.p1[1], self.p2[1], self.p3[1])
     self.maxz = max(self.p1[2], self.p2[2], self.p3[2])
     self.e1 = Line(self.p1, self.p2)
     self.e2 = Line(self.p2, self.p3)
     self.e3 = Line(self.p3, self.p1)
     # calculate normal, if p1-p2-pe are in clockwise order
     if self.normal is None:
         self.normal = pnormalized(
             pcross(psub(self.p3, self.p1), psub(self.p2, self.p1)))
     if not len(self.normal) > 3:
         self.normal = (self.normal[0], self.normal[1], self.normal[2], 'v')
     self.center = pdiv(padd(padd(self.p1, self.p2), self.p3), 3)
     self.plane = Plane(self.center, self.normal)
     # calculate circumcircle (resulting in radius and middle)
     denom = pnorm(pcross(psub(self.p2, self.p1), psub(self.p3, self.p2)))
     self.radius = (pdist(self.p2, self.p1) * pdist(self.p3, self.p2) *
                    pdist(self.p3, self.p1)) / (2 * denom)
     self.radiussq = self.radius**2
     denom2 = 2 * denom * denom
     alpha = pdist_sq(self.p3, self.p2) * pdot(psub(
         self.p1, self.p2), psub(self.p1, self.p3)) / denom2
     beta = pdist_sq(self.p1, self.p3) * pdot(psub(
         self.p2, self.p1), psub(self.p2, self.p3)) / denom2
     gamma = pdist_sq(self.p1, self.p2) * pdot(psub(
         self.p3, self.p1), psub(self.p3, self.p2)) / denom2
     self.middle = (self.p1[0] * alpha + self.p2[0] * beta +
                    self.p3[0] * gamma, self.p1[1] * alpha +
                    self.p2[1] * beta + self.p3[1] * gamma,
                    self.p1[2] * alpha + self.p2[2] * beta +
                    self.p3[2] * gamma)
예제 #5
0
 def is_point_inside(self, p):
     if (p == self.p1) or (p == self.p2):
         # these conditions are not covered by the code below
         return True
     dir1 = pnormalized(psub(p, self.p1))
     dir2 = pnormalized(psub(self.p2, p))
     # True if the two parts of the line have the same direction or if the
     # point is self.p1 or self.p2.
     return (dir1 == dir2 == self.dir) or (dir1 is None) or (dir2 is None)
예제 #6
0
 def intersect_sphere_edge(self, direction, edge, start=None):
     (cl, ccp, cp, l) = self.intersect_sphere_line(direction, edge, start=start)
     if cp:
         # check if the contact point is between the endpoints
         d = psub(edge.p2, edge.p1)
         m = pdot(psub(cp, edge.p1), d)
         if (m < -epsilon) or (m > pnormsq(d) + epsilon):
             return (None, INFINITE, None)
     return (cl, l, cp)
예제 #7
0
 def intersect_circle_plane(self, direction, triangle, start=None):
     if start is None:
         start = self.location
     ccp, cp, l = intersect_circle_plane(start, self.distance_majorradius,
                                         direction, triangle)
     # offset intersection
     if ccp:
         cl = psub(cp, psub(ccp, start))
         return (cl, ccp, cp, l)
     return (None, None, None, INFINITE)
예제 #8
0
 def intersect_circle_plane(self, direction, triangle, start=None):
     if start is None:
         start = self.location
     (ccp, cp, d) = intersect_circle_plane(
         padd(psub(start, self.location), self.center),
         self.distance_radius, direction, triangle)
     if ccp and cp:
         cl = padd(cp, psub(start, ccp))
         return (cl, ccp, cp, d)
     return (None, None, None, INFINITE)
예제 #9
0
 def intersect_circle_line(self, direction, edge, start=None):
     if start is None:
         start = self.location
     (ccp, cp, l) = intersect_circle_line(
         padd(psub(start, self.location), self.center), self.axis,
         self.distance_radius, self.distance_radiussq, direction, edge)
     if ccp:
         cl = padd(cp, psub(start, ccp))
         return (cl, ccp, cp, l)
     return (None, None, None, INFINITE)
예제 #10
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, psub(cp, ccp))
         return (cl, ccp, cp, l)
     return (None, None, None, INFINITE)
예제 #11
0
 def intersect_sphere_line(self, direction, edge, start=None):
     if start is None:
         start = self.location
     (ccp, cp, l) = intersect_sphere_line(padd(psub(start, self.location), self.center),
                                          self.distance_radius, self.distance_radiussq,
                                          direction, edge)
     # offset intersection
     if ccp:
         cl = psub(cp, psub(ccp, start))
         return (cl, ccp, cp, l)
     return (None, None, None, INFINITE)
예제 #12
0
 def intersect_torus_plane(self, direction, triangle, start=None):
     if start is None:
         start = self.location
     (ccp, cp, l) = intersect_torus_plane(
         padd(psub(start, self.location),
              self.center), self.axis, self.distance_majorradius,
         self.distance_minorradius, direction, triangle)
     if cp:
         cl = padd(cp, psub(start, ccp))
         return (cl, ccp, cp, l)
     return (None, None, None, INFINITE)
예제 #13
0
 def intersect_circle_line(self, direction, edge, start=None):
     if start is None:
         start = self.location
     (ccp, cp, l_len) = intersect_circle_line(start, self.axis,
                                              self.distance_majorradius,
                                              self.distance_majorradiussq,
                                              direction, edge)
     if ccp:
         cl = psub(cp, psub(ccp, start))
         return (cl, ccp, cp, l_len)
     return (None, None, None, INFINITE)
예제 #14
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
예제 #15
0
 def intersect_torus_point(self, direction, point, start=None):
     if start is None:
         start = self.location
     (ccp, cp, l) = intersect_torus_point(
         padd(psub(start, self.location),
              self.center), self.axis, self.distance_majorradius,
         self.distance_minorradius, self.distance_majorradiussq,
         self.distance_minorradiussq, direction, point)
     if ccp:
         cl = padd(point, psub(start, ccp))
         return (cl, ccp, point, l)
     return (None, None, None, INFINITE)
예제 #16
0
 def intersect_cylinder_edge(self, direction, edge, start=None):
     if start is None:
         start = self.location
     (cl, ccp, cp, l) = self.intersect_cylinder_line(direction,
                                                     edge,
                                                     start=start)
     if not ccp:
         return (None, INFINITE, None)
     m = pdot(psub(cp, edge.p1), edge.dir)
     if (m < -epsilon) or (m > edge.len + epsilon):
         return (None, INFINITE, None)
     if ccp[2] < padd(psub(start, self.location), self.center)[2]:
         return (None, INFINITE, None)
     return (cl, l, cp)
예제 #17
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
예제 #18
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
예제 #19
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
예제 #20
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))
예제 #21
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>"
예제 #22
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
예제 #23
0
 def append(self, point):
     # Sort the points in positive x/y direction - otherwise the
     # PolygonExtractor breaks.
     if self.points and (pdot(psub(point, self.points[0]), self.__forward) <
                         0):
         self.points.insert(0, point)
     else:
         self.points.append(point)
예제 #24
0
def intersect_circle_point(center, axis, radius, radiussq, direction, point):
    # take a plane through the base
    plane = Plane(center, axis)
    # intersect with line gives ccp
    (ccp, l) = plane.intersect_point(direction, point)
    # check if inside circle
    if ccp and (pnormsq(psub(center, ccp)) < radiussq - epsilon):
        return (ccp, point, -l)
    return (None, None, INFINITE)
예제 #25
0
 def intersect_cylinder_vertex(self, direction, point, start=None):
     if start is None:
         start = self.location
     (cl, ccp, cp, l) = self.intersect_cylinder_point(direction,
                                                      point,
                                                      start=start)
     if ccp and ccp[2] < padd(psub(start, self.location), self.center)[2]:
         return (None, INFINITE, None)
     return (cl, l, cp)
예제 #26
0
 def intersect_circle_edge(self, direction, edge, start=None):
     (cl, ccp, cp, l) = self.intersect_circle_line(direction,
                                                   edge,
                                                   start=start)
     if cp:
         # check if the contact point is between the endpoints
         m = pdot(psub(cp, edge.p1), edge.dir)
         if (m < -epsilon) or (m > edge.len + epsilon):
             return (None, INFINITE, cp)
     return (cl, l, cp)
예제 #27
0
파일: __init__.py 프로젝트: eddeliu/pycam-1
def _check_deviance_of_adjacent_points(p1, p2, p3, min_distance):
    straight = psub(p3, p1)
    added = pdist(p2, p1) + pdist(p3, p2)
    # compare only the x/y distance of p1 and p3 with min_distance
    if straight[0]**2 + straight[1]**2 < min_distance**2:
        # the points are too close together
        return True
    else:
        # allow 0.1% deviance - this is an angle of around 2 degrees
        return (added / pnorm(straight)) < 1.001
예제 #28
0
 def get_tool_x3d(self):
     yield '<Cylinder radius="{:f}" height="{:f}" />'.format(
         self.radius, self.height)
     yield '<Torus innerRadius="{:f}" outerRadius="{:f}" />'.format(
         self.minorradius, self.majorradius)
     yield '<Transform center="{:f} {:f} {:f}">'.format(
         psub(self.location, self.center))
     yield '<Disk2D innerRadius="{:f}" outerRadius="{:f}" />'.format(
         0, self.majorradius)
     yield "</Transform>"
예제 #29
0
 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)
예제 #30
0
 def intersect_cylinder_edge(self, direction, edge, start=None):
     (cl, ccp, cp, l) = self.intersect_cylinder_line(direction,
                                                     edge,
                                                     start=start)
     if ccp and ccp[2] < self.center[2]:
         return (None, INFINITE, None)
     if ccp:
         m = pdot(psub(cp, edge.p1), edge.dir)
         if (m < -epsilon) or (m > edge.len + epsilon):
             return (None, INFINITE, None)
     return (cl, l, cp)
예제 #31
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