Exemple #1
0
    def execute(self, context):
        selected = context.selected_objects  # save original selected items

        simple.remove_multiple('intarsion_')

        for ob in selected:
            ob.select_set(True)  # select original curves

        #  Perimeter cut largen then intarsion pocket externally, optional

        diam = self.diameter * 1.05 + self.backlight * 2  # make the diameter 5% larger and compensate for backlight
        utils.silhoueteOffset(context, -diam / 2)

        o1 = bpy.context.active_object
        utils.silhoueteOffset(context, diam)
        o2 = bpy.context.active_object
        utils.silhoueteOffset(context, -diam / 2)
        o3 = bpy.context.active_object
        o1.select_set(True)
        o2.select_set(True)
        o3.select_set(False)
        bpy.ops.object.delete(
            use_global=False)  # delete o1 and o2 temporary working curves
        o3.name = "intarsion_pocket"  # this is the pocket for intarsion
        bpy.context.object.location[2] = -self.intarsion_thickness

        if self.perimeter_cut > 0.0:
            utils.silhoueteOffset(context, self.perimeter_cut)
            bpy.context.active_object.name = "intarsion_perimeter"
            bpy.context.object.location[2] = -self.base_thickness
            bpy.ops.object.select_all(action='DESELECT')  # deselect new curve

        o3.select_set(True)
        context.view_layer.objects.active = o3
        #   intarsion profile is the inside piece of the intarsion
        utils.silhoueteOffset(context, -self.tolerance /
                              2)  # make smaller curve for material profile
        bpy.context.object.location[2] = self.intarsion_thickness
        o4 = bpy.context.active_object
        bpy.context.active_object.name = "intarsion_profil"
        o4.select_set(False)

        if self.backlight > 0.0:  # Make a smaller curve for backlighting purposes
            utils.silhoueteOffset(context,
                                  (-self.tolerance / 2) - self.backlight)
            bpy.context.active_object.name = "intarsion_backlight"
            bpy.context.object.location[
                2] = -self.backlight_depth_from_top - self.intarsion_thickness
            o4.select_set(True)
        o3.select_set(True)
        return {'FINISHED'}
def t(length, thick, diameter, tolerance, amount=0, stem=1, twist=False, tneck=0.5, tthick=0.01, combination='MF',
      base_gender='M', corner=False):
    if corner:
        if combination == 'MF':
            base_gender = 'M'
            combination = 'f'
        elif combination == 'F':
            base_gender = 'F'
            combination = 'f'
        elif combination == 'M':
            base_gender = 'M'
            combination = 'm'

    bar(length, thick, diameter, tolerance, amount=amount, stem=stem, twist=twist, tneck=tneck,
        tthick=tthick, which=base_gender)
    simple.active_name('tmp')
    fingers(diameter, tolerance, amount=amount, stem=stem)
    if combination == 'MF' or combination == 'M' or combination == 'm':
        simple.make_active('fingers')
        simple.move(y=thick / 2)
        simple.duplicate()
        simple.active_name('tmp')
        simple.union('tmp')

    if combination == 'M':
        simple.make_active('fingers')
        simple.mirrory()
        simple.active_name('tmp')
        simple.union('tmp')

    if combination == 'MF' or combination == 'F' or combination == 'f':
        simple.make_active('receptacle')
        simple.move(y=-thick / 2)
        simple.duplicate()
        simple.active_name('tmp')
        simple.difference('tmp', 'tmp')

    if combination == 'F':
        simple.make_active('receptacle')
        simple.mirrory()
        simple.active_name('tmp')
        simple.difference('tmp', 'tmp')

    simple.remove_multiple('receptacle')
    simple.remove_multiple('fingers')

    simple.rename('tmp', 't')
    simple.make_active('t')
