コード例 #1
0
ファイル: SolidPython.py プロジェクト: domalei/gdstart
def linearpath(x, y, z):
    outline = [
        Point3(0, 0, 0),
        Point3(0, 0, 10),
        Point3(0, 20, 10),
        Point3(x, y, z)
    ]
    return outline
コード例 #2
0
 def test_bezier_points(self):
     expected = [
         Point3(0.00, 0.00),
         Point3(1.38, 0.62),
         Point3(2.00, -1.00)
     ]
     actual = bezier_points(self.bezier_controls,
                            subdivisions=self.subdivisions)
     self.assertPointsListsEqual(expected, actual)
コード例 #3
0
 def test_bezier_points_raw(self):
     # Verify that we can use raw sequences of floats as inputs (e.g [(1,2), (3.2,4)])
     # rather than sequences of Point2s
     expected = [
         Point3(0.00, 0.00),
         Point3(1.38, 0.62),
         Point3(2.00, -1.00)
     ]
     actual = bezier_points(self.bezier_controls_raw,
                            subdivisions=self.subdivisions)
     self.assertPointsListsEqual(expected, actual)
コード例 #4
0
 def test_catmull_rom_points(self):
     expected = [
         Point3(0.00, 0.00),
         Point3(0.38, 0.44),
         Point3(1.00, 1.00),
         Point3(1.62, 1.06),
         Point3(2.00, 1.00)
     ]
     actual = catmull_rom_points(self.points,
                                 subdivisions=self.subdivisions,
                                 close_loop=False)
     self.assertPointsListsEqual(expected, actual)
コード例 #5
0
 def generate_transform_matrix(self):
     m_rotate_base = Matrix4.new_look_at(
         Point3(0, 0, 0),
         -self.origin.direction,
         self.origin.up).inverse()
     m = Matrix4.new_look_at(
         Point3(0, 0, 0),
         -self.position.direction,
         self.position.up) * m_rotate_base
     move = self.position.position - self.origin.position
     m.d, m.h, m.l = move.x, move.y, move.z
     return m
コード例 #6
0
 def test_catmull_rom_points_raw(self):
     # Verify that we can use raw sequences of floats as inputs (e.g [(1,2), (3.2,4)])
     # rather than sequences of Point2s
     expected = [
         Point3(0.00, 0.00),
         Point3(0.38, 0.44),
         Point3(1.00, 1.00),
         Point3(1.62, 1.06),
         Point3(2.00, 1.00)
     ]
     actual = catmull_rom_points(self.points_raw,
                                 subdivisions=self.subdivisions,
                                 close_loop=False)
     self.assertPointsListsEqual(expected, actual)
コード例 #7
0
ファイル: utils.py プロジェクト: ArroyoDev-LLC/3dframe
def round_point(point: Point3, n_digits=2):
    """Round a given 3d point."""
    p = point.copy()
    p.x = round(p.x, n_digits)
    p.y = round(p.y, n_digits)
    p.z = round(p.z, n_digits)
    return p.z
コード例 #8
0
ファイル: utils.py プロジェクト: yaohuic/SolidPython
def draw_segment(euc_line=None, endless=False, arrow_rad=7, vec_color=None):
    # Draw a tradtional arrow-head vector in 3-space.
    vec_arrow_rad = arrow_rad
    vec_arrow_head_rad = vec_arrow_rad * 1.5
    vec_arrow_head_length = vec_arrow_rad * 3

    if isinstance(euc_line, Vector3):
        p = Point3(*ORIGIN)
        v = euc_line
    elif isinstance(euc_line, Line3):
        p = euc_line.p
        v = -euc_line.v
    elif isinstance(euc_line, list) or isinstance(euc_line, tuple):
        # TODO: This assumes p & v are PyEuclid classes.
        # Really, they could as easily be two 3-tuples. Should
        # check for this.
        p, v = euc_line[0], euc_line[1]

    shaft_length = v.magnitude() - vec_arrow_head_length
    arrow = cylinder(r=vec_arrow_rad, h=shaft_length)
    arrow += up(shaft_length)(cylinder(r1=vec_arrow_head_rad,
                                       r2=0,
                                       h=vec_arrow_head_length))
    if endless:
        endless_length = max(v.magnitude() * 10, 200)
        arrow += cylinder(r=vec_arrow_rad / 3, h=endless_length, center=True)

    arrow = transform_to_point(body=arrow, dest_point=p, dest_normal=v)

    if vec_color:
        arrow = color(vec_color)(arrow)

    return arrow
