Exemple #1
0
def getBridgesPoly(o):
    if not hasattr(o, 'bridgespolyorig'):
        bridgecollectionname = o.bridges_collection_name
        bridgecollection = bpy.data.collections[bridgecollectionname]
        shapes = []
        bpy.ops.object.select_all(action='DESELECT')

        for ob in bridgecollection.objects:
            if ob.type == 'CURVE':
                ob.select_set(state=True)
        bpy.context.view_layer.objects.active = ob
        bpy.ops.object.duplicate()
        bpy.ops.object.join()
        ob = bpy.context.active_object
        shapes.extend(utils.curveToShapely(ob, o.use_bridge_modifiers))
        ob.select_set(state=True)
        bpy.ops.object.delete(use_global=False)
        bridgespoly = sops.unary_union(shapes)

        # buffer the poly, so the bridges are not actually milled...
        o.bridgespolyorig = bridgespoly.buffer(distance=o.cutter_diameter /
                                               2.0)
        o.bridgespoly_boundary = o.bridgespolyorig.boundary
        o.bridgespoly_boundary_prep = prepared.prep(o.bridgespolyorig.boundary)
        o.bridgespoly = prepared.prep(o.bridgespolyorig)
Exemple #2
0
def addAutoBridges(o):
    """attempt to add auto bridges as set of curves"""
    utils.getOperationSources(o)
    # if not o.onlycurves:
    #	o.warnings+=('not curves')
    #	return;
    bridgecollectionname = o.bridges_collection_name
    if bridgecollectionname == '' or bpy.data.collections.get(
            bridgecollectionname) == None:
        bridgecollectionname = 'bridges_' + o.name
        bpy.data.collections.new(bridgecollectionname)
        bpy.context.collection.children.link(
            bpy.data.collections[bridgecollectionname])
    g = bpy.data.collections[bridgecollectionname]
    o.bridges_collection_name = bridgecollectionname
    for ob in o.objects:

        if ob.type == 'CURVE' or ob.type == 'TEXT':
            curve = utils.curveToShapely(ob)
        if ob.type == 'MESH':
            curve = utils.getObjectSilhouete('OBJECTS', [ob])
        # curve = shapelyToMultipolygon(curve)
        for c in curve:
            c = c.exterior
            minx, miny, maxx, maxy = c.bounds
            d1 = c.project(sgeometry.Point(maxx + 1000, (maxy + miny) / 2.0))
            p = c.interpolate(d1)
            bo = addBridge(p.x, p.y, -math.pi / 2, o.bridges_width,
                           o.cutter_diameter * 1)
            g.objects.link(bo)
            bpy.context.collection.objects.unlink(bo)
            d1 = c.project(sgeometry.Point(minx - 1000, (maxy + miny) / 2.0))
            p = c.interpolate(d1)
            bo = addBridge(p.x, p.y, math.pi / 2, o.bridges_width,
                           o.cutter_diameter * 1)
            g.objects.link(bo)
            bpy.context.collection.objects.unlink(bo)
            d1 = c.project(sgeometry.Point((minx + maxx) / 2.0, maxy + 1000))
            p = c.interpolate(d1)
            bo = addBridge(p.x, p.y, 0, o.bridges_width, o.cutter_diameter * 1)
            g.objects.link(bo)
            bpy.context.collection.objects.unlink(bo)
            d1 = c.project(sgeometry.Point((minx + maxx) / 2.0, miny - 1000))
            p = c.interpolate(d1)
            bo = addBridge(p.x, p.y, math.pi, o.bridges_width,
                           o.cutter_diameter * 1)
            g.objects.link(bo)
            bpy.context.collection.objects.unlink(bo)