def tile(diameter, tolerance, tile_x_amount, tile_y_amount, stem=1):
    global DT
    diameter = diameter * DT
    # diameter * DT * (2 + stem - 1)
    (4 + 2 * (stem - 1)) * diameter
    width = (tile_x_amount) * (4 + 2 * (stem - 1)) * diameter + diameter
    height = (tile_y_amount) * (4 + 2 * (stem - 1)) * diameter + diameter

    print('size:', width, height)
    fingers(diameter, tolerance, amount=tile_x_amount+2, stem=stem)
    simple.add_rectangle(width, height)
    simple.active_name('_base')

    simple.make_active('fingers')
    simple.active_name('_fingers')
    simple.intersect('_')
    simple.remove_multiple('_fingers')
    simple.rename('intersection', '_fingers')
    simple.move(y=height/2)
    simple.union('_')
    simple.active_name('_base')
    simple.remove_doubles()
    simple.rename('receptacle', '_receptacle')
    simple.move(y=-height/2)
    simple.difference('_', '_base')
    simple.active_name('base')
    fingers(diameter, tolerance, amount=tile_y_amount, stem=stem)
    simple.rename('base', '_base')
    simple.remove_doubles()
    simple.rename('fingers', '_fingers')
    simple.rotate(math.pi/2)
    simple.move(x=-width/2)
    simple.union('_')
    simple.active_name('_base')
    simple.rename('receptacle', '_receptacle')
    simple.rotate(math.pi/2)
    simple.move(x=width/2)
    simple.difference('_', '_base')
    simple.active_name('tile_ ' + str(tile_x_amount) + '_' + str(tile_y_amount))
def bar(width, thick, diameter, tolerance, amount=0, stem=1, twist=False, tneck=0.5, tthick=0.01, twist_keep=False,
        twist_line=False, twist_line_amount=2, which='MF'):

    # width = length of the bar
    # thick = thickness of the bar
    # diameter = diameter of the tool for joint creation
    # tolerance = Tolerance in the joint
    # amount = amount of fingers in the joint 0 means auto generate
    # stem = amount of radius the stem or neck of the joint will have
    # twist = twist lock addition
    # tneck = percentage the twist neck will have compared to thick
    # tthick = thicknest of the twist material
    # Which M,F, MF, MM, FF

    global DT
    if amount == 0:
        amount = round(thick / ((4 + 2 * (stem - 1)) * diameter * DT)) - 1
    bpy.ops.curve.simple(align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), Simple_Type='Rectangle',
                         Simple_width=width, Simple_length=thick, use_cyclic_u=True, edit_mode=False)
    simple.active_name('tmprect')

    fingers(diameter, tolerance, amount, stem=stem)

    if which == 'MM' or which == 'M' or which == 'MF':
        simple.rename('fingers', '_tmpfingers')
        simple.rotate(-math.pi / 2)
        simple.move(x=width / 2)
        simple.rename('tmprect', '_tmprect')
        simple.union('_tmp')
        simple.active_name("tmprect")
        twistm('tmprect', thick, diameter, tolerance, twist, tneck, tthick, -math.pi / 2,
               x=width / 2, twist_keep=twist_keep)

    twistf('receptacle', thick, diameter, tolerance, twist, tneck, tthick, twist_keep=twist_keep)
    simple.rename('receptacle', '_tmpreceptacle')
    if which == 'FF' or which == 'F' or which == 'MF':
        simple.rotate(-math.pi / 2)
        simple.move(x=-width / 2)
        simple.rename('tmprect', '_tmprect')
        simple.difference('_tmp', '_tmprect')
        simple.active_name("tmprect")
        if twist_keep:
            simple.make_active('twist_keep_f')
            simple.rotate(-math.pi / 2)
            simple.move(x=-width / 2)
           
    simple.remove_multiple("_")  # Remove temporary base and holes
    simple.remove_multiple("fingers")  # Remove temporary base and holes

    if twist_line:
        joinery.twist_line(thick, tthick, tolerance, tneck, twist_line_amount, width)
        if twist_keep:
            simple.duplicate()
        simple.active_name('tmptwist')
        simple.difference('tmp', 'tmprect')
    simple.rename('tmprect', 'Puzzle_bar')
    simple.remove_multiple("tmp")  # Remove temporary base and holes
    simple.make_active('Puzzle_bar')
Exemple #5
0
def create_flex_side(length, height, finger_thick, top_bottom=False):
    #   assumes the base fingers were created and exist
    #   crates a flex side for mortise on curve
    #   length = length of curve
    #   height = height of side
    #   finger_length = lenght of finger or mortise
    #   finger_thick = finger thickness or thickness of material
    #   finger_tol = Play for finger 0 is very tight
    #   top_bottom = fingers on top and bottom if true, just on bottom if false
    #   flex_pocket = width of pocket on the flex side.  This is for kerf bending.
    if top_bottom:
        fingers = finger_pair("base", 0, height - finger_thick)
    else:
        simple.make_active("base")
        fingers = bpy.context.active_object
        bpy.ops.transform.translate(value=(0.0, height / 2 - finger_thick / 2 +
                                           0.0003, 0.0))

    bpy.ops.curve.simple(align='WORLD',
                         location=(length / 2 + 0.00025, 0, 0),
                         rotation=(0, 0, 0),
                         Simple_Type='Rectangle',
                         Simple_width=length,
                         Simple_length=height,
                         shape='3D',
                         outputType='POLY',
                         use_cyclic_u=True,
                         handleType='AUTO',
                         edit_mode=False)
    simple.active_name("_side")

    simple.make_active('_side')
    fingers.select_set(True)
    bpy.ops.object.curve_boolean(boolean_type='DIFFERENCE')

    simple.active_name("side")
    simple.remove_multiple('_')
    simple.remove_multiple('base')