コード例 #9
0
def star(num_points=5, outer_rad=15, dip_factor=0.5):
    star_pts = []
    for i in range(2 * num_points):
        rad = outer_rad - i % 2 * dip_factor * outer_rad
        angle = radians(360 / (2 * num_points) * i)
        star_pts.append(Point3(rad * cos(angle), rad * sin(angle), 0))
    return star_pts
コード例 #10
0
def _scale_loop(points:Sequence[Point3], scale:Union[float, Point2, Tuple2]=None) -> List[Point3]:
    if scale is None:
        return points

    if isinstance(scale, (float, int)):
        scale = [scale] * 2
    return [Point3(point.x * scale[0], point.y * scale[1], point.z) for point in points]
コード例 #11
0
ファイル: utils.py プロジェクト: salkinium/SolidPython
def transform_to_point( body: OpenSCADObject, 
                        dest_point: Point3, 
                        dest_normal: Vector3, 
                        src_point: Point3=Point3(0, 0, 0), 
                        src_normal: Vector3=Vector3(0, 1, 0), 
                        src_up: Vector3=Vector3(0, 0, 1)) -> OpenSCADObject:
    # Transform body to dest_point, looking at dest_normal.
    # Orientation & offset can be changed by supplying the src arguments

    # Body may be:
    #   -- an openSCAD object
    #   -- a list of 3-tuples  or PyEuclid Point3s
    #   -- a single 3-tuple or Point3
    dest_point = euclidify(dest_point, Point3)
    dest_normal = euclidify(dest_normal, Vector3)
    at = dest_point + dest_normal

    EUC_UP = euclidify(UP_VEC)
    EUC_FORWARD = euclidify(FORWARD_VEC)
    EUC_ORIGIN = euclidify(ORIGIN, Vector3)
    # if dest_normal and src_up are parallel, the transform collapses
    # all points to dest_point.  Instead, use EUC_FORWARD if needed
    if dest_normal.cross(src_up) == EUC_ORIGIN:
        if src_up.cross(EUC_UP) == EUC_ORIGIN:
            src_up = EUC_FORWARD
        else:
            src_up = EUC_UP
            
    def _orig_euclid_look_at(eye, at, up):
        '''
        Taken from the original source of PyEuclid's Matrix4.new_look_at() 
        prior to 1184a07d119a62fc40b2c6becdbeaf053a699047 (11 Jan 2015), 
        as discussed here:
        https://github.com/ezag/pyeuclid/commit/1184a07d119a62fc40b2c6becdbeaf053a699047
    
        We were dependent on the old behavior, which is duplicated here:
        '''
        z = (eye - at).normalized()
        x = up.cross(z).normalized()
        y = z.cross(x)

        m = Matrix4.new_rotate_triple_axis(x, y, z)
        m.d, m.h, m.l = eye.x, eye.y, eye.z
        return m
            
    look_at_matrix = _orig_euclid_look_at(eye=dest_point, at=at, up=src_up)
    
    if is_scad(body):
        # If the body being altered is a SCAD object, do the matrix mult
        # in OpenSCAD
        sc_matrix = scad_matrix(look_at_matrix)
        res = multmatrix(m=sc_matrix)(body)
    else:
        body = euclidify(body, Point3)
        if isinstance(body, (list, tuple)):
            res = [look_at_matrix * p for p in body]
        else:
            res = look_at_matrix * body
    return res
コード例 #12
0
def sinusoidal_ring(rad=25, segments=SEGMENTS):
    outline = []
    for i in range(segments):
        angle = i * 360 / segments
        x = rad * cos(radians(angle))
        y = rad * sin(radians(angle))
        z = 2 * sin(radians(angle * 6))
        outline.append(Point3(x, y, z))
    return outline