Exemple #3
0
	def execute(self, context):
		o1 = bpy.context.active_object
		shapes = utils.curveToShapely(o1)
		negative_overcuts = []
		positive_overcuts = []
		# count all the corners including inside and out
		cornerCnt = 0
		# a list of tuples for defining the inside corner 
		# tuple is: (pos, v1, v2, angle, allCorners list index)
		insideCorners = []
		diameter = self.diameter * 1.001
		radius = diameter / 2
		anglethreshold = math.pi - self.threshold
		centerv = Vector((0,0))
		extendedv = Vector((0,0))
		pos = Vector((0,0))
		sign = -1 if self.do_invert else 1
		isTBone = self.style == 'TBONE'
		# indexes in insideCorner tuple
		POS, V1, V2, A, IDX = range(5)
		
		def addOvercut(a):
			nonlocal pos, centerv, radius, extendedv, sign, negative_overcuts, positive_overcuts
			# move the overcut shape center position 1 radius in direction v
			pos -= centerv * radius
			if abs(a) < math.pi/2:
				shape = utils.Circle(radius, 64)
				shape = shapely.affinity.translate(shape, pos.x, pos.y)
			else: # elongate overcut circle to make sure tool bit can fit into slot
				p1 = pos + (extendedv * radius)
				l = shapely.geometry.LineString((pos, p1))
				shape = l.buffer(radius, resolution = 64)
			
			if sign>0:
				negative_overcuts.append(shape)
			else:	
				positive_overcuts.append(shape)


		def setOtherEdge(v1, v2, a):
			nonlocal centerv, extendedv
			if self.otherEdge:
				centerv = v1
				extendedv = v2
			else:
				centerv = -v2
				extendedv = -v1
			addOvercut(a)
				
		def setCenterOffset(a):
			nonlocal centerv, extendedv, sign
			centerv = v1 - v2
			centerv.normalize()
			extendedv = centerv * math.tan(a/2) * -sign
			addOvercut(a)
			
			
		def getCorner(idx, offset):
			nonlocal insideCorners
			idx += offset
			if idx >= len(insideCorners):
				idx -= len(insideCorners)
			return insideCorners[idx]
			
		def getCornerDelta(curidx, nextidx):
			nonlocal cornerCnt
			delta = nextidx - curidx
			if delta < 0:
				delta += cornerCnt
			return delta
			

		for s in shapes:
			s = shapely.geometry.polygon.orient(s,1)
			loops = [s.boundary] if s.boundary.type == 'LineString'	else s.boundary
			outercurve = self.do_outer or len(loops)==1
			for ci,c in enumerate(loops):
				if ci>0 or outercurve:
					if isTBone:
						cornerCnt = 0
						insideCorners = []
						
					for i,co in enumerate(c.coords):
						i1 = i-1
						if i1==-1:
							i1 = -2
						i2 = i+1
						if i2 == len(c.coords):
							i2 = 0
							
						v1 = Vector(co).xy - Vector(c.coords[i1]).xy
						v2 = Vector(c.coords[i2]).xy - Vector(co).xy

						if not v1.length==0 and not v2.length == 0:
							a = v1.angle_signed(v2)
							insideCornerFound = False
							outsideCornerFound = False
							if a<-anglethreshold:
								if sign<0:
									insideCornerFound = True
								else:
									outsideCornerFound = True
							elif a>anglethreshold:
								if sign>0:
									insideCornerFound = True
								else:
									outsideCornerFound = True
									
							
							if insideCornerFound:
								# an inside corner with an overcut has been found
								# which means a new side has been found
								pos = Vector((co[0],co[1]))
								v1.normalize()
								v2.normalize()
								# figure out which direction vector to use
								# v is the main direction vector to move the overcut shape along
								# ev is the direction vector used to elongate the overcut shape
								if self.style != 'DOGBONE':
									# t-bone and opposite edge styles get treated nearly the same
									if isTBone:
										cornerCnt += 1
										#insideCorner tuplet: (pos, v1, v2, angle, corner index)
										insideCorners.append((pos, v1, v2, a, cornerCnt-1))
										#processing of corners for T-Bone are done after all points are processed
										continue
									
									setOtherEdge(v1, v2, a)
										
								else: # DOGBONE style
									setCenterOffset(a)
									
								
							elif isTBone and outsideCornerFound:
								# add an outside corner to the list
								cornerCnt += 1	

					# check if t-bone processing required
					# if no inside corners then nothing to do
					if isTBone and len(insideCorners) > 0:
						#print(cornerCnt, len(insideCorners))
						# process all of the inside corners
						for i, corner in enumerate(insideCorners):
							pos, v1, v2, a, idx = corner
							# figure out which side of the corner to do overcut
							# if prev corner is outside corner
							# calc index distance between current corner and prev
							prevCorner = getCorner(i, -1)
							#print('first:', i, idx, prevCorner[IDX])
							if getCornerDelta(prevCorner[IDX], idx) == 1:
								# make sure there is an outside corner
								#print(getCornerDelta(getCorner(i, -2)[IDX], idx))
								if getCornerDelta(getCorner(i, -2)[IDX], idx) > 2:
									setOtherEdge(v1, v2, a)
									#print('first won')
									continue
									
							nextCorner = getCorner(i, 1)
							#print('second:', i, idx, nextCorner[IDX])
							if getCornerDelta(idx, nextCorner[IDX]) == 1:
								# make sure there is an outside corner 
								#print(getCornerDelta(idx, getCorner(i, 2)[IDX]))
								if getCornerDelta(idx, getCorner(i, 2)[IDX]) > 2:
									#print('second won')
									setOtherEdge(-v2, -v1, a)
									continue
							
							#print('third')
							if getCornerDelta(prevCorner[IDX], idx) == 3:
								# check if they share the same edge
								a1 = v1.angle_signed(prevCorner[V2])*180.0/math.pi
								#print('third won', a1)
								if a1 < -135 or a1 > 135:
									setOtherEdge(-v2, -v1, a)
									continue
							
							#print('fourth')
							if getCornerDelta(idx, nextCorner[IDX]) == 3:
								# check if they share the same edge
								a1 = v2.angle_signed(nextCorner[V1])*180.0/math.pi
								#print('fourth won', a1)
								if a1 < -135 or a1 > 135:
									setOtherEdge(v1, v2, a)
									continue
							
							#print('***No Win***')
							# the default if no other rules pass	
							setCenterOffset(a)
								
							
						
						
		negative_overcuts = shapely.ops.unary_union(negative_overcuts)
		positive_overcuts = shapely.ops.unary_union(positive_overcuts)
		fs = shapely.ops.unary_union(shapes)
		fs = fs.union(positive_overcuts)
		fs = fs.difference(negative_overcuts)
		o=utils.shapelyToCurve(o1.name+'_overcuts',fs,o1.location.z)
		return {'FINISHED'}	