Exemple #6
0
    def execute(
        self, context
    ):  # this is almost same as getobjectoutline, just without the need of operation data
        ob = context.active_object
        if self.opencurve and ob.type == 'CURVE':
            bpy.ops.object.duplicate()
            obj = context.active_object
            bpy.ops.object.transform_apply(location=True,
                                           rotation=True,
                                           scale=True)  # apply all transforms
            bpy.context.object.data.resolution_u = 60
            bpy.ops.object.convert(target='MESH')
            bpy.context.active_object.name = "temp_mesh"

            coords = []
            for v in obj.data.vertices:  # extract X,Y coordinates from the vertices data
                coords.append((v.co.x, v.co.y))

            simple.remove_multiple('temp_mesh')  # delete temporary mesh
            simple.remove_multiple('dilation')  # delete old dilation objects

            line = LineString(
                coords
            )  # convert coordinates to shapely LineString datastructure
            print("line length=", round(line.length * 1000), 'mm')

            dilated = line.buffer(
                self.offset,
                cap_style=1,
                resolution=16,
                mitre_limit=self.mitrelimit)  # use shapely to expand
            polygon_utils_cam.shapelyToCurve("dilation", dilated, 0)
        else:
            utils.silhoueteOffset(context, self.offset, int(self.style),
                                  self.mitrelimit)
        return {'FINISHED'}
def mitre(length, thick, angle, angleb, diameter, tolerance, amount=0, stem=1, twist=False,
          tneck=0.5, tthick=0.01, which='MF'):
    # length is the total width of the segments including 2 * radius and thick
    # radius = radius of the curve
    # thick = thickness of the bar
    # angle = angle of the female part
    # angleb = angle of the male part
    # diameter = diameter of the tool for joint creation
    # tolerance = Tolerance in the joint
    # amount = amount of fingers in the joint 0 means auto generate
    # stem = amount of radius the stem or neck of the joint will have
    # twist = twist lock addition
    # tneck = percentage the twist neck will have compared to thick
    # tthick = thicknest of the twist material
    # which = which joint to generate, Male Female MaleFemale M, F, MF

    # generate base rectangle
    bpy.ops.curve.simple(align='WORLD', location=(0, -thick / 2, 0), rotation=(0, 0, 0), Simple_Type='Rectangle',
                         Simple_width=length * 1.005 + 4 * thick, Simple_length=thick, use_cyclic_u=True,
                         edit_mode=False,
                         shape='3D')
    simple.active_name("tmprect")

    # generate cutout shapes
    bpy.ops.curve.simple(align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), Simple_Type='Rectangle',
                         Simple_width=4 * thick, Simple_length=6 * thick, use_cyclic_u=True, edit_mode=False,
                         shape='3D')
    simple.move(x=2 * thick)
    simple.rotate(angle)
    simple.move(x=length / 2)
    simple.active_name('tmpmitreright')

    bpy.ops.curve.simple(align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), Simple_Type='Rectangle',
                         Simple_width=4 * thick, Simple_length=6 * thick, use_cyclic_u=True, edit_mode=False,
                         shape='3D')
    simple.move(x=2 * thick)
    simple.rotate(angleb)
    simple.move(x=length / 2)
    simple.mirrorx()
    simple.active_name('tmpmitreleft')
    simple.difference('tmp', 'tmprect')
    simple.make_active('tmprect')

    fingers(diameter, tolerance, amount, stem=stem)

    #  Generate male section and join to the base
    if which == 'M' or which == 'MF':
        simple.make_active('fingers')
        simple.duplicate()
        simple.active_name('tmpfingers')
        simple.rotate(angle - math.pi / 2)
        h = thick / math.cos(angle)
        h /= 2
        simple.move(x=length / 2 + h * math.sin(angle), y=-thick / 2)
        if which == 'M':
            simple.rename('fingers', 'tmpfingers')
            simple.rotate(angleb - math.pi / 2)
            h = thick / math.cos(angleb)
            h /= 2
            simple.move(x=length / 2 + h * math.sin(angleb), y=-thick / 2)
            simple.mirrorx()

        simple.union('tmp')
        simple.active_name('tmprect')

    # Generate female section and join to base
    if which == 'MF' or which == 'F':
        simple.make_active('receptacle')
        simple.mirrory()
        simple.duplicate()
        simple.active_name('tmpreceptacle')
        simple.rotate(angleb - math.pi / 2)
        h = thick / math.cos(angleb)
        h /= 2
        simple.move(x=length / 2 + h * math.sin(angleb), y=-thick / 2)
        simple.mirrorx()
        if which == 'F':
            simple.rename('receptacle', 'tmpreceptacle2')
            simple.rotate(angle - math.pi / 2)
            h = thick / math.cos(angle)
            h /= 2
            simple.move(x=length / 2 + h * math.sin(angle), y=-thick / 2)
        simple.difference('tmp', 'tmprect')

    simple.remove_multiple('receptacle')
    simple.remove_multiple('fingers')
    simple.rename('tmprect', 'mitre')