コード例 #13
0
 def test_catmull_rom_points_3d(self):
     points = [Point3(-1, -1, 0), Point3(0, 0, 1), Point3(1, 1, 0)]
     expected = [
         Point3(-1.00, -1.00, 0.00),
         Point3(-0.62, -0.62, 0.50),
         Point3(0.00, 0.00, 1.00),
         Point3(0.62, 0.62, 0.50),
         Point3(1.00, 1.00, 0.00)
     ]
     actual = catmull_rom_points(points, subdivisions=2)
     self.assertPointsListsEqual(expected, actual)
コード例 #14
0
 def create_cutter(addr, left_or_right_dir):
     pos = switches.get_switch_position(addr)
     pos = Point3(*pos, 0)
     angle = switches.get_switch_angle(addr)
     cutter = switches.create_switch(addr, size=1)
     cutter = sc.translate(pos)(sc.scale(
         (4, 4, 0))(sc.translate(pos * -1)(cutter)))
     offset = utils.unit_point2(angle) * 2.5 * left_or_right_dir
     cutter = sc.translate((*offset, 0))(cutter)
     return cutter
コード例 #15
0
def sinusoidal_ring(rad=25, segments=SEGMENTS) -> List[Point3]:
    outline = []
    for i in range(segments):
        angle = radians(i * 360 / segments)
        scaled_rad = (1 + 0.18 * cos(angle * 5)) * rad
        x = scaled_rad * cos(angle)
        y = scaled_rad * sin(angle)
        z = 0
        # Or stir it up and add an oscillation in z as well
        # z = 3 * sin(angle * 6)
        outline.append(Point3(x, y, z))
    return outline
コード例 #16
0
ファイル: struttools2D.py プロジェクト: domalei/gdstart
def createseg(p1,p2,t):
    
    linearpath = [Point3(0,0,0), Point3(0,0,t)]
    #calculations for the four corners of the face
    #alpha is the angle of the segment from the x-axis CCW
    if p2[0] == p1[1]:
        alpha = np.pi/2
    alpha = np.arctan2((p2[1]-p1[1]),(p2[0]-p1[0]))
    #the x displacement of the corner from p1 and p2
    xoff = math.sin(alpha)*(t/2)
    #the y displacement of the corner from p1 and p2
    yoff = math.cos(alpha)*(t/2)    
    
    #1Acorner
    A1corner = [p1[0]-xoff,p1[1]+yoff]
    #B1corner
    B1corner = [p1[0]+xoff,p1[1]-yoff]
    #A2corner
    A2corner = [p2[0]-xoff,p2[1]+yoff]
    #B2corner
    B2corner = [p2[0]+xoff,p2[1]-yoff]
    
    #make the face from the 4 points that were defined earlier.
    face_pts = [Point3(A1corner[0], A1corner[1],0)]
    face_pts.append(Point3(A2corner[0], A2corner[1],0))
    face_pts.append(Point3(B2corner[0], B2corner[1],0))
    face_pts.append(Point3(B1corner[0], B1corner[1],0))
    #creates segment
    seg = extrude_along_path(shape_pts=face_pts,path_pts=linearpath)
    return seg
コード例 #17
0
ファイル: SolidPython2.py プロジェクト: domalei/gdstart
def face(start, sidelength, plane):
    #start = starting point as an array [0,0,0]
    #sidelength = int value
    #plane = decide which plane your face is on ('xy' for xy plane, etc..)
    face_pts = [Point3(start[0], start[1], start[2])]

    if plane == 'xy':
        face_pts.append(Point3(start[0] - sidelength, start[1], start[2]))
        face_pts.append(
            Point3(start[0] - sidelength, start[1] + sidelength, start[2]))
        face_pts.append(Point3(start[0], start[1] + sidelength, start[2]))
    elif plane == 'yz':
        face_pts.append(Point3(start[0], start[1] + sidelength, start[2]))
        face_pts.append(
            Point3(start[0], start[1] + sidelength, start[2] + sidelength))
        face_pts.append(Point3(start[0], start[1], start[2] + sidelength))
    elif plane == 'xz':
        face_pts.append(Point3(start[0] + sidelength, start[1], start[2]))
        face_pts.append(
            Point3(start[0] + sidelength, start[1] + sidelength, start[2]))
        face_pts.append(Point3(start[0], start[1] + sidelength, start[2]))

    return face_pts