Exemple #4
0
	def execute(self, context):
		#utils.silhoueteOffset(context,-self.diameter)
		o1=bpy.context.active_object
		shapes=utils.curveToShapely(o1)
		negative_overcuts=[]
		positive_overcuts=[]
		diameter = self.diameter*1.001
		for s in shapes:
				s=shapely.geometry.polygon.orient(s,1)
				if s.boundary.type == 'LineString':
					loops = [s.boundary]#s=shapely.geometry.asMultiLineString(s)
				else:	
					loops = s.boundary
				
				for ci,c in enumerate(loops):
					if ci>0 or self.do_outer:
						#c=s.boundary
						for i,co in enumerate(c.coords):
							i1=i-1
							if i1==-1:
								i1=-2
							i2=i+1
							if i2 == len(c.coords):
								i2=0
								
							v1 = Vector(co) - Vector(c.coords[i1])
							v1 = v1.xy#Vector((v1.x,v1.y,0))
							v2 = Vector(c.coords[i2]) - Vector(co)
							v2 = v2.xy#v2 = Vector((v2.x,v2.y,0))
							if not v1.length==0 and not v2.length == 0:
								a=v1.angle_signed(v2)
								sign=1
								#if ci==0:
								#	sign=-1
								#else:
								#	sign=1
								
								if self.invert:# and ci>0:
									sign*=-1
								if (sign<0 and a<-self.threshold) or (sign>0 and a>self.threshold):
									p=Vector((co[0],co[1]))
									v1.normalize()
									v2.normalize()
									v=v1-v2
									v.normalize()
									p=p-v*diameter/2
									if abs(a)<math.pi/2:
										shape=utils.Circle(diameter/2,64)
										shape= shapely.affinity.translate(shape,p.x,p.y)
									else:
										l=math.tan(a/2)*diameter/2
										p1=p-sign*v*l
										l=shapely.geometry.LineString((p,p1))
										shape=l.buffer(diameter/2, resolution = 64)
									
									if sign>0:
										negative_overcuts.append(shape)
									else:	
										positive_overcuts.append(shape)
									
								print(a)
					
							
				#for c in s.boundary:
		negative_overcuts = shapely.ops.unary_union(negative_overcuts)
		positive_overcuts = shapely.ops.unary_union(positive_overcuts)
		#shapes.extend(overcuts)
		fs=shapely.ops.unary_union(shapes)
		fs = fs.union(positive_overcuts)
		fs = fs.difference(negative_overcuts)
		o=utils.shapelyToCurve(o1.name+'_overcuts',fs,o1.location.z)
		#o=utils.shapelyToCurve('overcuts',overcuts,0)
		return {'FINISHED'}	