def arc(radius, thick, angle, diameter, tolerance, amount=0, stem=1, twist=False, tneck=0.5, tthick=0.01,
        twist_keep=False, which='MF'):
    # radius = radius of the curve
    # thick = thickness of the bar
    # angle = angle of the arc
    # diameter = diameter of the tool for joint creation
    # tolerance = Tolerance in the joint
    # amount = amount of fingers in the joint 0 means auto generate
    # stem = amount of radius the stem or neck of the joint will have
    # twist = twist lock addition
    # tneck = percentage the twist neck will have compared to thick
    # tthick = thicknest of the twist material
    # which = which joint to generate, Male Female MaleFemale M, F, MF

    global DT  # diameter tolerance for diameter of finger creation

    if angle == 0:  # angle cannot be 0
        angle = 0.01

    negative = False
    if angle < 0:  # if angle < 0 then negative is true
        angle = -angle
        negative = True

    if amount == 0:
        amount = round(thick / ((4 + 2 * (stem - 1)) * diameter * DT)) - 1

    fingers(diameter, tolerance, amount, stem=stem)
    twistf('receptacle', thick, diameter, tolerance, twist, tneck, tthick, twist_keep=twist_keep)

    # generate arc
    bpy.ops.curve.simple(align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), Simple_Type='Segment',
                         Simple_a=radius - thick / 2,
                         Simple_b=radius + thick / 2, Simple_startangle=-0.0001, Simple_endangle=math.degrees(angle),
                         Simple_radius=radius, use_cyclic_u=False, edit_mode=False)
    bpy.context.active_object.name = "tmparc"

    simple.rename('fingers', '_tmpfingers')

    simple.rotate(math.pi)
    simple.move(x=radius)
    bpy.ops.object.origin_set(type='ORIGIN_CURSOR', center='MEDIAN')

    simple.rename('tmparc', '_tmparc')
    if which == 'MF' or which == 'M':
        simple.union('_tmp')
        simple.active_name("base")
        twistm('base', thick, diameter, tolerance, twist, tneck, tthick, math.pi, x=radius)
        simple.rename('base', '_tmparc')

    simple.rename('receptacle', '_tmpreceptacle')
    simple.mirrory()
    simple.move(x=radius)
    bpy.ops.object.origin_set(type='ORIGIN_CURSOR', center='MEDIAN')
    simple.rotate(angle)
    simple.make_active('_tmparc')

    if which == 'MF' or which == 'F':
        simple.difference('_tmp', '_tmparc')
    bpy.context.active_object.name = "PUZZLE_arc"
    bpy.ops.object.curve_remove_doubles()
    simple.remove_multiple("_")  # Remove temporary base and holes
    simple.make_active('PUZZLE_arc')
    if which == 'M':
        simple.rotate(-angle)
        simple.mirrory()
        bpy.ops.object.transform_apply(location=True, rotation=True, scale=False)
        simple.rotate(-math.pi / 2)
        simple.move(y=radius)
        simple.rename('PUZZLE_arc', 'PUZZLE_arc_male')
    elif which == 'F':
        simple.mirrorx()
        simple.move(x=radius)
        simple.rotate(math.pi / 2)
        simple.rename('PUZZLE_arc', 'PUZZLE_arc_receptacle')
    else:
        simple.move(x=-radius)
    # bpy.ops.object.transform_apply(location=True, rotation=False, scale=False, properties=False)
    #
    if negative:  # mirror if angle is negative
        simple.mirrory()