コード例 #18
0
ファイル: koch.py プロジェクト: yaohuic/SolidPython
def affine_combination(a, b, weight=0.5):
    """
    Note that weight is a fraction of the distance between self and other.
    So... 0.33 is a point .33 of the way between self and other.
    """
    if hasattr(a, 'z'):
        return Point3(
            (1 - weight) * a.x + weight * b.x,
            (1 - weight) * a.y + weight * b.y,
            (1 - weight) * a.z + weight * b.z,
        )
    else:
        return Point2(
            (1 - weight) * a.x + weight * b.x,
            (1 - weight) * a.y + weight * b.y,
        )
コード例 #19
0
def extrude_example_transforms() -> OpenSCADObject:
    path_rad = PATH_RAD
    height = 2 * SHAPE_RAD
    num_steps = 120

    shape = circle_points(rad=path_rad, num_points=120)
    path = [Point3(0, 0, i) for i in frange(0, height, num_steps=num_steps)]

    max_rotation = radians(15)
    max_z_displacement = height / 10
    up = Vector3(0, 0, 1)

    # The transforms argument is powerful.
    # Each point in the entire extrusion will call this function with unique arguments:
    #   -- `path_norm` in [0, 1] specifying how far along in the extrusion a point's loop is
    #   -- `loop_norm` in [0, 1] specifying where in its loop a point is.
    def point_trans(point: Point3, path_norm: float,
                    loop_norm: float) -> Point3:
        # scale the point from 1x to 2x in the course of the
        # extrusion,
        scale = 1 + path_norm * path_norm / 2
        p = scale * point

        # Rotate the points sinusoidally up to max_rotation
        p = p.rotate_around(up, max_rotation * sin(tau * path_norm))

        # Oscillate z values sinusoidally, growing from
        # 0 magnitude to max_z_displacement
        max_z = lerp(path_norm, 0, 1, 0, max_z_displacement)
        angle = lerp(loop_norm, 0, 1, 0, 10 * tau)
        p.z += max_z * sin(angle)
        return p

    no_trans = make_label('No Transform')
    no_trans += down(height / 2)(extrude_along_path(shape,
                                                    path,
                                                    cap_ends=False))

    # We can pass transforms a single function that will be called on all points,
    # or pass a list with a transform function for each point along path
    arb_trans = make_label('Arbitrary Transform')
    arb_trans += down(height / 2)(extrude_along_path(shape,
                                                     path,
                                                     transforms=[point_trans],
                                                     cap_ends=False))

    return no_trans + right(3 * path_rad)(arb_trans)
コード例 #20
0
def toroidial_helix_coil(rad=25.4-2, pitch = (2*pi*((6*25.4)/2-(25.4-2/2)-2))/30, outer_rad=(6*25.4)/2-(25.4-2/2)-2, segments=SEGMENTS):
    h = 2*pi*outer_rad
    a = rad
    b = pitch/(2*pi)
    outline = []
    for i in range(segments):
        theta = 2*pi*(i/segments)
        t = (i/segments*h)/b
        x = a*cos(t)+outer_rad
        y = a*sin(t)
        z = 0#b*t
        # then rotate
        x, z = x*cos(theta) - z*sin(theta), x*sin(theta) + z*cos(theta)

        outline.append(Point3(x, y, z))

    return outline
コード例 #21
0
 def test_bezier_points_3d(self):
     # verify that we get a valid bezier curve back even when its control points
     # are outside the XY plane and aren't coplanar
     controls_3d = [
         Point3(-2, -1, 0),
         Point3(-0.5, -0.5, 1),
         Point3(0.5, 0.5, 1),
         Point3(2, 1, 0)
     ]
     actual = bezier_points(controls_3d, subdivisions=self.subdivisions)
     expected = [
         Point3(-2.00, -1.00, 0.00),
         Point3(0.00, 0.00, 0.75),
         Point3(2.00, 1.00, 0.00)
     ]
     self.assertPointsListsEqual(expected, actual)