Exemple #5
0
    def execute(self, context):
        #utils.silhoueteOffset(context,-self.diameter)
        o1 = bpy.context.active_object
        shapes = utils.curveToShapely(o1)
        negative_overcuts = []
        positive_overcuts = []
        diameter = self.diameter * 1.001
        for s in shapes:
            s = shapely.geometry.polygon.orient(s, 1)
            if s.boundary.type == 'LineString':
                loops = [s.boundary]  #s=shapely.geometry.asMultiLineString(s)
            else:
                loops = s.boundary

            for ci, c in enumerate(loops):
                if ci > 0 or self.do_outer:
                    #c=s.boundary
                    for i, co in enumerate(c.coords):
                        i1 = i - 1
                        if i1 == -1:
                            i1 = -2
                        i2 = i + 1
                        if i2 == len(c.coords):
                            i2 = 0

                        v1 = Vector(co) - Vector(c.coords[i1])
                        v1 = v1.xy  #Vector((v1.x,v1.y,0))
                        v2 = Vector(c.coords[i2]) - Vector(co)
                        v2 = v2.xy  #v2 = Vector((v2.x,v2.y,0))
                        if not v1.length == 0 and not v2.length == 0:
                            a = v1.angle_signed(v2)
                            sign = 1
                            #if ci==0:
                            #	sign=-1
                            #else:
                            #	sign=1

                            if self.invert:  # and ci>0:
                                sign *= -1
                            if (sign < 0 and a < -self.threshold) or (
                                    sign > 0 and a > self.threshold):
                                p = Vector((co[0], co[1]))
                                v1.normalize()
                                v2.normalize()
                                v = v1 - v2
                                v.normalize()
                                p = p - v * diameter / 2
                                if abs(a) < math.pi / 2:
                                    shape = utils.Circle(diameter / 2, 64)
                                    shape = shapely.affinity.translate(
                                        shape, p.x, p.y)
                                else:
                                    l = math.tan(a / 2) * diameter / 2
                                    p1 = p - sign * v * l
                                    l = shapely.geometry.LineString((p, p1))
                                    shape = l.buffer(diameter / 2,
                                                     resolution=64)

                                if sign > 0:
                                    negative_overcuts.append(shape)
                                else:
                                    positive_overcuts.append(shape)

                            print(a)

            #for c in s.boundary:
        negative_overcuts = shapely.ops.unary_union(negative_overcuts)
        positive_overcuts = shapely.ops.unary_union(positive_overcuts)
        #shapes.extend(overcuts)
        fs = shapely.ops.unary_union(shapes)
        fs = fs.union(positive_overcuts)
        fs = fs.difference(negative_overcuts)
        o = utils.shapelyToCurve(o1.name + '_overcuts', fs, o1.location.z)
        #o=utils.shapelyToCurve('overcuts',overcuts,0)
        return {'FINISHED'}