Exemple #9
0
def medial_axis(o):
    print('operation: Medial Axis')

    simple.remove_multiple("medialMesh")

    from cam.voronoi import Site, computeVoronoiDiagram

    chunks = []

    gpoly = spolygon.Polygon()
    angle = o.cutter_tip_angle
    slope = math.tan(math.pi * (90 - angle / 2) / 180)  # angle in degrees
    # slope = math.tan((math.pi-angle)/2) #angle in radian
    new_cutter_diameter = o.cutter_diameter
    m_o_name = o.object_name
    if o.cutter_type == 'VCARVE':
        angle = o.cutter_tip_angle
        # start the max depth calc from the "start depth" of the operation.
        maxdepth = o.maxz - slope * o.cutter_diameter / 2
        # don't cut any deeper than the "end depth" of the operation.
        if maxdepth < o.minz:
            maxdepth = o.minz
            # the effective cutter diameter can be reduced from it's max
            # since we will be cutting shallower than the original maxdepth
            # without this, the curve is calculated as if the diameter was at the original maxdepth and we get the bit
            # pulling away from the desired cut surface
            new_cutter_diameter = (maxdepth - o.maxz) / (-slope) * 2
    elif o.cutter_type == 'BALLNOSE':
        maxdepth = -new_cutter_diameter / 2
    else:
        o.warnings += 'Only Ballnose, Ball and V-carve cutters\n are supported'
        return
    # remember resolutions of curves, to refine them,
    # otherwise medial axis computation yields too many branches in curved parts
    resolutions_before = []

    for ob in o.objects:
        if ob.type == 'CURVE' or ob.type == 'FONT':
            resolutions_before.append(ob.data.resolution_u)
            if ob.data.resolution_u < 64:
                ob.data.resolution_u = 64

    polys = utils.getOperationSilhouete(o)
    mpoly = sgeometry.shape(polys)
    mpoly_boundary = mpoly.boundary
    ipol = 0
    for poly in polys.geoms:
        ipol = ipol + 1
        print("polygon:", ipol)
        schunks = shapelyToChunks(poly, -1)
        schunks = chunksRefineThreshold(
            schunks, o.medial_axis_subdivision,
            o.medial_axis_threshold)  # chunksRefine(schunks,o)

        verts = []
        for ch in schunks:
            for pt in ch.points:
                # pvoro = Site(pt[0], pt[1])
                verts.append(pt)  # (pt[0], pt[1]), pt[2])
        # verts= points#[[vert.x, vert.y, vert.z] for vert in vertsPts]
        nDupli, nZcolinear = unique(verts)
        nVerts = len(verts)
        print(str(nDupli) + " duplicates points ignored")
        print(str(nZcolinear) + " z colinear points excluded")
        if nVerts < 3:
            print("Not enough points")
            return {'FINISHED'}
        # Check colinear
        xValues = [pt[0] for pt in verts]
        yValues = [pt[1] for pt in verts]
        if checkEqual(xValues) or checkEqual(yValues):
            print("Points are colinear")
            return {'FINISHED'}
        # Create diagram
        print("Tesselation... (" + str(nVerts) + " points)")
        xbuff, ybuff = 5, 5  # %
        zPosition = 0
        vertsPts = [Point(vert[0], vert[1], vert[2]) for vert in verts]
        # vertsPts= [Point(vert[0], vert[1]) for vert in verts]

        pts, edgesIdx = computeVoronoiDiagram(vertsPts,
                                              xbuff,
                                              ybuff,
                                              polygonsOutput=False,
                                              formatOutput=True)

        # pts=[[pt[0], pt[1], zPosition] for pt in pts]
        newIdx = 0
        vertr = []
        filteredPts = []
        print('filter points')
        ipts = 0
        for p in pts:
            ipts = ipts + 1
            if ipts % 500 == 0:
                sys.stdout.write('\r')
                # the exact output you're looking for:
                prog_message = "points: " + str(ipts) + " / " + str(
                    len(pts)) + " " + str(round(100 * ipts / len(pts))) + "%"
                sys.stdout.write(prog_message)
                sys.stdout.flush()

            if not poly.contains(sgeometry.Point(p)):
                vertr.append((True, -1))
            else:
                vertr.append((False, newIdx))
                if o.cutter_type == 'VCARVE':
                    # start the z depth calc from the "start depth" of the operation.
                    z = o.maxz - mpoly.boundary.distance(
                        sgeometry.Point(p)) * slope
                    if z < maxdepth:
                        z = maxdepth
                elif o.cutter_type == 'BALL' or o.cutter_type == 'BALLNOSE':
                    d = mpoly_boundary.distance(sgeometry.Point(p))
                    r = new_cutter_diameter / 2.0
                    if d >= r:
                        z = -r
                    else:
                        # print(r, d)
                        z = -r + sqrt(r * r - d * d)
                else:
                    z = 0  #
                # print(mpoly.distance(sgeometry.Point(0,0)))
                # if(z!=0):print(z)
                filteredPts.append((p[0], p[1], z))
                newIdx += 1

        print('filter edges')
        filteredEdgs = []
        ledges = []
        for e in edgesIdx:
            do = True
            # p1 = pts[e[0]]
            # p2 = pts[e[1]]
            # print(p1,p2,len(vertr))
            if vertr[e[0]][0]:  # exclude edges with allready excluded points
                do = False
            elif vertr[e[1]][0]:
                do = False
            if do:
                filteredEdgs.append((vertr[e[0]][1], vertr[e[1]][1]))
                ledges.append(
                    sgeometry.LineString((filteredPts[vertr[e[0]][1]],
                                          filteredPts[vertr[e[1]][1]])))
        # print(ledges[-1].has_z)

        bufpoly = poly.buffer(-new_cutter_diameter / 2, resolution=64)

        lines = shapely.ops.linemerge(ledges)
        # print(lines.type)

        if bufpoly.type == 'Polygon' or bufpoly.type == 'MultiPolygon':
            lines = lines.difference(bufpoly)
            chunks.extend(shapelyToChunks(bufpoly, maxdepth))
        chunks.extend(shapelyToChunks(lines, 0))

        # generate a mesh from the medial calculations
        if o.add_mesh_for_medial:
            polygon_utils_cam.shapelyToCurve('medialMesh', lines, 0.0)
            bpy.ops.object.convert(target='MESH')

    oi = 0
    for ob in o.objects:
        if ob.type == 'CURVE' or ob.type == 'FONT':
            ob.data.resolution_u = resolutions_before[oi]
            oi += 1

    # bpy.ops.object.join()
    chunks = utils.sortChunks(chunks, o)

    layers = getLayers(o, o.maxz, o.min.z)

    chunklayers = []

    for layer in layers:
        for chunk in chunks:
            if chunk.isbelowZ(layer[0]):
                newchunk = chunk.copy()
                newchunk.clampZ(layer[1])
                chunklayers.append(newchunk)

    if o.first_down:
        chunklayers = utils.sortChunks(chunklayers, o)

    if o.add_mesh_for_medial:  # make curve instead of a path
        simple.joinMultiple("medialMesh")

    chunksToMesh(chunklayers, o)
    # add pocket operation for medial if add pocket checked
    if o.add_pocket_for_medial:
        #        o.add_pocket_for_medial = False
        # export medial axis parameter to pocket op
        ops.Add_Pocket(None, maxdepth, m_o_name, new_cutter_diameter)