コード例 #22
0
ファイル: koch.py プロジェクト: yaohuic/SolidPython
def kochify_3d(a,
               b,
               c,
               ab_weight=0.5,
               bc_weight=0.5,
               ca_weight=0.5,
               pyr_a_weight=ONE_THIRD,
               pyr_b_weight=ONE_THIRD,
               pyr_c_weight=ONE_THIRD,
               pyr_height_weight=ONE_THIRD):
    """
    Point3s a, b, and c must be coplanar and define a face
    ab_weight, etc define the subdivision of the original face
    pyr_a_weight, etc define where the point of the new pyramid face will go
    pyr_height determines how far from the face the new pyramid's point will be
    """
    triangles = []
    new_a = affine_combination(a, b, ab_weight)
    new_b = affine_combination(b, c, bc_weight)
    new_c = affine_combination(c, a, ca_weight)

    triangles.extend([[a, new_a, new_c], [b, new_b, new_a], [c, new_c, new_b]])

    avg_pt_x = a.x * pyr_a_weight + b.x * pyr_b_weight + c.x * pyr_c_weight
    avg_pt_y = a.y * pyr_a_weight + b.y * pyr_b_weight + c.y * pyr_c_weight
    avg_pt_z = a.z * pyr_a_weight + b.z * pyr_b_weight + c.z * pyr_c_weight

    center_pt = Point3(avg_pt_x, avg_pt_y, avg_pt_z)

    # The top of the pyramid will be on a normal
    ab_vec = b - a
    bc_vec = c - b
    ca_vec = a - c
    normal = ab_vec.cross(bc_vec).normalized()
    avg_side_length = (abs(ab_vec) + abs(bc_vec) + abs(ca_vec)) / 3
    pyr_h = avg_side_length * pyr_height_weight
    pyr_pt = LineSegment3(center_pt, normal, pyr_h).p2

    triangles.extend([[new_a, pyr_pt, new_c], [new_b, pyr_pt, new_a],
                      [new_c, pyr_pt, new_b]])

    return triangles
コード例 #23
0
ファイル: utils.py プロジェクト: pjdixit/SolidPython
def centroid(points: Sequence[PointVec23]) -> PointVec23:
    if not points:
        raise ValueError(f"centroid(): argument `points` is empty")
    first = points[0]
    is_3d = isinstance(first, (Vector3, Point3))
    if is_3d:
        total = Vector3(0, 0, 0)
    else:
        total = Vector2(0, 0)

    for p in points:
        total += p
    total /= len(points)

    if isinstance(first, Point2):
        return Point2(*total)
    elif isinstance(first, Point3):
        return Point3(*total)
    else:
        return total
コード例 #24
0
 def setUp(self):
     self.points = [
         Point3(0, 0),
         Point3(1, 1),
         Point3(2, 1),
     ]
     self.points_raw = [
         (0, 0),
         (1, 1),
         (2, 1),
     ]
     self.bezier_controls = [
         Point3(0, 0),
         Point3(1, 1),
         Point3(2, 1),
         Point3(2, -1),
     ]
     self.bezier_controls_raw = [(0, 0), (1, 1), (2, 1), (2, -1)]
     self.subdivisions = 2
コード例 #25
0
ファイル: SolidPython2.py プロジェクト: domalei/gdstart
def linearpath(start, extrudelength, direction):
    if direction == 'x':
        outline = [
            Point3(start[0], start[1], start[2]),
            Point3(start[0] + extrudelength, start[1], start[2])
        ]
    elif direction == 'y':
        outline = [
            Point3(start[0], start[1] + 10, start[2]),
            Point3(start[0], start[1] + extrudelength, start[2])
        ]
    elif direction == 'z':
        outline = [
            Point3(start[0], start[1], start[2]),
            Point3(start[0], start[1], start[2] + extrudelength)
        ]
    return outline
コード例 #26
0
import difflib
import unittest
import re
from euclid3 import Point3, Vector3, Point2

from solid import scad_render
from solid.objects import cube, polygon, sphere, translate
from solid.test.ExpandedTestCase import DiffOutput
from solid.utils import BoundingBox, arc, arc_inverted, euc_to_arr, euclidify
from solid.utils import extrude_along_path, fillet_2d, is_scad, offset_points
from solid.utils import split_body_planar, transform_to_point, project_to_2D
from solid.utils import FORWARD_VEC, RIGHT_VEC, UP_VEC
from solid.utils import back, down, forward, left, right, up
from solid.utils import label

tri = [Point3(0, 0, 0), Point3(10, 0, 0), Point3(0, 10, 0)]