Exemple #6
0
    def execute(self, context):
        o1 = bpy.context.active_object
        shapes = utils.curveToShapely(o1)
        negative_overcuts = []
        positive_overcuts = []
        # count all the corners including inside and out
        cornerCnt = 0
        # a list of tuples for defining the inside corner
        # tuple is: (pos, v1, v2, angle, allCorners list index)
        insideCorners = []
        diameter = self.diameter * 1.001
        radius = diameter / 2
        anglethreshold = math.pi - self.threshold
        centerv = mathutils.Vector((0, 0))
        extendedv = mathutils.Vector((0, 0))
        pos = mathutils.Vector((0, 0))
        sign = -1 if self.do_invert else 1
        isTBone = self.style == 'TBONE'
        # indexes in insideCorner tuple
        POS, V1, V2, A, IDX = range(5)

        def addOvercut(a):
            nonlocal pos, centerv, radius, extendedv, sign, negative_overcuts, positive_overcuts
            # move the overcut shape center position 1 radius in direction v
            pos -= centerv * radius
            if abs(a) < math.pi / 2:
                shape = utils.Circle(radius, 64)
                shape = shapely.affinity.translate(shape, pos.x, pos.y)
            else:  # elongate overcut circle to make sure tool bit can fit into slot
                p1 = pos + (extendedv * radius)
                l = shapely.geometry.LineString((pos, p1))
                shape = l.buffer(radius, resolution=64)

            if sign > 0:
                negative_overcuts.append(shape)
            else:
                positive_overcuts.append(shape)

        def setOtherEdge(v1, v2, a):
            nonlocal centerv, extendedv
            if self.otherEdge:
                centerv = v1
                extendedv = v2
            else:
                centerv = -v2
                extendedv = -v1
            addOvercut(a)

        def setCenterOffset(a):
            nonlocal centerv, extendedv, sign
            centerv = v1 - v2
            centerv.normalize()
            extendedv = centerv * math.tan(a / 2) * -sign
            addOvercut(a)

        def getCorner(idx, offset):
            nonlocal insideCorners
            idx += offset
            if idx >= len(insideCorners):
                idx -= len(insideCorners)
            return insideCorners[idx]

        def getCornerDelta(curidx, nextidx):
            nonlocal cornerCnt
            delta = nextidx - curidx
            if delta < 0:
                delta += cornerCnt
            return delta

        for s in shapes:
            s = shapely.geometry.polygon.orient(s, 1)
            loops = [s.boundary
                     ] if s.boundary.type == 'LineString' else s.boundary
            outercurve = self.do_outer or len(loops) == 1
            for ci, c in enumerate(loops):
                if ci > 0 or outercurve:
                    if isTBone:
                        cornerCnt = 0
                        insideCorners = []

                    for i, co in enumerate(c.coords):
                        i1 = i - 1
                        if i1 == -1:
                            i1 = -2
                        i2 = i + 1
                        if i2 == len(c.coords):
                            i2 = 0

                        v1 = mathutils.Vector(co).xy - mathutils.Vector(
                            c.coords[i1]).xy
                        v2 = mathutils.Vector(
                            c.coords[i2]).xy - mathutils.Vector(co).xy

                        if not v1.length == 0 and not v2.length == 0:
                            a = v1.angle_signed(v2)
                            insideCornerFound = False
                            outsideCornerFound = False
                            if a < -anglethreshold:
                                if sign < 0:
                                    insideCornerFound = True
                                else:
                                    outsideCornerFound = True
                            elif a > anglethreshold:
                                if sign > 0:
                                    insideCornerFound = True
                                else:
                                    outsideCornerFound = True

                            if insideCornerFound:
                                # an inside corner with an overcut has been found
                                # which means a new side has been found
                                pos = mathutils.Vector((co[0], co[1]))
                                v1.normalize()
                                v2.normalize()
                                # figure out which direction vector to use
                                # v is the main direction vector to move the overcut shape along
                                # ev is the direction vector used to elongate the overcut shape
                                if self.style != 'DOGBONE':
                                    # t-bone and opposite edge styles get treated nearly the same
                                    if isTBone:
                                        cornerCnt += 1
                                        # insideCorner tuplet: (pos, v1, v2, angle, corner index)
                                        insideCorners.append(
                                            (pos, v1, v2, a, cornerCnt - 1))
                                        # processing of corners for T-Bone are done after all points are processed
                                        continue

                                    setOtherEdge(v1, v2, a)

                                else:  # DOGBONE style
                                    setCenterOffset(a)

                            elif isTBone and outsideCornerFound:
                                # add an outside corner to the list
                                cornerCnt += 1

                    # check if t-bone processing required
                    # if no inside corners then nothing to do
                    if isTBone and len(insideCorners) > 0:
                        # print(cornerCnt, len(insideCorners))
                        # process all of the inside corners
                        for i, corner in enumerate(insideCorners):
                            pos, v1, v2, a, idx = corner
                            # figure out which side of the corner to do overcut
                            # if prev corner is outside corner
                            # calc index distance between current corner and prev
                            prevCorner = getCorner(i, -1)
                            # print('first:', i, idx, prevCorner[IDX])
                            if getCornerDelta(prevCorner[IDX], idx) == 1:
                                # make sure there is an outside corner
                                # print(getCornerDelta(getCorner(i, -2)[IDX], idx))
                                if getCornerDelta(getCorner(i, -2)[IDX],
                                                  idx) > 2:
                                    setOtherEdge(v1, v2, a)
                                    # print('first won')
                                    continue

                            nextCorner = getCorner(i, 1)
                            # print('second:', i, idx, nextCorner[IDX])
                            if getCornerDelta(idx, nextCorner[IDX]) == 1:
                                # make sure there is an outside corner
                                # print(getCornerDelta(idx, getCorner(i, 2)[IDX]))
                                if getCornerDelta(idx,
                                                  getCorner(i, 2)[IDX]) > 2:
                                    # print('second won')
                                    setOtherEdge(-v2, -v1, a)
                                    continue

                            # print('third')
                            if getCornerDelta(prevCorner[IDX], idx) == 3:
                                # check if they share the same edge
                                a1 = v1.angle_signed(
                                    prevCorner[V2]) * 180.0 / math.pi
                                # print('third won', a1)
                                if a1 < -135 or a1 > 135:
                                    setOtherEdge(-v2, -v1, a)
                                    continue

                            # print('fourth')
                            if getCornerDelta(idx, nextCorner[IDX]) == 3:
                                # check if they share the same edge
                                a1 = v2.angle_signed(
                                    nextCorner[V1]) * 180.0 / math.pi
                                # print('fourth won', a1)
                                if a1 < -135 or a1 > 135:
                                    setOtherEdge(v1, v2, a)
                                    continue

                            # print('***No Win***')
                            # the default if no other rules pass
                            setCenterOffset(a)

        negative_overcuts = shapely.ops.unary_union(negative_overcuts)
        positive_overcuts = shapely.ops.unary_union(positive_overcuts)
        fs = shapely.ops.unary_union(shapes)
        fs = fs.union(positive_overcuts)
        fs = fs.difference(negative_overcuts)
        o = utils.shapelyToCurve(o1.name + '_overcuts', fs, o1.location.z)
        return {'FINISHED'}