Exemple #10
0
def pocket(o):
    print('operation: pocket')
    scene = bpy.context.scene

    simple.remove_multiple("3D_poc")

    max_depth = checkminz(o)
    cutter_angle = math.radians(o.cutter_tip_angle / 2)
    c_offset = o.cutter_diameter / 2
    if o.cutter_type == 'VCARVE':
        c_offset = -max_depth * math.tan(cutter_angle)
    elif o.cutter_type == 'CYLCONE':
        c_offset = -max_depth * math.tan(cutter_angle) + o.cylcone_diameter / 2
    elif o.cutter_type == 'BALLCONE':
        c_offset = -max_depth * math.tan(cutter_angle) + o.ball_radius
    if c_offset > o.cutter_diameter / 2:
        c_offset = o.cutter_diameter / 2

    p = utils.getObjectOutline(c_offset, o, False)
    approxn = (min(o.max.x - o.min.x, o.max.y - o.min.y) /
               o.dist_between_paths) / 2
    print("approximative:" + str(approxn))
    print(o)

    i = 0
    chunks = []
    chunksFromCurve = []
    lastchunks = []
    centers = None
    firstoutline = p  # for testing in the end.
    prest = p.buffer(-c_offset, o.circle_detail)
    while not p.is_empty:
        if o.pocketToCurve:
            polygon_utils_cam.shapelyToCurve(
                '3dpocket', p, 0.0)  # make a curve starting with _3dpocket

        nchunks = shapelyToChunks(p, o.min.z)
        # print("nchunks")
        pnew = p.buffer(-o.dist_between_paths, o.circle_detail)
        # print("pnew")

        nchunks = limitChunks(nchunks, o)
        chunksFromCurve.extend(nchunks)
        parentChildDist(lastchunks, nchunks, o)
        lastchunks = nchunks

        percent = int(i / approxn * 100)
        progress('outlining polygons ', percent)
        p = pnew

        i += 1

    # if (o.poc)#TODO inside outside!
    if (o.movement_type == 'CLIMB' and o.spindle_rotation_direction
            == 'CW') or (o.movement_type == 'CONVENTIONAL'
                         and o.spindle_rotation_direction == 'CCW'):
        for ch in chunksFromCurve:
            ch.points.reverse()

    chunksFromCurve = utils.sortChunks(chunksFromCurve, o)

    chunks = []
    layers = getLayers(o, o.maxz, checkminz(o))

    for l in layers:
        lchunks = setChunksZ(chunksFromCurve, l[1])
        if o.ramp:
            for ch in lchunks:
                ch.zstart = l[0]
                ch.zend = l[1]

        # helix_enter first try here TODO: check if helix radius is not out of operation area.
        if o.helix_enter:
            helix_radius = c_offset * o.helix_diameter * 0.01  # 90 percent of cutter radius
            helix_circumference = helix_radius * pi * 2

            revheight = helix_circumference * tan(o.ramp_in_angle)
            for chi, ch in enumerate(lchunks):
                if not chunksFromCurve[chi].children:
                    p = ch.points[
                        0]  # TODO:intercept closest next point when it should stay low
                    # first thing to do is to check if helix enter can really enter.
                    checkc = Circle(helix_radius + c_offset, o.circle_detail)
                    checkc = affinity.translate(checkc, p[0], p[1])
                    covers = False
                    for poly in o.silhouete:
                        if poly.contains(checkc):
                            covers = True
                            break

                    if covers:
                        revolutions = (l[0] - p[2]) / revheight
                        # print(revolutions)
                        h = Helix(helix_radius, o.circle_detail, l[0], p,
                                  revolutions)
                        # invert helix if not the typical direction
                        if (o.movement_type == 'CONVENTIONAL'
                                and o.spindle_rotation_direction == 'CW') or (
                                    o.movement_type == 'CLIMB'
                                    and o.spindle_rotation_direction == 'CCW'):
                            nhelix = []
                            for v in h:
                                nhelix.append((2 * p[0] - v[0], v[1], v[2]))
                            h = nhelix
                        ch.points = h + ch.points
                    else:
                        o.warnings = o.warnings + 'Helix entry did not fit! \n '
                        ch.closed = True
                        ch.rampZigZag(l[0], l[1], o)
        # Arc retract here first try:
        if o.retract_tangential:  # TODO: check for entry and exit point before actual computing... will be much better.
            # TODO: fix this for CW and CCW!
            for chi, ch in enumerate(lchunks):
                # print(chunksFromCurve[chi])
                # print(chunksFromCurve[chi].parents)
                if chunksFromCurve[chi].parents == [] or len(
                        chunksFromCurve[chi].parents) == 1:

                    revolutions = 0.25
                    v1 = Vector(ch.points[-1])
                    i = -2
                    v2 = Vector(ch.points[i])
                    v = v1 - v2
                    while v.length == 0:
                        i = i - 1
                        v2 = Vector(ch.points[i])
                        v = v1 - v2

                    v.normalize()
                    rotangle = Vector((v.x, v.y)).angle_signed(Vector((1, 0)))
                    e = Euler((0, 0, pi / 2.0))  # TODO:#CW CLIMB!
                    v.rotate(e)
                    p = v1 + v * o.retract_radius
                    center = p
                    p = (p.x, p.y, p.z)

                    # progress(str((v1,v,p)))
                    h = Helix(o.retract_radius, o.circle_detail,
                              p[2] + o.retract_height, p, revolutions)

                    e = Euler(
                        (0, 0,
                         rotangle + pi))  # angle to rotate whole retract move
                    rothelix = []
                    c = []  # polygon for outlining and checking collisions.
                    for p in h:  # rotate helix to go from tangent of vector
                        v1 = Vector(p)

                        v = v1 - center
                        v.x = -v.x  # flip it here first...
                        v.rotate(e)
                        p = center + v
                        rothelix.append(p)
                        c.append((p[0], p[1]))

                    c = sgeometry.Polygon(c)
                    # print('çoutline')
                    # print(c)
                    coutline = c.buffer(c_offset, o.circle_detail)
                    # print(h)
                    # print('çoutline')
                    # print(coutline)
                    # polyToMesh(coutline,0)
                    rothelix.reverse()

                    covers = False
                    for poly in o.silhouete:
                        if poly.contains(coutline):
                            covers = True
                            break

                    if covers:
                        ch.points.extend(rothelix)

        chunks.extend(lchunks)

    if o.ramp:
        for ch in chunks:
            ch.rampZigZag(ch.zstart, ch.points[0][2], o)

    if o.first_down:
        chunks = utils.sortChunks(chunks, o)

    if o.pocketToCurve:  # make curve instead of a path
        simple.joinMultiple("3dpocket")

    else:
        chunksToMesh(chunks, o)  # make normal pocket path