scad_test_cases = [
    # Test name, function, args, expected value
    ('up', up, [2], '\n\ntranslate(v = [0, 0, 2]);'),
    ('down', down, [2], '\n\ntranslate(v = [0, 0, -2]);'),
    ('left', left, [2], '\n\ntranslate(v = [-2, 0, 0]);'),
    ('right', right, [2], '\n\ntranslate(v = [2, 0, 0]);'),
    ('forward', forward, [2], '\n\ntranslate(v = [0, 2, 0]);'),
    ('back', back, [2], '\n\ntranslate(v = [0, -2, 0]);'),
    ('arc', arc, [10, 0, 90, 24],
     '\n\ndifference() {\n\tcircle($fn = 24, r = 10);\n\trotate(a = 0) {\n\t\ttranslate(v = [0, -10, 0]) {\n\t\t\tsquare(center = true, size = [30, 20]);\n\t\t}\n\t}\n\trotate(a = -90) {\n\t\ttranslate(v = [0, -10, 0]) {\n\t\t\tsquare(center = true, size = [30, 20]);\n\t\t}\n\t}\n}'
     ),
    ('arc_inverted', arc_inverted, [10, 0, 90, 24],
     '\n\ndifference() {\n\tintersection() {\n\t\trotate(a = 0) {\n\t\t\ttranslate(v = [-990, 0, 0]) {\n\t\t\t\tsquare(center = false, size = [1000, 1000]);\n\t\t\t}\n\t\t}\n\t\trotate(a = 90) {\n\t\t\ttranslate(v = [-990, -1000, 0]) {\n\t\t\t\tsquare(center = false, size = [1000, 1000]);\n\t\t\t}\n\t\t}\n\t}\n\tcircle($fn = 24, r = 10);\n}'
     ),
コード例 #27
0
ファイル: utils.py プロジェクト: salkinium/SolidPython
def extrude_along_path( shape_pts:Points, 
                        path_pts:Points, 
                        scale_factors:Sequence[float]=None) -> OpenSCADObject:
    # Extrude the convex curve defined by shape_pts along path_pts.
    # -- For predictable results, shape_pts must be planar, convex, and lie
    # in the XY plane centered around the origin.
    #
    # -- len(scale_factors) should equal len(path_pts).  If not present, scale
    #       will be assumed to be 1.0 for each point in path_pts
    # -- Future additions might include corner styles (sharp, flattened, round)
    #       or a twist factor
    polyhedron_pts:Points= []
    facet_indices:List[Tuple[int, int, int]] = []

    if not scale_factors:
        scale_factors = [1.0] * len(path_pts)

    # Make sure we've got Euclid Point3's for all elements
    shape_pts = euclidify(shape_pts, Point3)
    path_pts = euclidify(path_pts, Point3)

    src_up = Vector3(*UP_VEC)

    for which_loop in range(len(path_pts)):
        path_pt = path_pts[which_loop]
        scale = scale_factors[which_loop]

        # calculate the tangent to the curve at this point
        if which_loop > 0 and which_loop < len(path_pts) - 1:
            prev_pt = path_pts[which_loop - 1]
            next_pt = path_pts[which_loop + 1]

            v_prev = path_pt - prev_pt
            v_next = next_pt - path_pt
            tangent = v_prev + v_next
        elif which_loop == 0:
            tangent = path_pts[which_loop + 1] - path_pt
        elif which_loop == len(path_pts) - 1:
            tangent = path_pt - path_pts[which_loop - 1]

        # Scale points
        this_loop:Point3 = []
        if scale != 1.0:
            this_loop = [(scale * sh) for sh in shape_pts]
            # Convert this_loop back to points; scaling changes them to Vectors
            this_loop = [Point3(v.x, v.y, v.z) for v in this_loop]
        else:
            this_loop = shape_pts[:] # type: ignore

        # Rotate & translate
        this_loop = transform_to_point(this_loop, dest_point=path_pt, 
                                        dest_normal=tangent, src_up=src_up)

        # Add the transformed points to our final list
        polyhedron_pts += this_loop
        # And calculate the facet indices
        shape_pt_count = len(shape_pts)
        segment_start = which_loop * shape_pt_count
        segment_end = segment_start + shape_pt_count - 1
        if which_loop < len(path_pts) - 1:
            for i in range(segment_start, segment_end):
                facet_indices.append( (i, i + shape_pt_count, i + 1) )
                facet_indices.append( (i + 1, i + shape_pt_count, i + shape_pt_count + 1) )
            facet_indices.append( (segment_start, segment_end, segment_end + shape_pt_count) )
            facet_indices.append( (segment_start, segment_end + shape_pt_count, segment_start + shape_pt_count) )

    # Cap the start of the polyhedron
    for i in range(1, shape_pt_count - 1):
        facet_indices.append((0, i, i + 1))

    # And the end (could be rolled into the earlier loop)
    # FIXME: concave cross-sections will cause this end-capping algorithm
    # to fail
    end_cap_base = len(polyhedron_pts) - shape_pt_count
    for i in range(end_cap_base + 1, len(polyhedron_pts) - 1):
        facet_indices.append( (end_cap_base, i + 1, i) )

    return polyhedron(points=euc_to_arr(polyhedron_pts), faces=facet_indices) # type: ignore
コード例 #28
0
ファイル: test_utils.py プロジェクト: imanyakin/SolidPython
import unittest
import re
from euclid3 import Point3, Vector3, Point2

from solid import scad_render
from solid.objects import cube, polygon, sphere, translate
from solid.test.ExpandedTestCase import DiffOutput
from solid.utils import BoundingBox, arc, arc_inverted, euc_to_arr, euclidify 
from solid.utils import extrude_along_path, fillet_2d, is_scad, offset_points
from solid.utils import split_body_planar, transform_to_point, project_to_2D
from solid.utils import path_2d, path_2d_polygon
from solid.utils import FORWARD_VEC, RIGHT_VEC, UP_VEC
from solid.utils import back, down, forward, left, right, up
from solid.utils import label

tri = [Point3(0, 0, 0), Point3(10, 0, 0), Point3(0, 10, 0)]

scad_test_cases = [
    # Test name, function, args, expected value
    ('up', up, [2], '\n\ntranslate(v = [0, 0, 2]);'),
    ('down', down, [2], '\n\ntranslate(v = [0, 0, -2]);'),
    ('left', left, [2], '\n\ntranslate(v = [-2, 0, 0]);'),
    ('right', right, [2], '\n\ntranslate(v = [2, 0, 0]);'),
    ('forward', forward, [2], '\n\ntranslate(v = [0, 2, 0]);'),
    ('back', back, [2], '\n\ntranslate(v = [0, -2, 0]);'),
    ('arc', arc, [10, 0, 90, 24], '\n\ndifference() {\n\tcircle($fn = 24, r = 10);\n\trotate(a = 0) {\n\t\ttranslate(v = [0, -10, 0]) {\n\t\t\tsquare(center = true, size = [30, 20]);\n\t\t}\n\t}\n\trotate(a = -90) {\n\t\ttranslate(v = [0, -10, 0]) {\n\t\t\tsquare(center = true, size = [30, 20]);\n\t\t}\n\t}\n}'),
    ('arc_inverted', arc_inverted, [10, 0, 90, 24], '\n\ndifference() {\n\tintersection() {\n\t\trotate(a = 0) {\n\t\t\ttranslate(v = [-990, 0, 0]) {\n\t\t\t\tsquare(center = false, size = [1000, 1000]);\n\t\t\t}\n\t\t}\n\t\trotate(a = 90) {\n\t\t\ttranslate(v = [-990, -1000, 0]) {\n\t\t\t\tsquare(center = false, size = [1000, 1000]);\n\t\t\t}\n\t\t}\n\t}\n\tcircle($fn = 24, r = 10);\n}'),
    ('transform_to_point_scad', transform_to_point, [cube(2), [2, 2, 2], [3, 3, 1]], '\n\nmultmatrix(m = [[0.7071067812, -0.1622214211, -0.6882472016, 2], [-0.7071067812, -0.1622214211, -0.6882472016, 2], [0.0000000000, 0.9733285268, -0.2294157339, 2], [0, 0, 0, 1.0000000000]]) {\n\tcube(size = 2);\n}'),
    ('extrude_along_path', extrude_along_path, [tri, [[0, 0, 0], [0, 20, 0]]], '\n\npolyhedron(faces = [[0, 3, 1], [1, 3, 4], [1, 4, 2], [2, 4, 5], [0, 2, 5], [0, 5, 3], [0, 1, 2], [3, 5, 4]], points = [[0.0000000000, 0.0000000000, 0.0000000000], [10.0000000000, 0.0000000000, 0.0000000000], [0.0000000000, 0.0000000000, 10.0000000000], [0.0000000000, 20.0000000000, 0.0000000000], [10.0000000000, 20.0000000000, 0.0000000000], [0.0000000000, 20.0000000000, 10.0000000000]]);'),
    ('extrude_along_path_vertical', extrude_along_path, [tri, [[0, 0, 0], [0, 0, 20]]], '\n\npolyhedron(faces = [[0, 3, 1], [1, 3, 4], [1, 4, 2], [2, 4, 5], [0, 2, 5], [0, 5, 3], [0, 1, 2], [3, 5, 4]], points = [[0.0000000000, 0.0000000000, 0.0000000000], [-10.0000000000, 0.0000000000, 0.0000000000], [0.0000000000, 10.0000000000, 0.0000000000], [0.0000000000, 0.0000000000, 20.0000000000], [-10.0000000000, 0.0000000000, 20.0000000000], [0.0000000000, 10.0000000000, 20.0000000000]]);'),
コード例 #29
0
class Container(OpenSCADObject):
    origin = Connector(
        Point3(0, 0, 0),
        Vector3(0, 1, 0),
        Vector3(0, 0, 1)
    )

    origin_output_connectors = {}

    def __init__(self, input_connectors=None):
        OpenSCADObject.__init__(self, "container", {})
        self.position = self.origin()
        self.adjust_to_input(input_connectors)
        self.transform_matrix = self.generate_transform_matrix()
        self.add(self.generate())
        self.output_connectors = self.generate_output_connectors()

    def adjust_to_input(self, input_connectors):
        return

    def generate_at_origin(self):
        return union()

    def generate(self):
        obj = self.generate_at_origin()
        matrix = scad_matrix(self.transform_matrix)
        return multmatrix(m=matrix)(obj)

    def recursive_transform(self, v):
        m = self.transform_matrix

        if not v:
            return v
        if isinstance(v, Connector):
            return v.transform(m)
        elif isinstance(v, Point3):
            return m * v
        elif isinstance(v, Vector3):
            return m * v
        elif isinstance(v, dict):
            new_v = {}
            for k, v1 in v.items():
                new_v[k] = self.recursive_transform(v1)
            return new_v
        elif isinstance(v, list):
            new_v = []
            for v1 in v:
                new_v.append(self.recursive_transform(v1))
            return new_v
        else:
            raise RuntimeError("Unsupported type")

    def generate_output_connectors(self):
        m = self.transform_matrix

        return self.recursive_transform(self.origin_output_connectors)

    def generate_transform_matrix(self):
        m_rotate_base = Matrix4.new_look_at(
            Point3(0, 0, 0),
            -self.origin.direction,
            self.origin.up).inverse()
        m = Matrix4.new_look_at(
            Point3(0, 0, 0),
            -self.position.direction,
            self.position.up) * m_rotate_base
        move = self.position.position - self.origin.position
        m.d, m.h, m.l = move.x, move.y, move.z
        return m
コード例 #30
0
#! /usr/bin/env python3
import unittest
import re

from solid import OpenSCADObject, scad_render
from solid.utils import extrude_along_path
from euclid3 import Point2, Point3

from typing import Union

tri = [Point3(0, 0, 0), Point3(10, 0, 0), Point3(0, 10, 0)]


class TestExtrudeAlongPath(unittest.TestCase):
    # Test cases will be dynamically added to this instance
    # using the test case arrays above
    def assertEqualNoWhitespace(self, a, b):
        remove_whitespace = lambda s: re.subn(r'[\s\n]', '', s)[0]
        self.assertEqual(remove_whitespace(a), remove_whitespace(b))

    def assertEqualOpenScadObject(self, expected: str,
                                  actual: Union[OpenSCADObject, str]):
        if isinstance(actual, OpenSCADObject):
            act = scad_render(actual)
        elif isinstance(actual, str):
            act = actual
        self.assertEqualNoWhitespace(expected, act)

    def test_extrude_along_path(self):
        path = [[0, 0, 0], [0, 20, 0]]
        # basic test