Exemple #11
0
def variable_finger(loop,
                    loop_length,
                    min_finger,
                    finger_size,
                    finger_thick,
                    finger_tolerance,
                    adaptive,
                    base=False,
                    double_adaptive=False):
    #   distributes mortises of a fixed distance
    #   dynamically changes the finger tolerance with the angle differences
    #   loop = takes in a shapely shape
    #   finger_size = size of the mortise
    #   finger_thick = thickness of the material
    #   finger_tolerance = minimum finger tolerance
    #   adaptive = angle threshold to reduce finger size

    coords = list(loop.coords)
    old_mortise_angle = 0
    distance = min_finger / 2
    finger_sz = min_finger
    oldfinger_sz = min_finger
    hpos = []  # hpos is the horizontal positions of the middle of the mortise
    # slope_array(loop)
    print("joinery loop length", round(loop_length * 1000), "mm")
    for i, p in enumerate(coords):
        if i == 0:
            p_start = p

        if p != p_start:
            not_start = True
        else:
            not_start = False
        pd = loop.project(Point(p))

        if not_start:
            while distance <= pd:
                mortise_angle = angle(oldp, p)
                mortise_angle_difference = abs(mortise_angle -
                                               old_mortise_angle)
                mad = (1 + 6 * min(mortise_angle_difference, math.pi / 4) /
                       (math.pi / 4))  # factor for tolerance for the finger
                distance += mad * finger_tolerance  # move finger by the factor mad greater with larger angle difference
                mortise_point = loop.interpolate(distance)
                if mad > 2 and double_adaptive:
                    hpos.append(distance)  # saves the mortise center

                hpos.append(distance + finger_sz)  # saves the mortise center
                if base:
                    mortise(finger_sz, finger_thick, finger_tolerance * mad,
                            distance + finger_sz, 0, 0)
                    simple.active_name("_base")
                else:
                    mortise(finger_sz, finger_thick, finger_tolerance * mad,
                            mortise_point.x, mortise_point.y, mortise_angle)
                    if i == 1:
                        #  put a mesh cylinder at the first coordinates to indicate start
                        simple.remove_multiple("start_here")
                        bpy.ops.mesh.primitive_cylinder_add(
                            radius=finger_thick / 2,
                            depth=0.025,
                            enter_editmode=False,
                            align='WORLD',
                            location=(mortise_point.x, mortise_point.y, 0),
                            scale=(1, 1, 1))
                        simple.active_name("start_here_mortise")

                old_distance = distance
                old_mortise_point = mortise_point
                finger_sz = finger_size
                next_angle_difference = math.pi

                #   adaptive finger length start
                while finger_sz > min_finger and next_angle_difference > adaptive:
                    finger_sz *= 0.95  # reduce the size of finger by a percentage... the closer to 1.0, the slower
                    distance = old_distance + 3 * oldfinger_sz / 2 + finger_sz / 2
                    mortise_point = loop.interpolate(
                        distance)  # get the next mortise point
                    next_mortise_angle = angle(
                        (old_mortise_point.x, old_mortise_point.y),
                        (mortise_point.x,
                         mortise_point.y))  # calculate next angle
                    next_angle_difference = abs(next_mortise_angle -
                                                mortise_angle)

                oldfinger_sz = finger_sz
                old_mortise_angle = mortise_angle
        oldp = p
    if base:
        simple.join_multiple("_base")
        simple.active_name("base")
    else:
        print("placeholder")
        simple.join_multiple("_mort")
        simple.active_name("variable_mortise")
    return hpos