#!/usr/bin/env python3 # We will use the inkex module with the predefined Effect base class. import inkex import math from fablabchemnitz_inkscape_path import * from lxml import etree #Constants defined here WoodHingeSize = 3 #To be multiplied by thickness WoodHingeInternalCircle = 2 #To be multiplied by thickness WoodHingeRect = 1.5 #To be multiplied by thickness SteelHingeSpacing = 0.3 RadiusSteelHingeAxis = 1.3 #Use axis about 2.4mm diameter, I use nails 2.3mmx70mm MinMove = 1e-2 #Minimum distance betwwen two points (0.01 mm !) #Global variables used for the whole program thickness = 0 burn = 0 fDebug = None def distance2Points(x0, y0, x1, y1): return math.sqrt((x1-x0)**2 + (y1-y0)**2) def DebugMsg(s): ''' Print a debug message into debug file if debug file is defined ''' if fDebug: fDebug.write(s) def OpenDebugFile(): global fDebug try: fDebug = open( 'DebugGenericBox.txt', 'w') except IOError: pass DebugMsg("Start processing\n") def CloseDebugFile(): global fDebug if fDebug: fDebug.close() fDebug = None def drawHole(path, x0, y0, dx, dy, burn): ''' Add a rectangle starting at x0,y0 and with a length dx and width dy to the current path burn is the burn factor, so actual coordinates are modified by burn/2 ''' path.MoveTo(x0+burn/2, y0+burn/2) path.LineToVRel(dy-burn) path.LineToHRel(dx-burn) path.LineToVRel(-dy+burn) path.LineToHRel(-dx+burn) class Ellipse: ''' This class defines some functions that will be used with the coffin style lid ''' def __init__(self, a, b): ''' a and b are the ellipse parameters ''' self.a = a self.b = b self.Start = 0 def length(self): ''' Compute a rather good approwimation of the ellipse length. Use the formula Ramanujan 2 ''' h = (self.a - self.b)*(self.a - self.b)/((self.a + self.b)*(self.a + self.b)) l = math.pi*(self.a+self.b)*(1.0 + 3*h/(10.0+math.sqrt(4.0-3*h))) return l def length2Angle(self, l): ''' Compute the angle which gives the given length on the ellipse. The ellipse perimeter couldn't be computed from known functions, so we use a discrete integral computation In order to save time, this function should be called with increasing value of l, i.e. it doesn't recompute values less than previous parameter l ''' CurDistance = PrevDistance = self.LastDistance index = self.CurPoint while CurDistance < l and index < self.nPoints: PrevDistance = CurDistance Alpha = (index +0.5)* self.StepAngle + self.Start CurDistance += self.StepAngle*math.sqrt((self.a*math.sin(Alpha))**2 + (self.b*math.cos(Alpha))**2) index += 1 #Will stop here, record values self.LastDistance = CurDistance self.CurPoint = index #Interpolate between the last points to increase precision if CurDistance > PrevDistance: Delta = (l - PrevDistance)/(CurDistance - PrevDistance)*self.StepAngle return (index-1)*self.StepAngle + Delta + self.Start else: return index*self.StepAngle + self.Start def Compute_Ellipse_Params(self, Start, End): self.length_ellipse = self.length() * (End - Start)/math.pi/2.0 self.Start = Start self.End = End #Compute length between notches, each notch is about 2mm wide, total length is 2*( l_between_notches + 1) if self.length_ellipse < 80: self.l_between_notches = 1 elif self.length_ellipse < 150: self.l_between_notches = 2 elif self.length_ellipse < 250: self.l_between_notches = 3 else: self.l_between_notches = 4 self.nb_Ellipse_Notch = int(round(self.length_ellipse / (2*( self.l_between_notches + 1) + 2),0)) #Add a notch at the end self.size_Ellipse_Notch = self.length_ellipse / (self.nb_Ellipse_Notch *( self.l_between_notches + 1) + 1) self.Size_betweenNotches = self.l_between_notches*self.size_Ellipse_Notch self.nb_point_between_notches = int(round(self.Size_betweenNotches)) self.SizeBetweenPoints = self.Size_betweenNotches / self.nb_point_between_notches DebugMsg("Ellipse length ="+str(self.length_ellipse)+" nb_Ellipse_Notch="+str(self.nb_Ellipse_Notch) +" size_Ellipse_Notch="+str(self.size_Ellipse_Notch)+" Distance between notches="+str((self.l_between_notches+1)*self.size_Ellipse_Notch) +"mm, Nb point_between nocthes="+str(self.nb_point_between_notches) +" Total Size Notch ="+str(self.size_Ellipse_Notch*self.nb_Ellipse_Notch*(self.l_between_notches+1)+self.size_Ellipse_Notch)+'\n') #Compute the number of points used to compute the integration, and init values to be used by length2Angle if self.length_ellipse < 500: self.nPoints = 20000 #Error will be less than 0.01mm elif self.length_ellipse < 2000: self.nPoints = 100000 else: self.nPoints = 500000 #Beware compute time will be higher. def drawNotchedEllipse(self, path, Start, End, Offset): ''' draw the notched ellipse from Start Angle to End Angle using path path ''' self.Compute_Ellipse_Params(Start, End) #Compute offset to be added to coordinates such as the start point matches with start angle xOffset = -self.a*math.cos(Start) + Offset[0] yOffset = -self.a*math.sin(Start) + Offset[1] self.StepAngle = (End - Start)/self.nPoints self.CurPoint = 0 self.LastDistance = 0.0 #At the start point DebugMsg("nPoints ="+str(self.nPoints)+" StepAngle="+str(self.StepAngle)+"\n") DebugMsg("Offset Ellipse="+str((xOffset, yOffset))+'\n') ''' #TEST a1 = self.length2Angle(1.0) DebugMsg("length2Angle(1.0) --> "+str(a1*180/math.pi)+'\n') a2 = self.length2Angle(2.0) DebugMsg("length2Angle(2.0) --> "+str(a2*180/math.pi)+'\n') a3 = self.length2Angle(5.0) DebugMsg("length2Angle(5.0) --> "+str(a3*180/math.pi)+'\n') a4 = self.length2Angle(10.0) DebugMsg("length2Angle(10.0) --> "+str(a4*180/math.pi)+'\n') a5 = self.length2Angle(self.length_ellipse/2.0) DebugMsg("length2Angle(length/2) --> "+str(a5*180/math.pi)+'\n') a6 = self.length2Angle(3*self.length_ellipse/4.0) DebugMsg("length2Angle(length*0.75) --> "+str(a6*180/math.pi)+'\n') a7 = self.length2Angle(self.length_ellipse-2.0) DebugMsg("length2Angle(length-2) --> "+str(a7*180/math.pi)+'\n') a8 = self.length2Angle(self.length_ellipse-1.0) DebugMsg("length2Angle(length-1) --> "+str(a8*180/math.pi)+'\n') a9 = self.length2Angle(self.length_ellipse) DebugMsg("length2Angle(length) --> "+str(a9*180/math.pi)+'\n') self.StepAngle = (End - Start)/self.nPoints self.CurPoint = 0 self.LastDistance = 0.0 #At the start point a9 = self.length2Angle(self.length_ellipse) DebugMsg("length2Angle(length), fresh start --> "+str(a9*180/math.pi)+'\n') self.CurPoint = 0 self.LastDistance = 0.0 #At the start point #End TEST ''' #The side face is "internal", that is the notches are towards the exterior. DeltaAngleNotches = -math.pi/2 #Angle from the tangeant CurAngle = Start #Starting point CurDistance = 0 #Distance on ellipse #Now for all notches but the last one for i in range(self.nb_Ellipse_Notch): #Start with the notch itself, but first compute the tangeant at the current point theta = math.atan2(self.b*math.cos(CurAngle), -self.a*math.sin(CurAngle)) AngleNotch = theta + DeltaAngleNotches #Draw notch , start position on ellipse + Notch itself x = self.a * math.cos(CurAngle) + thickness * math.cos(AngleNotch) + xOffset y = self.b * math.sin(CurAngle) + thickness * math.sin(AngleNotch) + yOffset DebugMsg("Notch, Pos without offset="+str((self.a * math.cos(CurAngle) + thickness * math.cos(AngleNotch), self.b * math.sin(CurAngle) + thickness * math.sin(AngleNotch) ))+" WithOffset"+str((x,y))+'\n') path.LineTo(x, y) #Now the side parralel to the ellipse x += self.size_Ellipse_Notch * math.cos(theta) y += self.size_Ellipse_Notch * math.sin(theta) path.LineTo(x, y) #Now back to the ellipse, do not use the angle to come back to the ellipse but compute the position on ellipse. #This will give a better approximation of the ellipse. As ellipse is convex, the interior of the notch will be shorter than the exterior CurDistance += self.size_Ellipse_Notch CurAngle = self.length2Angle(CurDistance) x = self.a * math.cos(CurAngle) + xOffset y = self.b * math.sin(CurAngle) + yOffset path.LineTo(x, y) #Now draw the interior line, but mm by mm to have a good approximation of the ellipse for j in range(self.nb_point_between_notches): CurDistance += self.SizeBetweenPoints CurAngle = self.length2Angle(CurDistance) x = self.a * math.cos(CurAngle) + xOffset y = self.b * math.sin(CurAngle) + yOffset path.LineTo(x, y) #We are now ready to draw the next notch #Now draw the last notch, but draw it "backward" to have a symetric view. theta = math.atan2(self.b*math.cos(End), -self.a*math.sin(End)) AngleNotch = theta + DeltaAngleNotches #Draw notch , start position on ellipse + Notch itself x_end_notch = self.a * math.cos(End) + thickness * math.cos(AngleNotch) + xOffset y_end_notch = self.b * math.sin(End) + thickness * math.sin(AngleNotch) + yOffset #Now the side parralel to the ellipse x_start_notch = x_end_notch - self.size_Ellipse_Notch * math.cos(theta) y_start_notch = y_end_notch - self.size_Ellipse_Notch * math.sin(theta) path.LineTo(x_start_notch, y_start_notch) path.LineTo(x_end_notch, y_end_notch) #For the last point, we will use the End Parameter x = self.a * math.cos(End) + xOffset y = self.b * math.sin(End) + yOffset path.LineTo(x,y) #We should be arrived at the last point now ! # Generate vertical lines for flex # Parameters : StartX, StartY, size, nunmber of lines and +1 if lines goes up and -1 down def GenLinesFlex(self, StartX, StartY, Size, nLine, UpDown, path): DebugMsg("Enter GenLinesFlex, Pos="+str((StartX, StartY))+" nSegment="+str(nLine)+" Size Segment="+str(Size)+" UpDown="+str(UpDown)+" End="+str((StartX, StartY+nLine*(Size+2)-2))+'\n') for i in range(nLine): path.Line(StartX, StartY, StartX, StartY + UpDown*Size) DebugMsg("GenLinesFlex from "+str((StartX, StartY))+" to "+str((StartX, StartY + UpDown*Size))+'\n') StartY += UpDown*(Size+2) def drawFlexEllipse(self, path, height, SkipFlex, Position): ''' draw the flex lines for the ellipse After this path will be at the right/bottom corner of the flex line. ''' xpos = Position[0] ypos = Position[1] #First compute angles of each notch in order to skip unnecessary flex lines self.StepAngle = (self.End - self.Start)/self.nPoints self.CurPoint = 0 self.LastDistance = 0.0 #At the start point CurAngle = self.Start #Starting point CurDistance = 0 #Distance on ellipse DeltaNotch = (self.l_between_notches+1)*self.size_Ellipse_Notch ListDistance = [] #Now for all notches but the last one for i in range(self.nb_Ellipse_Notch): #Start with the notch itself, but first compute the tangeant at the current point (x0,y0) LastAngle = CurAngle # with the line equation in the form alpha*x + beta*y + gamma = 0 alpha = self.b * math.cos(CurAngle) beta = self.a * math.sin(CurAngle) gamma = -(self.a*self.b) CurDistance += DeltaNotch CurAngle = self.length2Angle(CurDistance) #Now compute distance between tangeant and next point. x1 = self.a * math.cos(CurAngle) y1 = self.b * math.sin(CurAngle) #Distance betwwen line and point is (alpha * pt.x + beta * pt.y + gamma)*(alpha * pt.x + beta * pt.y + gamme)/sqrt(alpha*alpha + beta*beta) distance = abs(alpha * x1 + beta * y1 + gamma)/math.sqrt(alpha*alpha + beta*beta) ListDistance.append(distance) DebugMsg("LastAngle ="+str(round(180*LastAngle/math.pi,2))+" CurAngle="+str(round(180*CurAngle/math.pi,2))+" NewPoint="+str((x1,y1))+" distance="+str(distance)+'\n') #and for the last one, repeat the previous ListDistance.append(distance) ''' Now, this is the real flex line drawing ''' #Compute number of vertical lines. Each long mark should be at most 50mm long to avoid failures TotalHeight = height+2*thickness nMark = int( TotalHeight / 50) + 1 #Compute number of lines nMark = max(nMark, 2) # At least 2 marks #Sizes of short and long lines to make flex LongMark = (TotalHeight / nMark) - 2.0 #Long Mark equally divide the height ShortMark = LongMark/2 # And short mark should lay at center of long marks DebugMsg("\ndrawFlexEllipse, Pos="+str(Position)+" TotalHeight="+str(TotalHeight)+" nMark="+str(nMark)+" LongMark="+str(LongMark)+" ShortMark="+str(ShortMark)+'\n') for i in range(self.nb_Ellipse_Notch): ''' For each set notch + interval between notches, always start with a notch, and we are external in this case The path is designed as it will lead to "optimal" move of the laser beam. First draw the nocth and the line inside the notch First edge of the notch, start with a short line, then nMark-1 long lines then a short one. This will cover the entire height+2*thickness The the second edge of the notch, the same but drawn backwards (bottom to top) and at last the line inside the notch, drawn from top to bottom ''' DebugMsg("Notch("+str(i)+"), SkipFlex="+str(SkipFlex)+" ListDistance[i]="+str(ListDistance[i])+'\n') #Draw the edge line from Top to Bottom self.GenLinesFlex(xpos, ypos, ShortMark, 1, 1, path) #Then nMark-1 long Lines self.GenLinesFlex(xpos, ypos+ShortMark+2, LongMark, nMark-1, 1, path) #And the last short line self.GenLinesFlex(xpos, ypos+TotalHeight-ShortMark, ShortMark, 1, 1, path) #Now we are at the bottom of the Flex face, draw the bottom notch path.Line(xpos, ypos+height+thickness, xpos+self.size_Ellipse_Notch, ypos+height+thickness) #Then draw the same pattern for the other side of the notch, but bottom to top self.GenLinesFlex(xpos+self.size_Ellipse_Notch, ypos+TotalHeight, ShortMark, 1, -1, path) #Then nMark-1 long Lines self.GenLinesFlex(xpos+self.size_Ellipse_Notch, ypos+TotalHeight-ShortMark-2, LongMark, nMark-1, -1, path) #And the last short line that will reach the top external edge self.GenLinesFlex(xpos+self.size_Ellipse_Notch, ypos+ShortMark, ShortMark, 1, -1, path) #then the top notch path.Line(xpos+self.size_Ellipse_Notch, ypos + thickness, xpos, ypos+thickness) #Then draw the long lines inside the notch, first and last will be shorter by thickness #This line is drawn from top to bottom, and start at 1mm from the interior of the notch self.GenLinesFlex(xpos+self.size_Ellipse_Notch/2, ypos+thickness+1, LongMark-thickness, 1, 1, path) #Then the remaining inside if any if nMark > 2: self.GenLinesFlex(xpos+self.size_Ellipse_Notch/2, ypos+3+LongMark, LongMark, nMark-2, 1, path) #Then the last one, shorter also, will reach internal bottom + 1mm self.GenLinesFlex(xpos+self.size_Ellipse_Notch/2, ypos+TotalHeight-LongMark-1, LongMark-thickness, 1, 1, path) ''' At this point we are near the bottom line. First draw the external line up to the next notch ''' xpos += self.size_Ellipse_Notch #xpos is the other side of the notch path.Line(xpos, ypos+TotalHeight, xpos+self.Size_betweenNotches, ypos+TotalHeight) ''' Then draw the lines between external top and bottom, but only if needed when SkipFlex is true They are 2*l_between_notches - 1 lines, so the number is always odd Even indexes are made of long lines only and drawn Bottom to Top. Odd indexes are made of one short line, nMark-2 long lines then a short line and rawn top to bottom As total number is odd, wa always end with long lines drawn from bottom to top, so the last position will be near the top line ''' #If the ellipse is not very round at this point, in order to save laser time, draw only lines inside the notch and the line just before the notch drawAllLines = False if SkipFlex == False or ListDistance[i] > 0.5: drawAllLines = True for j in range(2*self.l_between_notches-1): if j == 2*self.l_between_notches-2 or drawAllLines: if (j % 2)==0: #even, draw long lines bottom to top self.GenLinesFlex(xpos+(j+1)*self.size_Ellipse_Notch/2, ypos+TotalHeight-1, LongMark, nMark, -1, path) else: #Odd, draw short line, nMark-2 long lines then a short line, top to bottom self.GenLinesFlex(xpos+(j+1)*self.size_Ellipse_Notch/2, ypos+1, ShortMark-1, 1, 1, path) #Then nMark-1 long Lines self.GenLinesFlex(xpos+(j+1)*self.size_Ellipse_Notch/2, ypos+ShortMark+2, LongMark, nMark-1, 1, path) #And the last short line self.GenLinesFlex(xpos+(j+1)*self.size_Ellipse_Notch/2, ypos+TotalHeight-ShortMark, ShortMark-1, 1, 1, path) #Now we are near the top line, draw the line up to the next notch path.Line(xpos, ypos, xpos+self.Size_betweenNotches, ypos) #And we are ready to draw the next flex pattern xpos += self.Size_betweenNotches ''' Now draw the pattern for the last notch ''' #Draw the edge line from Top to Bottom self.GenLinesFlex(xpos, ypos, ShortMark, 1, 1, path) #Then nMark-1 long Lines self.GenLinesFlex(xpos, ypos+ShortMark+2, LongMark, nMark-1, 1, path) #And the last short line self.GenLinesFlex(xpos, ypos+TotalHeight-ShortMark, ShortMark, 1, 1, path) #Now we are at the bottom of the Flex face, draw the bottom notch path.Line(xpos, ypos+height+thickness, xpos+self.size_Ellipse_Notch, ypos+height+thickness) #Then draw the same pattern for the other side of the notch, but bottom to top self.GenLinesFlex(xpos+self.size_Ellipse_Notch, ypos+TotalHeight, ShortMark, 1, -1, path) #Then nMark-1 long Lines self.GenLinesFlex(xpos+self.size_Ellipse_Notch, ypos+TotalHeight-ShortMark-2, LongMark, nMark-1, -1, path) #And the last short line that will reach the top external edge self.GenLinesFlex(xpos+self.size_Ellipse_Notch, ypos+ShortMark, ShortMark, 1, -1, path) #then the top notch path.Line(xpos+self.size_Ellipse_Notch, ypos + thickness, xpos, ypos+thickness) #Then draw the long lines inside the notch, first and last will be shorter by thickness #This line is drawn from top to bottom, and start at 1mm from the interior of the notch self.GenLinesFlex(xpos+self.size_Ellipse_Notch/2, ypos+thickness+1, LongMark-thickness, 1, 1, path) #Then the remaining inside if any if nMark > 2: self.GenLinesFlex(xpos+self.size_Ellipse_Notch/2, ypos+3+LongMark, LongMark, nMark-2, 1, path) #Then the last one, shorter also, will reach internal bottom + 1mm self.GenLinesFlex(xpos+self.size_Ellipse_Notch/2, ypos+TotalHeight-LongMark-1, LongMark-thickness, 1, 1, path) xpos += self.size_Ellipse_Notch #xpos is the other side of the notch path.MoveTo(xpos, ypos+TotalHeight) #Path will be at the end of flex line on the BOTTOM edge. DebugMsg("Path pos ="+str((xpos, ypos+TotalHeight))+'\n') class CornerPoint: ''' This class stores data about corners, to be used later to draw the faces of the box position is a tuple giving the position of the corner ''' def __init__(self, position, radius, x_internal, y_internal, WoodHingeCorner = False): self.x_internal = x_internal self.y_internal = y_internal self.WoodHingeCorner = WoodHingeCorner if radius > 0: self.radius = radius else: self.radius = 0 #Compute position of circle center, do it now because it is always here, even if corner moves (internal/external) if position[0] <= thickness: #Left corner self.xc = position[0] + self.radius else: #Right corner self.xc = position[0] - self.radius if position[1] <= thickness: #Top corner self.yc = position[1] + self.radius else: #Bottom corner self.yc = position[1] - self.radius #Compute position of corner, given internal or external position of finger joints if x_internal: self.x_corner = position[0] elif position[0] <= thickness: self.x_corner = position[0] - thickness if self.radius > 0: self.radius += thickness # Change radius accordingly, beware do it only for x direction (only once !) else: self.x_corner = position[0] + thickness if self.radius > 0: self.radius += thickness if y_internal: self.y_corner = position[1] elif position[1] <= thickness: self.y_corner = position[1] - thickness else: self.y_corner = position[1] + thickness #Compute position of line of finger joints if position[0] <= thickness and position[1] <= thickness: #Top left corner, compute positions of start/end of corners self.quadrant = 0 self.x_start_joint = position[0] + self.radius #X direction, do not take into account Internal/External self.y_start_joint = self.y_corner self.x_end_joint = self.x_corner self.y_end_joint = position[1] + self.radius #Y Direction, do not take into account Internal/External elif position[1] <= thickness: #Top right corner self.quadrant = 1 self.x_start_joint = self.x_corner self.y_start_joint = position[1] + self.radius self.x_end_joint = position[0] - self.radius self.y_end_joint = self.y_corner elif position[0] <= thickness: #Bottom left corner self.quadrant = 3 self.x_start_joint = self.x_corner self.y_start_joint = position[1] - self.radius self.x_end_joint = position[0] + self.radius self.y_end_joint = self.y_corner else: #Bottom right corner self.quadrant = 2 self.x_start_joint = position[0] - self.radius self.y_start_joint = self.y_corner self.x_end_joint = self.x_corner self.y_end_joint = position[1] - self.radius #Specific case for WoodHingeCorner, "corner" is 3/4 of the circle out of the corner if WoodHingeCorner: if self.quadrant == 0: self.y_end_joint = self.y_corner + WoodHingeSize*thickness self.x_start_joint = self.x_corner + WoodHingeSize*thickness elif self.quadrant == 1: self.x_end_joint = self.x_corner - WoodHingeSize*thickness self.y_start_joint = self.y_corner + WoodHingeSize*thickness DebugMsg("End CornerPoint init. Corner="+str((self.x_corner, self.y_corner))+" Circle="+str((self.xc, self.yc))+" StartJoint="+str((self.x_start_joint, self.y_start_joint))+" EndJoint="+str((self.x_end_joint, self.y_end_joint))+" WoodHingeCorner="+str(self.WoodHingeCorner)+'\n') def drawCorner(self, path): ''' Draw the lines around the corner using path Start position of the path should be (x_end_joint, y_end_joint), not checked nor enforced End Position is (x_start_joint, y_start_joint) ''' if self.WoodHingeCorner: #Specific case, draw 3/4 of a circle of radius WoodHingeSize*thickness + plus a small segment of size thickness if self.quadrant == 0: #Left corner DebugMsg("drawCorner_WoodHinge Left: StartPoint="+str((self.x_end_joint, self.y_end_joint))+" Circle="+str((self.xc, self.yc))+ " EndPoint="+str((self.x_start_joint, self.y_start_joint))+'\n') path.LineToHRel(-thickness) path.drawQuarterCircle(self.x_corner-thickness, self.y_corner, WoodHingeSize*thickness, 3) #Start Lower Left path.drawQuarterCircle(self.x_corner-thickness, self.y_corner, WoodHingeSize*thickness, 0) #Start Upper Left path.drawQuarterCircle(self.x_corner-thickness, self.y_corner, WoodHingeSize*thickness, 1) #Start Upper Right elif self.quadrant == 1: #Right corner DebugMsg("drawCorner_WoodHinge Right: StartPoint="+str((self.x_end_joint, self.y_end_joint))+" Circle="+str((self.xc, self.yc))+ " EndPoint="+str((self.x_start_joint, self.y_start_joint))+'\n') path.LineToHRel(thickness) path.drawQuarterCircle(self.x_corner+thickness, self.y_corner, WoodHingeSize*thickness, 0) #Start Upper Left path.drawQuarterCircle(self.x_corner+thickness, self.y_corner, WoodHingeSize*thickness, 1) #Start Upper Right path.drawQuarterCircle(self.x_corner+thickness, self.y_corner, WoodHingeSize*thickness, 2) #Start Lower Right path.LineToHRel(-thickness) elif self.radius > 0: #DebugMsg("drawCorner radius Center"+str((self.xc, self.yc))+" RAdius="+str(self.radius)+ " quadrant="+str(self.quadrant)+'\n') path.drawQuarterCircle(self.xc, self.yc, self.radius, self.quadrant) else: DebugMsg("drawCorner: StartPoint="+str((self.x_end_joint, self.y_end_joint))+" Corner="+str((self.x_corner, self.y_corner))+ " EndPoint="+str((self.x_start_joint, self.y_start_joint))+'\n') if distance2Points(self.x_end_joint, self.y_end_joint, self.x_corner, self.y_corner) > MinMove: #Draw line up to real corner path.LineTo(self.x_corner, self.y_corner) if distance2Points(self.x_start_joint, self.y_start_joint, self.x_corner, self.y_corner) > MinMove: #Draw line between corner and start of joints path.LineTo(self.x_start_joint, self.y_start_joint) class NotchLine: ''' This class deals with straight lines with or without finger joints start and end parameters are actually tuples giving position (x,y) and internal/external status of each point The angle give the direction, it couldn't be easily computed from start and ending point because of internal/external status If parameter DrawHalf is < 0, only first half of line will be drawn, if > 0 only second half. When DrawHalf is null both parts will be drawn Beware, DrawHalf could be < 0 or > 0 only when Status (Internal/External) are indentical. ''' def __init__(self, start, end, angle, finger_joint_size, DrawHalf=0): self.StartX = start[0] self.StartY = start[1] self.EndX = end[0] self.EndY = end[1] self.StartStatus = start[2] self.EndStatus = end[2] self.JointSize = finger_joint_size self.Angle = angle self.size_line_joint = 0 self.start_line_joint_x = self.StartX self.start_line_joint_y = self.StartY self.end_line_joint_x = self.EndX self.end_line_joint_y = self.EndY self.DrawHalf = DrawHalf DebugMsg("NotchLine_init, StartPoint="+str(start)+" EndPoint="+str(end)+" Joint_size="+str(finger_joint_size)+" DrawHalf="+str(DrawHalf)+'\n') # Compute size of all finger joints # Compute size as a distance to deal with every direction. size = math.sqrt((self.EndX - self.StartX)*(self.EndX - self.StartX) + (self.EndY - self.StartY)*(self.EndY - self.StartY)) # Compute number of joints if finger_joint_size == 0: # No finger joint self.nb_finger_joint = 0 if DrawHalf != 0: #Draw only half of line (specific case for rounded flex) self.EndX = (self.StartX + self.EndX) / 2 self.EndY = (self.StartY + self.EndY) / 2 self.end_line_joint_x = self.EndX self.end_line_joint_y = self.EndY elif start[2] == end[2]: # Same status, internal/external, the number of notches should be odd (at least 3) if size < 3 * finger_joint_size: self.nb_finger_joint = 0 else: self.nb_finger_joint = 2*int((size-finger_joint_size) / (2*finger_joint_size)) + 1 self.size_line_joint = self.nb_finger_joint * finger_joint_size # compute start and stop of finger joint line, centered on edge delta_pos = (size - self.size_line_joint)/2 self.start_line_joint_x = self.StartX + delta_pos*math.cos(angle) self.start_line_joint_y = self.StartY + delta_pos*math.sin(angle) self.end_line_joint_x = self.EndX - delta_pos*math.cos(angle) self.end_line_joint_y = self.EndY - delta_pos*math.sin(angle) if DrawHalf < 0: #Draw only first half of notch line,i.e. end will be at the middle of segment self.EndX = (self.StartX + self.EndX) / 2 self.EndY = (self.StartY + self.EndY) / 2 self.nb_finger_joint = (self.nb_finger_joint // 2 ) + 1 #Previous number was odd (2n+1), new notch count = n + 1, as last one will be half notch self.end_line_joint_x = self.start_line_joint_x + ((self.nb_finger_joint-0.5)*finger_joint_size)*math.cos(angle) #Quit line at end of last notch self.end_line_joint_y = self.start_line_joint_y + ((self.nb_finger_joint-0.5)*finger_joint_size)*math.sin(angle) #Quit line at end of last notch if (self.nb_finger_joint%2) == 0 and self.StartStatus: #Now nb joint is even, so Internal/External status is changed so end is external self.end_line_joint_x += thickness * math.cos(angle-math.pi/2) self.end_line_joint_y += thickness * math.sin(angle-math.pi/2) self.EndX = self.end_line_joint_x self.EndY = self.end_line_joint_y elif (self.nb_finger_joint%2) == 0 and self.StartStatus == 0: #Now nb joint is even, so Internal/External status is changed so end is internal self.end_line_joint_x += thickness * math.cos(angle+math.pi/2) self.end_line_joint_y += thickness * math.sin(angle+math.pi/2) self.EndX = self.end_line_joint_x self.EndY = self.end_line_joint_y elif DrawHalf > 0: #Draw only second half of notch line,i.e. Start will be at the middle of segment self.StartX = (self.StartX + self.EndX) / 2 self.StartY = (self.StartY + self.EndY) / 2 self.nb_finger_joint = (self.nb_finger_joint // 2 ) + 1 #Previous number was odd (2n+1), new notch count = n+1 , as first one with half notch for the first one #Draw the first half notch as a shift from start position self.start_line_joint_x = self.StartX - 0.5*finger_joint_size*math.cos(angle) self.start_line_joint_y = self.StartY - 0.5*finger_joint_size*math.sin(angle) if (self.nb_finger_joint%2) == 0 and self.EndStatus: #Now number of joints is even, so switch StartStatus to have different status (Start and End), and keep End Status #In this case, Start is now External self.StartStatus = 0 #Move Start point self.start_line_joint_x += thickness * math.cos(angle-math.pi/2) self.start_line_joint_y += thickness * math.sin(angle-math.pi/2) else: #Now number of joints is even, so switch StartStatus to have different status (Start and End), and keep End Status #In this case, Start is now Internal self.StartStatus = 1 #Move Start point self.start_line_joint_x += thickness * math.cos(angle+math.pi/2) self.start_line_joint_y += thickness * math.sin(angle+math.pi/2) else: #Start and end have different internal/external status. Number of notches should be even if size < 2 * finger_joint_size: self.nb_finger_joint = 0 else: self.nb_finger_joint = 2*int(size / (2*finger_joint_size)) self.size_line_joint = self.nb_finger_joint * finger_joint_size # compute start and stop of finger joint line, centered on edge delta_pos = (size - self.size_line_joint)/2 self.start_line_joint_x = self.StartX + delta_pos*math.cos(angle) self.start_line_joint_y = self.StartY + delta_pos*math.sin(angle) self.end_line_joint_x = self.EndX - delta_pos*math.cos(angle) self.end_line_joint_y = self.EndY - delta_pos*math.sin(angle) DebugMsg("NotchLine_init, size of line joints = "+str(size)+" Nb_Joint="+str(self.nb_finger_joint)+" size_line_joint="+str(self.size_line_joint)+" start_line_joint"+str(( self.start_line_joint_x, self.start_line_joint_y))+" end_line_joint="+str((self.end_line_joint_x, self.end_line_joint_y))+'\n') def ModifyNotchLine(self, SizeCut, CutOnStart): ''' This function modify a vertical notch line to take into account cuts needed by WoodHinge Beware, only safe to call with vertical lines, unexpected results in other cases SizeCut is the Size of cut, last notch will be at last 1.5 thickness far from this cut CutOnStart is True when the cut is at the start of the line. Beware could be top or bottom if angle is 90 or 270° ''' DebugMsg("Enter ModifyNotchLine, CutOnStart="+str(CutOnStart)+" angle="+str(self.Angle)+" Start ="+str(self.StartY)+" End="+str(self.EndY)+" nb_finger_joint="+str(self.nb_finger_joint)+" SizeJoint="+str(self.JointSize)+" start_line_joint_y="+str(self.start_line_joint_y)+" end_line_joint_y="+str(self.end_line_joint_y)+'\n') Dir = 0 #Bottom to Top if Dir = 0 SizeCut -= thickness #In all cases, reduce sizecut because top and bottom lines are always external in Y if abs(self.Angle - math.pi/2) < 1e-6: Dir = 1 # Top to Bottom if Dir == 1 and CutOnStart: #Change line, shorten of SizeCut at the start, in this case start at end of line nbNotch = 1 ypos = self.end_line_joint_y Limit = SizeCut + self.StartY + 1.5*thickness DebugMsg("WHC_init_1 : ypos ="+str(ypos)+" nbNotch ="+str(nbNotch)+" Limit="+str(Limit)+" NewSizeCut="+str(SizeCut)+"\n") while ypos > Limit: ypos -= 2*self.JointSize nbNotch += 2 DebugMsg("WHC : ypos ="+str(ypos)+" nbNotch ="+str(nbNotch)+"\n") #Now change the line if nbNotch > 3: nbNotch -= 2 #Sub last step which was too far self.start_line_joint_y = self.end_line_joint_y - nbNotch*self.JointSize self.nb_finger_joint = nbNotch self.StartY += SizeCut else: self.nb_finger_joint = 0 #No more notch self.StartY += SizeCut elif Dir==1 and CutOnStart == False: #Change line, shorten of SizeCut at the end, in this case start at start of line nbNotch = 1 ypos = self.start_line_joint_y Limit = self.EndY - SizeCut - 1.5*thickness DebugMsg("WHC_init_2 : ypos ="+str(ypos)+" nbNotch ="+str(nbNotch)+" Limit="+str(Limit)+" NewSizeCut="+str(SizeCut)+"\n") while ypos < Limit: ypos += 2*self.JointSize nbNotch += 2 DebugMsg("WHC : ypos ="+str(ypos)+" nbNotch ="+str(nbNotch)+"\n") #Now change the line if nbNotch > 3: nbNotch -= 2 #Sub last step which was too far #Cut on end, so change EndY and end_line_joint_y self.end_line_joint_y = self.start_line_joint_y + nbNotch*self.JointSize self.nb_finger_joint = nbNotch self.EndY -= SizeCut else: self.nb_finger_joint = 0 #No more notch self.EndY -= SizeCut if self.EndY < self.end_line_joint_y: #Limit send_line_joint_y to be lower or equal than EndY self.end_line_joint_y = self.EndY elif Dir==0 and CutOnStart: #Change line, shorten of SizeCut at the start, in this case this the bottom of line because Angle is 270° nbNotch = 1 ypos = self.end_line_joint_y Limit = self.StartY - SizeCut - 1.5*thickness DebugMsg("WHC_init_3 : ypos ="+str(ypos)+" nbNotch ="+str(nbNotch)+" Limit="+str(Limit)+" NewSizeCut="+str(SizeCut)+"\n") while ypos < Limit: ypos += 2*self.JointSize nbNotch += 2 DebugMsg("WHC : ypos ="+str(ypos)+" nbNotch ="+str(nbNotch)+"\n") #Now change the line if nbNotch > 3: nbNotch -= 2 #Sub last step which was too far #Change at start of line self.start_line_joint_y = self.end_line_joint_y + nbNotch*self.JointSize self.nb_finger_joint = nbNotch self.StartY -= SizeCut else: self.nb_finger_joint = 0 #No more notch self.StartY -= SizeCut elif Dir==0 and CutOnStart == 0: #Change line, shorten of SizeCut at the end, in this case this the top of line because Angle is 270° nbNotch = 1 ypos = self.start_line_joint_y Limit = self.EndY + SizeCut + 1.5*thickness DebugMsg("WHC_init_4 : ypos ="+str(ypos)+" nbNotch ="+str(nbNotch)+" Limit="+str(Limit)+" NewSizeCut="+str(SizeCut)+"\n") while ypos > Limit: ypos -= 2*self.JointSize nbNotch += 2 DebugMsg("WHC : ypos ="+str(ypos)+" nbNotch ="+str(nbNotch)+"\n") #Now change the line if nbNotch > 3: nbNotch -= 2 #Sub last step which was too far self.end_line_joint_y = self.start_line_joint_y - nbNotch*self.JointSize self.nb_finger_joint = nbNotch self.EndY += SizeCut #New EndY is below the previous one else: self.nb_finger_joint = 0 #No more notch self.EndY += SizeCut if self.EndY < self.end_line_joint_y: self.end_line_joint_y = self.EndY DebugMsg("Exit ModifyNotchLine, angle="+str(self.Angle)+" Start ="+str(self.StartY)+" End="+str(self.EndY)+" nb_finger_joint="+str(self.nb_finger_joint)+" SizeJoint="+str(self.JointSize)+" start_line_joint_y="+str(self.start_line_joint_y)+" end_line_joint_y="+str(self.end_line_joint_y)+'\n') def drawNotchLine(self, path): ''' Draw the actual line, starting at current position of path. The position should be StartX, StartY, this is not checked or enforced to avoid unwanted moves Each finger joint is JointSize long but there is a correction to take into account the burn factor (thickness of the cutting line). So each external joint is actually JointSize+2*burn long and Internal joints are JointSize-2*burn ''' if self.nb_finger_joint == 0: #Easy case, no finger joint, draw a straight line path.LineTo(self.EndX, self.EndY) return #Normal case, there are finger joint(s) #First compute angles. #AngleJoint is the angle for drawing the first part of the finger joint #If start point is internal, AngleJoint should be Angle - pi/2, else it should be Angle + pi/2 if self.StartStatus: #internal AngleJoint = self.Angle - math.pi/2 DeltaBurn = burn else: AngleJoint = self.Angle + math.pi/2 DeltaBurn = -burn DebugMsg("drawNotchLine, Angle ="+str(round(self.Angle*180/math.pi))+" AngleJoint="+str(round(AngleJoint*180/math.pi))+'\n') DebugMsg("start_line_joint="+str((self.start_line_joint_x, self.start_line_joint_y))+" JointSize="+str(self.JointSize)+" DeltaBurn="+str(DeltaBurn)+'\n') #First go up to start of notch line + first joint + burn correction xcur = self.start_line_joint_x + (self.JointSize+DeltaBurn)*math.cos(self.Angle) ycur = self.start_line_joint_y + (self.JointSize+DeltaBurn)*math.sin(self.Angle) path.LineTo(xcur, ycur) DebugMsg("First Point="+str((xcur, ycur))+'\n') i = self.nb_finger_joint - 1 while i > 0: #The start drawing finger joint path.LineToRel(thickness*math.cos(AngleJoint), thickness*math.sin(AngleJoint)) #Compute next AngleJoint for return move if necessary AngleJoint = AngleJoint + math.pi if AngleJoint > 2*math.pi: AngleJoint -= 2*math.pi #Keep angle between 0 and 2*pi #idem for burn factor DeltaBurn = -DeltaBurn #Then line which is JointSize long and take into account the burn factor, draw half finger joint when last of first half if self.DrawHalf < 0 and i == 1: path.LineToRel((self.JointSize/2+DeltaBurn)*math.cos(self.Angle), (self.JointSize/2+DeltaBurn)*math.sin(self.Angle)) elif i > 1: #Do not draw last segment, not necessary, will be completed by next path.LIneTo path.LineToRel((self.JointSize+DeltaBurn)*math.cos(self.Angle), (self.JointSize+DeltaBurn)*math.sin(self.Angle)) i -= 1 #Then draw last part, up to end point #Do not check if necessary because of burn factor, last position is not the real end of notch line. path.LineTo(self.EndX, self.EndY) DebugMsg("Last LineTo End ="+str((self.EndX, self.EndY))+'\n') class FlexLines: ''' This class deals and draw set of flex lines to round a corner ''' def drawFlexLines(self, Position, Height, Radius, path): ''' First compute how many segment per line. Segment length should be kept short, < 50mm or so, so high boxes means number of lines Also compute distance between lines, which depend on radius. Shorter radius means smaller distance between lines But keep min distance at about 1mm minimum and 1.5mm max, after this value flex is quite hard to bend ! ''' if Height+2*thickness < 30: nSegmentFlex = 1 elif Height+2*thickness < 80: nSegmentFlex = 2 elif Height+2*thickness < 150: nSegmentFlex = 3 else: nSegmentFlex = Height+2*thickness // 50 #Then compute distance between flex lines. The basic idea is to have a minimum of 15 lines per corner, with lines distant at least of 1mm #But also ensure that distance between lines is at most at 2mm round_distance = Radius*math.pi/2 flex_line_spacing = round_distance / 14 flex_line_spacing = max(flex_line_spacing, 1.0) flex_line_spacing = min(flex_line_spacing, 1.5) nb_flex_lines = int(round(round_distance / flex_line_spacing,0)) DebugMsg("sizeround ="+str(round_distance)+" flex_line_spacing="+str(flex_line_spacing)+" nb_flex_lines="+str(nb_flex_lines)+" size="+str(nb_flex_lines*flex_line_spacing)+"\n") #nb_flex_lines should be odd nb_flex_lines |= 1 flex_line_spacing = round_distance / (nb_flex_lines-1) #Real distance between lines length_flex_segment_case1 = (Height+2*thickness - 2*nSegmentFlex) / nSegmentFlex #Case 1, 1/2 segment starting at top, n-1 segments and 1/2 segment up to bottom length_flex_segment_case2 = (Height+2*thickness - 2*(nSegmentFlex+1)) / nSegmentFlex #Case 2, n segments equally spaced (2mm) from top to bottom DebugMsg("nSegmentFlex="+str(nSegmentFlex)+" sizeround ="+str(round_distance)+" flex_line_spacing="+str(flex_line_spacing)+" nb_flex_lines="+str(nb_flex_lines)+" size="+str(nb_flex_lines*flex_line_spacing)+"\n") #Now draw set of flex lines for i in range(nb_flex_lines): if i % 2: #In this case draw nSegmentFlex segments which are identical. First segment start at 2 mm above bottom line, segments are 2mm spaced for j in range(nSegmentFlex): path.MoveTo(Position + i * flex_line_spacing, Height+thickness-2-j * (length_flex_segment_case2+2) ) path.LineToVRel(-length_flex_segment_case2) else: #In this case draw a first segment starting at -thickness (top), segment is length_flex_segment_even/2 long path.MoveTo(Position + i * flex_line_spacing, -thickness ) path.LineToVRel(length_flex_segment_case1/2) #One half segment #Then nSegmentFlex-1 which are for j in range(nSegmentFlex-1): path.MoveTo(Position + i * flex_line_spacing, j*(length_flex_segment_case1+2) + length_flex_segment_case1/2 + 2 - thickness ) path.LineToVRel(length_flex_segment_case1) path.MoveTo(Position + i * flex_line_spacing, Height+thickness - length_flex_segment_case1/2) path.LineTo(Position + i * flex_line_spacing, Height+thickness ) class FlexFace: ''' This class deal with flex faces, which are used as vertical faces when rounded corners are used. ''' def __init__(self, FlexBandList, isLid, zbox, z_joint, InkscapeGroup, PositionInPage): ''' The list FlexBandList contains all elements to be used on top and bottom line of the flex face. Each element is in a tuple item 0 is the path id item 1 is Start_Internal item 2 is End Internal item 3..n are tuple with ( size, size_joints top, radius rounded corner, size_joints bottom, [hasCircle]) Last item is always with radius = 0 ''' self.FlexBandList = FlexBandList self.z_joint = z_joint self.height = zbox self.isLid = isLid #Update PositionInPage to take into account finger joints (only OK if it is a simple shape with finger joints). PositionInPage[0] -= thickness PositionInPage[1] -= thickness FlexElt = FlexBandList[3] if len(FlexElt) == 5 and FlexElt[4] and self.isLid == False: #Change path offset to take into account the circle... PositionInPage[0] -= WoodHingeSize*thickness PositionInPage[1] -= WoodHingeSize*thickness elif len(FlexBandList) > 4: FlexElt = FlexBandList[len(FlexBandList)-1] if len(FlexElt) == 5 and FlexElt[4] and self.isLid == False: #Change path offset to take into account the circle... but only on y here PositionInPage[1] -= WoodHingeSize*thickness self.BoundingBox = (-PositionInPage[0], -PositionInPage[1], -PositionInPage[0], -PositionInPage[1]) #If needed, create path which will be used to draw the face #The path will be in the group InkscapeGroup name = FlexBandList[0] if isLid: name = 'Lid_'+name self.path = th_inkscape_path(PositionInPage, InkscapeGroup, name) #Remember these 2 parameters for Side Notch lines self.InkscapeGroup = InkscapeGroup self.BaseName = FlexBandList[0] def Close(self): ''' Close and write the path after drawing is done ''' self.path.Close() self.path.GenPath() def drawClip(self, size_clip, UpDown): ''' Draw a single clip pattern The clip is vertical, with length size_clip and width size_clip/4 Add clip to current path, use LineTo New path position will be end of clip If draw up, UpDown should be 1 ''' if UpDown != 1: UpDown=-1 #Will draw negative #First draw vertical line which is .31*size self.path.LineToVRel(size_clip*0.3075*UpDown) #Then small bezier curve self.path.BezierRel(0, size_clip*0.036241333*UpDown, size_clip*0.045356111, size_clip*0.052734333*UpDown, size_clip*0.0685556, size_clip*0.025*UpDown) #then line self.path.LineToRel(size_clip*0.132166667, size_clip*-0.157555556*UpDown) #then bezier self.path.BezierRel(size_clip*0.016710556, size_clip*-0.02*UpDown, size_clip*0.05, size_clip*-0.008*UpDown, size_clip*0.05, size_clip*0.017795167*UpDown) #Then vertical line self.path.LineToVRel(size_clip*0.615*UpDown) #then bezier self.path.BezierRel(0, size_clip*0.026*UpDown, size_clip*-0.032335, size_clip*0.037760389*UpDown, size_clip*-0.05, size_clip*0.017795167*UpDown) #Then line self.path.LineToRel(size_clip*-0.132166667, size_clip*-0.157555556*UpDown) #then last bezier #c -0.42188,0.5 -1.23438,0.203125 -1.23438,-0.449219 self.path.BezierRel(size_clip*-0.023437778, size_clip*-0.027777778*UpDown, size_clip*-0.068576667, size_clip*-0.011284722*UpDown, size_clip*-0.068576667, size_clip*0.025*UpDown) #then last line self.path.LineToVRel(size_clip*0.3075*UpDown) def drawFlexFace(self, ClosePath): ''' Draw the flex face into its path, close path if argument is true after drawing This method is only valid when the corners are straight. When all corners are rounded, drawRoundedFlexFace should be used. ''' ListFlexLines = [] #Build Top line xpos = 0 if self.isLid: TopJointOff = 3 BotJointOff = 1 else: TopJointOff = 1 BotJointOff = 3 leftCircle = False leftCircleCut = False leftCirclePos = 0 rightCircle = False rightCircleCut = False rightCirclePos = 0 LastRadius = 0 #Always start with straight corner DebugMsg("\nEnter drawFlexFace, isLid="+str(self.isLid)+" Number of elements in list="+str(len(self.FlexBandList))+"Height="+str(self.height)+"\n") #Now read all elements (3..N) for i in range(3, len(self.FlexBandList)): FlexElement = self.FlexBandList[i] DebugMsg("Top line, i="+str(i)+" FlexElement="+str(FlexElement)+'\n') if i == 3 and len(FlexElement) == 5 and FlexElement[4] and self.isLid == False: #Specific case of left wood hinge face, draw circle on top leftCircle = True leftCirclePos = -thickness #Remember circle position #In this case start position is 0, (WoodHingeSize-1)*thickness self.path.MoveTo(0, (WoodHingeSize-1)*thickness) self.path.LineToHRel(-thickness) self.path.drawQuarterCircle(-thickness, -thickness, WoodHingeSize*thickness, 3) #Start Lower Left self.path.drawQuarterCircle(-thickness, -thickness, WoodHingeSize*thickness, 0) #Start Upper Left self.path.drawQuarterCircle(-thickness, -thickness, WoodHingeSize*thickness, 1) #Start Upper Right #After this position should be WoodHingeSize*thickness-thickness, -thickness self.path.LineTo(FlexElement[0] - FlexElement[2], -thickness) xpos += FlexElement[0] - LastRadius - FlexElement[2] elif i == 3 and len(FlexElement) == 5 and FlexElement[4] and self.isLid == True: leftCircleCut = True if i == 3: #Draw path start if self.FlexBandList[1]: #First item : Start point if internal self.path.MoveTo(0, -thickness) # Start position (0, -thickness) because flex band is always external in Y direction else: self.path.MoveTo(-thickness, -thickness) # Start position (-thickness, -thickness) because x external and flex band is always external in Y direction self.path.LineTo(0, -thickness) DebugMsg("Element "+str(i)+": xpos="+str(xpos)+' Size ='+str(FlexElement[0])+' radius ='+str(FlexElement[2])+' --> '+str(FlexElement[2]*math.pi/2)+'\n') #First Notch Line, with length SizeEdge - SizeOfRoundedCorners hLine = NotchLine((xpos, -thickness, 0), (xpos+FlexElement[0]-(LastRadius+FlexElement[2]), -thickness, 0), 0.0, FlexElement[TopJointOff]) hLine.drawNotchLine(self.path) xpos += FlexElement[0] - LastRadius - FlexElement[2] elif i == len(self.FlexBandList) - 1 and len(FlexElement) == 5 and FlexElement[4] and self.isLid == False: #Specific case of right wood hinge face, draw circle on top rightCircle = True rightCirclePos = xpos #Remember circle position #In this case start position is 0, (WoodHingeSize-1)*thickness self.path.LineTo( xpos + FlexElement[0] - LastRadius - (WoodHingeSize-1)*thickness, -thickness) xpos += FlexElement[0] - LastRadius rightCirclePos = xpos + thickness #Remember circle position self.path.drawQuarterCircle(rightCirclePos, -thickness, WoodHingeSize*thickness, 0) #Start Upper Left self.path.drawQuarterCircle(rightCirclePos, -thickness, WoodHingeSize*thickness, 1) #Start Upper Right self.path.drawQuarterCircle(rightCirclePos, -thickness, WoodHingeSize*thickness, 2) #Start Lower Right self.path.LineToHRel(-thickness) elif i == len(self.FlexBandList) - 1 and len(FlexElement) == 5 and FlexElement[4] and self.isLid == True: rightCircleCut = True DebugMsg("Element "+str(i)+": xpos="+str(xpos)+' Size ='+str(FlexElement[0])+' radius ='+str(FlexElement[2])+' --> '+str(FlexElement[2]*math.pi/2)+'\n') #First Notch Line, with length SizeEdge - SizeOfRoundedCorners hLine = NotchLine((xpos, -thickness, 0), (xpos+FlexElement[0]-(LastRadius+FlexElement[2]), -thickness, 0), 0.0, FlexElement[TopJointOff]) hLine.drawNotchLine(self.path) xpos += FlexElement[0] - LastRadius - FlexElement[2] else: if i == 3: #Draw path start if self.FlexBandList[1]: #First item : Start point if internal self.path.MoveTo(0, -thickness) # Start position (0, -thickness) because flex band is always external in Y direction else: self.path.MoveTo(-thickness, -thickness) # Start position (-thickness, -thickness) because x external and flex band is always external in Y direction self.path.LineTo(0, -thickness) DebugMsg("Element "+str(i)+": xpos="+str(xpos)+' Size ='+str(FlexElement[0])+' radius ='+str(FlexElement[2])+' --> '+str(FlexElement[2]*math.pi/2)+'\n') #First Notch Line, with length SizeEdge - SizeOfRoundedCorners hLine = NotchLine((xpos, -thickness, 0), (xpos+FlexElement[0]-(LastRadius+FlexElement[2]), -thickness, 0), 0.0, FlexElement[TopJointOff]) hLine.drawNotchLine(self.path) xpos += FlexElement[0] - LastRadius - FlexElement[2] #Then the line corresponding to rounded corner, also add coordinates for Flex lines if FlexElement[2] > 0: self.path.LineTo(xpos + FlexElement[2]*math.pi/2, -thickness) ListFlexLines.append((xpos, FlexElement[2])) xpos += FlexElement[2]*math.pi/2 LastRadius = FlexElement[2] #For the next edge if rightCircle == 0: if self.FlexBandList[2] == 0: #External end ? self.path.LineTo(xpos + thickness, -thickness) xpos += thickness self.path.LineTo(xpos, 0) DebugMsg('Vertical Line 1, xpos='+str(xpos)+'\n') #Then Vertical notch line, vLine = NotchLine((xpos, 0, self.FlexBandList[2]), (xpos, self.height, self.FlexBandList[2]), math.pi/2, self.z_joint) if rightCircle: #In this case modify the line just created #Specific case, shorten Right line of notches to take into account the wood hinge circle. Delete some notches on top SizeCut = WoodHingeSize*thickness vLine.ModifyNotchLine(SizeCut, True) #Last parameter, CutOnStart = True elif rightCircleCut: #In this case modify the line just created #Specific case, shorten Right line of notches to take into account the wood hinge circle cut. Delete some notches on bottom SizeCut = WoodHingeSize*thickness vLine.ModifyNotchLine(SizeCut, False) #Last parameter, CutOnStart = False vLine.drawNotchLine(self.path) #Draw the line of notches if rightCircleCut: #Then the cut. Choose 0.95*SizeCut because the actual circle is NOT centered of this vertical edge but shifted by thickness self.path.LineTo(xpos, self.height+thickness-SizeCut*0.95) #Then the rounded cut, almost a quarter of circle, radius SizeCut self.path.Bezier(xpos-SizeCut*0.23, self.height+thickness-SizeCut*0.90, xpos-SizeCut+thickness, self.height+thickness-SizeCut*0.551916, xpos-SizeCut+thickness, self.height+thickness) else: self.path.LineTo(xpos, self.height+thickness) DebugMsg("Start bottom line, reverse\n") #Then Bottom line (reverse from top line) if self.FlexBandList[2] == 0: #External end ? self.path.LineTo(xpos - thickness, self.height+thickness) xpos -= thickness for i in range(len(self.FlexBandList)-1, 2, -1): #Start at end up to third element #For reverse drawing, should have the radius of the next corner if i > 3: NextRadius = self.FlexBandList[i-1][2] else: NextRadius = 0 FlexElement = self.FlexBandList[i] DebugMsg("Element "+str(i)+": xpos="+str(xpos)+' Size ='+str(FlexElement[0])+' radius ='+str(FlexElement[2])+' --> '+str(FlexElement[2]*math.pi/2)+' Next Radius='+str(NextRadius)+'\n') #First the line corresponding to rounded corner (reverse from previous) DebugMsg("Draw line for rounded corner, size ="+str(FlexElement[2]*math.pi/2)+" New xpos="+str(xpos - FlexElement[2]*math.pi/2)+'\n') if FlexElement[2] > 0: self.path.LineTo(xpos - FlexElement[2]*math.pi/2, self.height+thickness) xpos -= FlexElement[2]*math.pi/2 #Then Notch Line if i == 3 and leftCircleCut: #specific case, draw up to start of cut self.path.LineTo(SizeCut - thickness , self.height+thickness) xpos = 0 #Not true yet, but needed to place the vertical line at the right position DebugMsg("leftCircleCut True, pathto "+str((SizeCut - thickness , self.height+thickness))+" xpos ="+str(xpos)+"\n") else: hLine = NotchLine((xpos, self.height+thickness, 0), (xpos-(FlexElement[0]-FlexElement[2]-NextRadius), self.height+thickness, 0), math.pi, FlexElement[BotJointOff]) hLine.drawNotchLine(self.path) xpos -= FlexElement[0] - NextRadius - FlexElement[2] if leftCircleCut == False: if self.FlexBandList[1] == 0: #External Start ? self.path.LineTo(xpos - thickness, self.height+thickness) xpos -= thickness self.path.LineTo(xpos, self.height) #Then Vertical notch line for left edge vLine = NotchLine((xpos, self.height, self.FlexBandList[1]), (xpos, 0, self.FlexBandList[1]), -math.pi/2, self.z_joint) if leftCircle: SizeCut = WoodHingeSize*thickness vLine.ModifyNotchLine(SizeCut, False) #Last parameter, CutOnStart = False, because we start at bottom elif leftCircleCut: #In this case, shorten the notch line on bottom because of the circle cut SizeCut = WoodHingeSize*thickness vLine.ModifyNotchLine(SizeCut, True) #Last parameter, CutOnStart = True, because we start at bottom #Draw the rounded cut, almost a quarter of circle, radius ExtRadius self.path.Bezier(SizeCut-thickness, self.height+thickness-SizeCut*0.551916 , SizeCut*0.23, self.height+thickness-SizeCut*0.90 , 0, self.height+thickness-SizeCut*0.95) vLine.drawNotchLine(self.path) DebugMsg('Vertical Line 2, xpos='+str(xpos)+'\n') #Draw up to -thickness because external in Y direction if leftCircle: self.path.LineTo(xpos, SizeCut - thickness) else: self.path.LineTo(xpos, -thickness) # If circle, draw interior and rectangles #Case with WoodHingeCorner, draw circle and rectangle if leftCircle: #Draw the circle internal to the hinge, radius is 2*thickness mm CircleRadius = WoodHingeInternalCircle*thickness self.path.drawCircle(leftCirclePos, -thickness, CircleRadius) #Then the internal rectangle, rectangle height is 1.5*thickness RectHeight = WoodHingeRect*thickness self.path.MoveTo(leftCirclePos, -thickness) #Starting point Ext/Bottom self.path.LineToVRel(-RectHeight) #Ext/Top self.path.LineToHRel(thickness) #Int/Top self.path.LineToVRel(RectHeight) #Int Bottom self.path.LineToHRel(-thickness) #Return to start if rightCircle: #Draw the circle internal to the hinge, radius is 2*thickness mm CircleRadius = WoodHingeInternalCircle*thickness self.path.drawCircle(rightCirclePos, -thickness, CircleRadius) #Then the internal rectangle, rectangle height is 1.5*thickness RectHeight = WoodHingeRect*thickness self.path.MoveTo(rightCirclePos, -thickness) #Starting point Ext/Bottom self.path.LineToVRel(-RectHeight) #Ext/Top self.path.LineToHRel(-thickness) #Int/Top self.path.LineToVRel(RectHeight) #Int Bottom self.path.LineToHRel(thickness) #Return to start #Now draw flex lines for FlexLinePos in ListFlexLines: Flex = FlexLines() Flex.drawFlexLines(FlexLinePos[0], self.height, FlexLinePos[1], self.path) #Get bounding box of path self.BoundingBox = (self.path.xmin, self.path.ymin, self.path.xmax, self.path.ymax) if ClosePath: self.path.Close() self.path.GenPath() def drawRoundedFlexFace(self, ClosePath): ''' Draw a Flex band when all corners are rounded. This is a specific case because there are clips at the center of back face Back face should be the first in list ''' #Compute clips number and position, zone with clips will be between thickness and zbox - thickness zoneclips = self.height - 2*thickness #Size of clips is dependant to size of zoneclips if zoneclips < 50: sizeclips = 10 else: sizeclips = 18 nbclips = int(zoneclips // sizeclips) if nbclips == 0: inkex.errormsg('Box is not high enough, no rrom for clips') return DebugMsg("\ndrawRoundedFlexFace, sizeclips="+str(sizeclips)+" nbclips="+str(nbclips)+'\n') ListFlexLines = [] LastRadius = self.FlexBandList[6][2] # Radius of left back corner xpos = 0 FlexElement = self.FlexBandList[3] DebugMsg("First Half notch line, size ="+str(FlexElement[0])+" Size Round BackLeft="+str(LastRadius)+" Size Round BackRight="+str(FlexElement[2])+'\n') #The notch line will be centered on xpos (0), so should start at -(SizeNotchLine-SizeRadius_BackLeft-SizeRadius_BackRight)/2 First_hLine = NotchLine((-(FlexElement[0]-FlexElement[2] - LastRadius)/2, -thickness, 0), ((FlexElement[0]-FlexElement[2] - LastRadius)/2, -thickness, 0), 0.0, FlexElement[1], 1) #Draw only second half if First_hLine.StartStatus == 0: self.path.MoveTo(0, -thickness) # Start position (0, -thickness) because flex band is external in Y direction, and this side start internal in X else: self.path.MoveTo(0, 0) # Start position (0, 0) because flex band is internal in Y direction, and this side start internal in X First_hLine.drawNotchLine(self.path) xpos = (FlexElement[0]-FlexElement[2]-LastRadius)/2 DebugMsg("After drawing first half of notch line, xpos ="+str(xpos)+'\n') ListFlexLines.append((xpos, FlexElement[2])) #Add this position to draw flex lines. #Then the line corresponding to rounded corner if FlexElement[2] > 0: self.path.LineTo(xpos + FlexElement[2]*math.pi/2, -thickness) xpos += FlexElement[2]*math.pi/2 DebugMsg("Line corresponding to back right corner, l="+str(FlexElement[2]*math.pi/2)+" xpos="+str(xpos)+'\n') LastRadius = FlexElement[2] #Now read all elements (4..N-1) --> 4..6 here for i in range(4, 7): FlexElement = self.FlexBandList[i] DebugMsg("Element "+str(i)+": xpos="+str(xpos)+' Size ='+str(FlexElement[0])+' radius ='+str(FlexElement[2])+" LastRadius="+str(LastRadius)+"--> "+str(FlexElement[0] - LastRadius - FlexElement[2]) +'\n') #First Notch Line hLine = NotchLine((xpos, -thickness, 0), (xpos+FlexElement[0] - LastRadius - FlexElement[2] , -thickness, 0), 0.0, FlexElement[1], 0) hLine.drawNotchLine(self.path) xpos += FlexElement[0] - LastRadius - FlexElement[2] #Then the line corresponding to rounded corner if FlexElement[2] > 0: self.path.LineTo(xpos + FlexElement[2]*math.pi/2, -thickness) ListFlexLines.append((xpos, FlexElement[2])) xpos += FlexElement[2]*math.pi/2 LastRadius = FlexElement[2] DebugMsg("After drawing line for rounded corner, xpos="+str(xpos)+'\n') #Last element FlexElement = self.FlexBandList[7] DebugMsg("Last Element (7): xpos="+str(xpos)+' Size ='+str(FlexElement[0])+' radius ='+str(FlexElement[2])+" LastRadius="+str(LastRadius)+"--> "+str(FlexElement[0] - LastRadius - FlexElement[2]) +'\n') #Last Notch Line, at last half of it ! First half indeed. hLine = NotchLine((xpos, -thickness, 0), (xpos+FlexElement[0] - LastRadius - FlexElement[2], -thickness, 0), 0.0, FlexElement[1], -1) hLine.drawNotchLine(self.path) xpos += (FlexElement[0] - LastRadius - FlexElement[2])/2 self.path.LineTo(xpos, thickness) DebugMsg('Clip Line 1, xpos='+str(xpos)+'\n') #Then Vertical clip line self.path.LineToVRel((zoneclips - nbclips*sizeclips)/2) for i in range(nbclips): self.drawClip(sizeclips, 1) DebugMsg("Bottom line, reverse, start at xpos="+str((xpos, self.height+thickness))+'\n') #Then Bottom line (reverse from top line) FlexElement = self.FlexBandList[7] #Element 7 is the last one, with radius of Back Right corner NextRadius = self.FlexBandList[6][2] #This is the radius of the left right corner DebugMsg("Element 7: xpos="+str(xpos)+' Size ='+str(FlexElement[0])+' radius ='+str(FlexElement[2])+' --> '+str(FlexElement[0]-FlexElement[2]-NextRadius)+'\n') #Last Notch Line, half line. Center line on xpos hLine = NotchLine((xpos + (FlexElement[0] - NextRadius - FlexElement[2])/2, self.height+thickness, 0), (xpos-(FlexElement[0] - NextRadius - FlexElement[2])/2, self.height+thickness, 0), math.pi, FlexElement[3], 1) if hLine.StartStatus == 0: self.path.LineTo(xpos, self.height+thickness) else: self.path.LineTo(xpos, self.height) hLine.drawNotchLine(self.path) xpos -= (FlexElement[0] - NextRadius - FlexElement[2])/2 for i in range(6, 3, -1): #Start at end up to third element FlexElement = self.FlexBandList[i] NextRadius = self.FlexBandList[i-1][2] DebugMsg("Element "+str(i)+": xpos="+str(xpos)+' Size ='+str(FlexElement[0])+" radius ="+str(FlexElement[2])+" NextRadius="+str(NextRadius)+' --> '+str(FlexElement[0] - FlexElement[2] - NextRadius)+'\n') #First the line corresponding to rounded corner (reverse from previous) if FlexElement[2] > 0: self.path.LineTo(xpos - FlexElement[2]*math.pi/2, self.height+thickness) xpos -= FlexElement[2]*math.pi/2 DebugMsg("After line for rounded corner, l="+str(FlexElement[2]*math.pi/2)+" Pos="+str((xpos, self.height+thickness))+'\n') #Then Notch Line hLine = NotchLine((xpos, self.height+thickness, 0), (xpos-(FlexElement[0] - FlexElement[2] - NextRadius), self.height+thickness, 0), math.pi, FlexElement[3], 0) hLine.drawNotchLine(self.path) xpos -= FlexElement[0] - FlexElement[2] - NextRadius NextRadius = self.FlexBandList[7][2] FlexElement = self.FlexBandList[3] DebugMsg("First Element (3): xpos="+str(xpos)+' Size ='+str(FlexElement[0])+" radius ="+str(FlexElement[2])+" NextRadius="+str(NextRadius)+' --> '+str(FlexElement[0] - FlexElement[2] - NextRadius)+'\n') #Then Last round corner self.path.LineTo(xpos - FlexElement[2]*math.pi/2, self.height+thickness) xpos -= FlexElement[2]*math.pi/2 DebugMsg("Last Round corner, l="+str(FlexElement[2]*math.pi/2)+" new pos="+str((xpos, self.height+thickness))+'\n') #Then Notch Line, half of it hLine = NotchLine((xpos, self.height+thickness, 0), (xpos-(FlexElement[0]-FlexElement[2]-LastRadius), self.height+thickness, 0), math.pi, FlexElement[3], -1) #Draw only first half hLine.drawNotchLine(self.path) xpos -= (FlexElement[0]-FlexElement[2] - LastRadius)/2 self.path.LineTo(xpos, self.height) #Then Vertical clip line DebugMsg('Vertical Clip 2, pos='+str((xpos, self.height))+'\n') #and vertical trip (reverse) self.path.LineToVRel(-1.0*((zoneclips - nbclips*sizeclips)/2) - thickness) for i in range(nbclips): self.drawClip(sizeclips, -1) if First_hLine.StartStatus == 0: #If StartStatus is external, move to (0,-Thickness) self.path.LineTo(0, -thickness) else: self.path.LineTo(0, 0) #Now draw flex lines for FlexLinePos in ListFlexLines: Flex = FlexLines() Flex.drawFlexLines(FlexLinePos[0], self.height, FlexLinePos[1], self.path) #Get bounding box of path self.BoundingBox = (self.path.xmin, self.path.ymin, self.path.xmax, self.path.ymax) if ClosePath: self.path.Close() self.path.GenPath() def drawSideLineNotches(self): ''' Draw the side line notches used with sliding lid. These lines are on left and right (if flex) lines These lines are created whenever the top notches are not null ''' n_side_line = 0 ypos = -self.BoundingBox[1] LastRadius = 0 for i in range(3, len(self.FlexBandList)): FlexElement = self.FlexBandList[i] if FlexElement[1] > 0: #Notches are present, draw SideLine with notches n_side_line += 1 DebugMsg("\nDraw "+self.BaseName+'LidJoint'+str(n_side_line)+" Radius="+str(FlexElement[2])+" LastRadius="+str(LastRadius)+" Size ="+str(FlexElement[0] - FlexElement[2] - LastRadius)+'\n') Line = BoxFace(self.BaseName+'LidJoint'+str(n_side_line), CornerPoint((0,0), 0, 1, 1), 0, #Start point, no notch CornerPoint((FlexElement[0] - FlexElement[2] - LastRadius,0), 0, 1, 1), 0, #Size is up to rounded corner, no notch for the small side CornerPoint((FlexElement[0] - FlexElement[2] - LastRadius,thickness), 0, 1, 1), FlexElement[1], #Same x, height = 2*thickness, joints up to next CornerPoint((0, thickness), 0, 1, 1), 0, self.InkscapeGroup, [-self.BoundingBox[2]-2, ypos]) ypos -= 2*thickness + 2 Line.drawSimpleFace(True) LastRadius = FlexElement[2] class BoxFace: ''' This class deals with faces Each face is defined with 4 corners and the size of the finger joints between the corners finger joint size = 0 means no finger joints (straight line) The InkscapeGroup parameter is used to bind the path in this group The PositionInPage parameter is used to fix the path within the inkscape document ''' def __init__(self, name, top_left, top_finger_joint, top_right, right_finger_joint, bottom_right, bottom_finger_joint, bottom_left, left_finger_joint, InkscapeGroup, PositionInPage, Path=None): #First set up the corners self.top_left_corner = top_left self.top_right_corner = top_right self.bottom_right_corner = bottom_right self.bottom_left_corner = bottom_left #then the lines between the corners self.TopLine = NotchLine((top_left.x_start_joint, top_left.y_start_joint, top_left.y_internal), (top_right.x_end_joint, top_right.y_end_joint, top_right.y_internal), 0, top_finger_joint) self.RightLine = NotchLine((top_right.x_start_joint, top_right.y_start_joint, top_right.x_internal), (bottom_right.x_end_joint, bottom_right.y_end_joint, bottom_right.x_internal), math.pi/2, right_finger_joint) self.BottomLine = NotchLine((bottom_right.x_start_joint, bottom_right.y_start_joint, bottom_right.y_internal), (bottom_left.x_end_joint, bottom_left.y_end_joint, bottom_left.y_internal), math.pi, bottom_finger_joint) self.LeftLine = NotchLine((bottom_left.x_start_joint, bottom_left.y_start_joint, bottom_left.x_internal), (top_left.x_end_joint, top_left.y_end_joint, top_left.x_internal), -math.pi/2, left_finger_joint) #Update PositionInPage to take into account external corners or notches if self.top_left_corner.WoodHingeCorner: PositionInPage[0] -= (WoodHingeSize+1)*thickness PositionInPage[1] -= WoodHingeSize*thickness elif self.top_right_corner.WoodHingeCorner: PositionInPage[1] -= WoodHingeSize*thickness PositionInPage[0] -= thickness elif self.top_left_corner.x_internal == 0 or self.bottom_left_corner.x_internal == 0 or self.LeftLine.nb_finger_joint > 0: PositionInPage[0] -= thickness if self.top_left_corner.y_internal == 0 or self.top_right_corner.y_internal == 0 or self.TopLine.nb_finger_joint > 0: PositionInPage[1] -= thickness self.BoundingBox = (-PositionInPage[0], -PositionInPage[1], -PositionInPage[0], -PositionInPage[1]) self.name = name self.InkscapeGroup = InkscapeGroup #If needed, create path which will be used to draw the face #The path will be in the group InkscapeGroup if Path == None: self.path = th_inkscape_path(PositionInPage, InkscapeGroup, name) DebugMsg("Creating path("+name+") Position ="+str(PositionInPage)+'\n') else: self.path = Path #DebugMsg("Create path "+str(name)+ " PositionInPage="+str(PositionInPage)+'\n') def Close(self): ''' Close and write the path after drawing is done ''' self.path.Close() self.path.GenPath() def drawSimpleFace(self, ClosePath): ''' Draw the face, when there are no other elements in the perimeter If ClosePath is true the path is closed ''' if self.top_left_corner.WoodHingeCorner: #Specific case, shorten Left line of notches to take into account the wood hinge circle #But first copy values from right edge, because WoodHingeCorner has modified the notch line self.LeftLine.start_line_joint_y = self.RightLine.end_line_joint_y self.LeftLine.JointSize = self.RightLine.JointSize self.LeftLine.nb_finger_joint = self.RightLine.nb_finger_joint self.LeftLine.EndY = self.RightLine.StartY SizeCut = WoodHingeSize * thickness #Start from bottom (because reverse on left line) up to sizecut self.LeftLine.ModifyNotchLine(SizeCut, False) #Last parameter, CutOnStart = False, because we start at bottom if self.top_right_corner.WoodHingeCorner: #Specific case, shorten Right line of notches to take into account the wood hinge circle #But first copy values from Left edge, because WoodHingeCorner has modified the notch line self.RightLine.start_line_joint_y = self.LeftLine.end_line_joint_y self.RightLine.end_line_joint_y = self.LeftLine.start_line_joint_y self.RightLine.JointSize = self.LeftLine.JointSize self.RightLine.nb_finger_joint = self.LeftLine.nb_finger_joint self.RightLine.StartY = self.LeftLine.EndY SizeCut = WoodHingeSize * thickness self.RightLine.ModifyNotchLine(SizeCut, True) #Last parameter, CutOnStart = False, because we start at Top # Go To starting point self.path.MoveTo(self.top_left_corner.x_end_joint, self.top_left_corner.y_end_joint) #DebugMsg("StartPoint, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #first (top left) corner self.top_left_corner.drawCorner(self.path) #DebugMsg("TopLeft, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #then top edge self.TopLine.drawNotchLine(self.path) #DebugMsg("Top Edge, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Top right corner self.top_right_corner.drawCorner(self.path) #DebugMsg("Top Right corner, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Right edge self.RightLine.drawNotchLine(self.path) #DebugMsg("Right Edge, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Bottom right corner self.bottom_right_corner.drawCorner(self.path) #DebugMsg("Bottom Right corner, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Bottom edge self.BottomLine.drawNotchLine(self.path) #DebugMsg("Bottom Edge, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Bottom left corner self.bottom_left_corner.drawCorner(self.path) #DebugMsg("Bottom Left corner, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Left edge self.LeftLine.drawNotchLine(self.path) #DebugMsg("Left Edge, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #The position is now (top_left_corner.x_end_joint, top_left_corner.y_end_joint), it is the starting point #Case with WoodHingeCorner, draw circle and rectangle if self.top_left_corner.WoodHingeCorner: #Draw the circle internal to the hinge, radius is 2*thickness mm CircleRadius = WoodHingeInternalCircle*thickness self.path.drawCircle(-thickness, -thickness, CircleRadius) #Then the internal rectangle, rectangle height is 1.5*thickness RectHeight = WoodHingeRect*thickness self.path.MoveTo(-thickness, -thickness) #Starting point Ext/Bottom self.path.LineToVRel(-RectHeight) #Ext/Top self.path.LineToHRel(thickness) #Int/Top self.path.LineToVRel(RectHeight) #Int Bottom self.path.LineToHRel(-thickness) #Return to start if self.top_right_corner.WoodHingeCorner: #Draw the circle internal to the hinge, radius is 2*thickness mm CircleRadius = WoodHingeInternalCircle*thickness self.path.drawCircle(self.top_right_corner.x_corner+thickness, -thickness, CircleRadius) #Then the internal rectangle, rectangle height is 1.5*thickness RectHeight = WoodHingeRect*thickness self.path.MoveTo(self.top_right_corner.x_corner+thickness, -thickness) #Starting point Ext/Bottom self.path.LineToVRel(-RectHeight) #Ext/Top self.path.LineToHRel(-thickness) #Int/Top self.path.LineToVRel(RectHeight) #Int Bottom self.path.LineToHRel(thickness) #Return to start #Get bounding box of path self.BoundingBox = (self.path.xmin, self.path.ymin, self.path.xmax, self.path.ymax) #Close the path if asked if ClosePath: self.path.Close() self.path.GenPath() def drawSimpleFaceHinge(self, HingeList, ClosePath): ''' Draw the face, and the cut for the hinge If ClosePath is true the path is closed ''' # Go To starting point self.path.MoveTo(self.top_left_corner.x_end_joint, self.top_left_corner.y_end_joint) #DebugMsg("StartPoint, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #first (top left) corner self.top_left_corner.drawCorner(self.path) #DebugMsg("TopLeft, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #then top edge, no notch in this case, but cut for the hinge(s) for Hinge in HingeList: HingePos = Hinge[2] - 1 self.path.LineTo(HingePos, 0) #Then cut for the Hinge self.path.LineToVRel(4.5*thickness+1) self.path.LineToHRel(5*thickness + 2.5*SteelHingeSpacing + 2) self.path.LineToVRel(-4.5*thickness-1) #Then line up to length self.path.LineTo(self.top_right_corner.x_corner, 0) #Up to end of top line #Top right corner self.top_right_corner.drawCorner(self.path) #DebugMsg("Top Right corner, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Right edge self.RightLine.drawNotchLine(self.path) #DebugMsg("Right Edge, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Bottom right corner self.bottom_right_corner.drawCorner(self.path) #DebugMsg("Bottom Right corner, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Bottom edge self.BottomLine.drawNotchLine(self.path) #DebugMsg("Bottom Edge, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Bottom left corner self.bottom_left_corner.drawCorner(self.path) #DebugMsg("Bottom Left corner, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Left edge self.LeftLine.drawNotchLine(self.path) #DebugMsg("Left Edge, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #The position is now (top_left_corner.x_end_joint, top_left_corner.y_end_joint), it is the starting point #Get bounding box of path self.BoundingBox = (self.path.xmin, self.path.ymin, self.path.xmax, self.path.ymax) #Close the path if asked if ClosePath: self.path.Close() self.path.GenPath() #DebugMsg("Closing path, BoundingBox="+str(self.BoundingBox)+'\n') def drawFaceWithHoles(self, n_slot, slot_size, DeltaHolePosition, z_joint_size, ClosePath, HingeList = None): ''' Draw a face with holes (for internal walls) The holes positions are given in a list (see CalcNotchPos), and an offset will be added if necessary (shorten face) ''' if HingeList == None: #No cut for hinge, call regular function to draw face self.drawSimpleFace(False) #First draw the face itself, without closing path else: self.drawSimpleFaceHinge(HingeList, False) #First draw the face itself, without closing path #now the holes used to fix the walls #This line will be used to draw the holes l_NotchLine = NotchLine((0, 0, 1), (self.bottom_right_corner.y_end_joint, 0, 1), math.pi/2, z_joint_size) StartHole = l_NotchLine.start_line_joint_y + l_NotchLine.JointSize Spacing = 2*l_NotchLine.JointSize DebugMsg("drawFaceWithHoles, Hole Start ="+str(StartHole)+" Spacing="+str(Spacing)+" n_holes"+str(l_NotchLine.nb_finger_joint//2) +' n_slot='+str(n_slot)+' slot_size='+str(slot_size)+" Delta_Pos="+str(DeltaHolePosition)+'\n') for i in range(1, n_slot): #For each wall, draw holes corresponding at each notch on zbox for j in range((l_NotchLine.nb_finger_joint)//2): drawHole(self.path, i*(slot_size+thickness) - DeltaHolePosition -thickness, StartHole + j*Spacing, thickness, l_NotchLine.JointSize, burn) #Close the path if asked if ClosePath: self.path.Close() self.path.GenPath() def drawSideLineNotches(self, xpos, ypos): ''' Draw the side line notches used with sliding lid. These lines are on left and right lines These lines are created whenever the top notches are not null ''' n_side_line = 0 Line = BoxFace(self.name+'LidJoint', CornerPoint((0,0), 0, 1, 1), 0, #Start point, no notch CornerPoint((self.top_right_corner.xc - self.top_left_corner.xc,0), 0, 1, 1), 0, #Size is up to rounded corner, no notch for the small side CornerPoint((self.top_right_corner.xc - self.top_left_corner.xc,thickness), 0, 1, 1), self.TopLine.JointSize, #Same x, height = 2*thickness, joints up to next CornerPoint((0, thickness), 0, 1, 1), 0, self.InkscapeGroup, [xpos, ypos]) Line.drawSimpleFace(True) def drawExternalBackSlidingLid(self, ClosePath): ''' Draw the face, specific case for sliding lid back face If ClosePath is true the path is closed ''' # Go To starting point self.path.MoveTo(self.top_left_corner.x_end_joint, self.top_left_corner.y_end_joint) #first (top left) corner self.top_left_corner.drawCorner(self.path) #DebugMsg("TopLeft, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Then draw below thickness self.path.LineToVRel(thickness) #then top edge, without notches self.path.LineToHRel(self.top_right_corner.x_end_joint) #Then Up thickness self.path.LineToVRel(-thickness) #Top right corner self.top_right_corner.drawCorner(self.path) #DebugMsg("Top Right corner, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Right edge self.RightLine.drawNotchLine(self.path) #DebugMsg("Right Edge, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Bottom right corner self.bottom_right_corner.drawCorner(self.path) #DebugMsg("Bottom Right corner, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Bottom edge self.BottomLine.drawNotchLine(self.path) #DebugMsg("Bottom Edge, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Bottom left corner self.bottom_left_corner.drawCorner(self.path) #DebugMsg("Bottom Left corner, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Left edge self.LeftLine.drawNotchLine(self.path) #DebugMsg("Left Edge, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #The position is now (top_left_corner.x_end_joint, top_left_corner.y_end_joint), it is the starting point #Get bounding box of path self.BoundingBox = (self.path.xmin, self.path.ymin, self.path.xmax, self.path.ymax) #Close the path if asked if ClosePath: self.path.Close() self.path.GenPath() #DebugMsg("Closing path, BoundingBox="+str(self.BoundingBox)+'\n') def drawExternalBackWoodHingeLid(self, ClosePath): ''' Draw the face, specific case for wood hinge lid back face This face will use a specific vertical notch lines, which are shorter by the circle of the hinge If ClosePath is true the path is closed ''' DebugMsg("\n enter drawExternalBackWoodHingeLid\n") #Size of wood hinge cut SizeCut = WoodHingeSize*thickness + 2*burn #Modify right line to accomodate this cut self.RightLine.ModifyNotchLine(SizeCut, True) #Do the same for left line, but reverse self.LeftLine.ModifyNotchLine(SizeCut, False) # Go To starting point self.path.MoveTo(0, -thickness) self.path.LineTo(self.top_right_corner.x_end_joint, -thickness) #Space for cut #Then go to cut self.path.LineToVRel(SizeCut) self.path.LineToHRel(thickness) #Right edge self.RightLine.drawNotchLine(self.path) #Bottom right corner self.bottom_right_corner.drawCorner(self.path) #Bottom edge self.BottomLine.drawNotchLine(self.path) #Bottom left corner self.bottom_left_corner.drawCorner(self.path) #Left edge self.LeftLine.drawNotchLine(self.path) #Then cut self.path.LineToHRel(thickness) self.path.LineTo(0, -thickness) #The position is now (top_left_corner.x_end_joint, top_left_corner.y_end_joint), it is the starting point #Get bounding box of path self.BoundingBox = (self.path.xmin, self.path.ymin, self.path.xmax, self.path.ymax) #Close the path if asked if ClosePath: self.path.Close() self.path.GenPath() #DebugMsg("Closing path, BoundingBox="+str(self.BoundingBox)+'\n') def drawLidBackWoodHinge(self, ClosePath): ''' Draw the lid back when Wood hinge is chosen, specific case for wood hinge lid back face This face will use a specific vertical notch lines, which are shorter by the circle of the hinge If ClosePath is true the path is closed ''' #Size of wood hinge cut SizeCut = WoodHingeSize*thickness + 2*burn DebugMsg("\n enter drawLidBackWoodHinge, SizeCut = "+str(SizeCut)+"\n") DebugMsg("Joint size ="+str(self.RightLine.JointSize)+" Top_Right="+str((self.top_right_corner.x_corner, self.top_right_corner.y_corner))+" Bottom Right="+str((self.bottom_right_corner.x_corner, self.bottom_right_corner.y_corner))+"\n") #Change right line, from top to bottom RightLine self.RightLine.ModifyNotchLine(SizeCut, False) #Last Parameter false because we start on Top and cut is on bottom #The left line will be the same but reverse self.LeftLine.ModifyNotchLine(SizeCut, True) #Last Parameter false because we start on Bottom and cut is on bottom # Go To starting point self.path.MoveTo(self.top_left_corner.x_end_joint, self.top_left_corner.y_end_joint) #DebugMsg("StartPoint, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #first (top left) corner self.top_left_corner.drawCorner(self.path) #DebugMsg("TopLeft, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #then top edge self.TopLine.drawNotchLine(self.path) #DebugMsg("Top Edge, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Top right corner self.top_right_corner.drawCorner(self.path) #Right edge self.RightLine.drawNotchLine(self.path) #Then the cut with the notch for the circle StartNotchCircle = 1.5 * thickness self.path.LineToHRel(-thickness) self.path.LineTo(self.bottom_right_corner.x_end_joint - thickness, self.bottom_right_corner.y_corner - StartNotchCircle) self.path.LineToHRel(thickness) self.path.LineToVRel(StartNotchCircle) self.path.LineTo(self.bottom_right_corner.x_end_joint - thickness, self.bottom_right_corner.y_corner) #Bottom edge self.path.LineTo(-thickness, self.bottom_left_corner.y_corner) #Then Cut self.path.LineToVRel(-StartNotchCircle) self.path.LineToHRel(thickness) self.path.LineTo(0, self.bottom_left_corner.y_corner - SizeCut) self.path.LineToHRel(-thickness) #Left edge self.LeftLine.drawNotchLine(self.path) self.path.LineTo(-thickness, -thickness) #Get bounding box of path self.BoundingBox = (self.path.xmin, self.path.ymin, self.path.xmax, self.path.ymax) #Close the path if asked if ClosePath: self.path.Close() self.path.GenPath() #DebugMsg("Closing path, BoundingBox="+str(self.BoundingBox)+'\n') def drawExternalBackSteelHingeLid(self, HingeList, ClosePath): ''' Draw the face, specific case for lid with 'steel hinge' back face This face will have cuts to place the real hinge elements HingeList is a list of Hinge position If ClosePath is true the path is closed ''' DebugMsg("\n enter drawExternalBackSteelHingeLid\n") # Go To starting point self.path.MoveTo(-thickness, -thickness) #The top line will have cut for the hinge for Hinge in HingeList: HingePos = Hinge[2] self.path.LineTo(HingePos + thickness, -thickness) #add thickness in x because hinge pos is internal, and sub thickness in y because always external #Then Hinge self.path.LineToVRel(2.5*thickness) self.path.LineToHRel(thickness) self.path.LineToVRel(-thickness + 0.5*SteelHingeSpacing) self.path.LineToHRel(thickness + SteelHingeSpacing) self.path.LineToVRel(thickness - 0.5*SteelHingeSpacing) self.path.LineToHRel(thickness) self.path.LineToVRel(-thickness + 0.5*SteelHingeSpacing) self.path.LineToHRel(thickness + SteelHingeSpacing) self.path.LineToVRel(thickness - 0.5*SteelHingeSpacing) self.path.LineToHRel(thickness) self.path.LineToVRel(-2.5*thickness) #Then line up to length self.path.LineTo(self.top_right_corner.x_corner, -thickness) #Up to end of top line #Right edge self.RightLine.drawNotchLine(self.path) #Bottom right corner self.bottom_right_corner.drawCorner(self.path) #Bottom edge self.BottomLine.drawNotchLine(self.path) #Bottom left corner self.bottom_left_corner.drawCorner(self.path) #Left edge self.LeftLine.drawNotchLine(self.path) #Then return to Start self.path.LineTo(-thickness, -thickness) #Now draw holes for the hinge(s) for Hinge in HingeList: self.path.MoveTo(Hinge[2]+thickness, 3.5*thickness) self.path.LineToHRel(thickness) self.path.LineToVRel(-thickness) self.path.LineToHRel(-thickness) self.path.LineToVRel(thickness) self.path.MoveTo(Hinge[2] + 3*thickness + SteelHingeSpacing, 3.5*thickness) self.path.LineToHRel(thickness) self.path.LineToVRel(-thickness) self.path.LineToHRel(-thickness) self.path.LineToVRel(thickness) self.path.MoveTo(Hinge[2] + 5*thickness + 2*SteelHingeSpacing, 3.5*thickness) self.path.LineToHRel(thickness) self.path.LineToVRel(-thickness) self.path.LineToHRel(-thickness) self.path.LineToVRel(thickness) #Get bounding box of path self.BoundingBox = (self.path.xmin, self.path.ymin, self.path.xmax, self.path.ymax) #Close the path if asked if ClosePath: self.path.Close() self.path.GenPath() #DebugMsg("Closing path, BoundingBox="+str(self.BoundingBox)+'\n') def drawLidBackSteelHinge(self, HingeList, ClosePath): ''' Draw the lid back, specific case for lid with 'steel hinge' back face This face will have cuts to place the real hinge elements HingeList is a list of Hinge position If ClosePath is true the path is closed ''' DebugMsg("\n enter drawLidBackSteelHinge\n") # Go To starting point self.path.MoveTo(self.top_left_corner.x_end_joint, self.top_left_corner.y_end_joint) #DebugMsg("StartPoint, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #first (top left) corner self.top_left_corner.drawCorner(self.path) #DebugMsg("TopLeft, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #then top edge self.TopLine.drawNotchLine(self.path) #DebugMsg("Top Edge, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Top right corner self.top_right_corner.drawCorner(self.path) #Right edge self.RightLine.drawNotchLine(self.path) #Bottom right corner self.bottom_right_corner.drawCorner(self.path) #Bottom edge, this one has cut for the hinge(s). z = self.bottom_right_corner.y_corner #Now draw holes for the hinge(s), reverse because draw from right to left for Hinge in reversed(HingeList): HingePos = Hinge[2] + thickness #First H line up to end of 2nd hinge self.path.LineTo(HingePos + 5*thickness + 2.5*SteelHingeSpacing, z) #Then Hinge self.path.LineToVRel(-1.5*thickness - 0.5*SteelHingeSpacing) self.path.LineToHRel(-thickness - SteelHingeSpacing) self.path.LineToVRel(-thickness + 0.5*SteelHingeSpacing) self.path.LineToHRel(-thickness) self.path.LineToVRel(thickness - 0.5*SteelHingeSpacing) self.path.LineToHRel(-thickness - SteelHingeSpacing) self.path.LineToVRel(-thickness + 0.5*SteelHingeSpacing) self.path.LineToHRel(-thickness) self.path.LineToVRel(thickness - 0.5*SteelHingeSpacing) self.path.LineToHRel(-thickness - SteelHingeSpacing) self.path.LineToVRel(1.5*thickness + 0.5*SteelHingeSpacing) #Then draw up to corner self.path.LineTo(self.bottom_left_corner.x_end_joint, self.bottom_left_corner.y_end_joint) #Bottom left corner self.bottom_left_corner.drawCorner(self.path) #Left edge self.LeftLine.drawNotchLine(self.path) #Then return to Start self.path.LineTo(-thickness, -thickness) #Then draw holes for the hinge(s) for Hinge in HingeList: HingePos = Hinge[2] + 2*thickness self.path.MoveTo(HingePos + 0.5*SteelHingeSpacing, z - 3.5*thickness) self.path.LineToHRel(thickness) self.path.LineToVRel(-thickness) self.path.LineToHRel(-thickness) self.path.LineToVRel(thickness) self.path.MoveTo(HingePos + 2*thickness + 1.5*SteelHingeSpacing, z - 3.5*thickness) self.path.LineToHRel(thickness) self.path.LineToVRel(-thickness) self.path.LineToHRel(-thickness) self.path.LineToVRel(thickness) #Get bounding box of path self.BoundingBox = (self.path.xmin, self.path.ymin, self.path.xmax, self.path.ymax) #Close the path if asked if ClosePath: self.path.Close() self.path.GenPath() #DebugMsg("Closing path, BoundingBox="+str(self.BoundingBox)+'\n') def drawLidSideWoodHinge(self, FlagRight, ClosePath): ''' Generate lid side with integrated hinge. This is a rectangle with a rounded cut for the hinge and notches on 3 edges No notch on the bottom edge ''' SizeCut = WoodHingeSize*thickness + 2*burn DebugMsg("\n enter drawLidSideWoodHinge, SizeCut="+str(SizeCut)+" FlagRight ="+str(FlagRight)+"\n") #Because of the cut on the lid, we have to change either the right of left line of notches if FlagRight > 0: self.RightLine.ModifyNotchLine(SizeCut, False) else: self.LeftLine.ModifyNotchLine(SizeCut, True) # Go To starting point self.path.MoveTo(self.top_left_corner.x_end_joint, self.top_left_corner.y_end_joint) #DebugMsg("StartPoint, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #first (top left) corner self.top_left_corner.drawCorner(self.path) #DebugMsg("TopLeft, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #then top edge self.TopLine.drawNotchLine(self.path) #DebugMsg("Top Edge, PathPos ="+str((self.path.x, self.path.y))+" Bounding Box="+str(self.path.GetBoundingBox())+'\n') #Top right corner self.top_right_corner.drawCorner(self.path) #Right edge, first start with normal notch line self.RightLine.drawNotchLine(self.path) #If right side, special case. Start with notches, but then switch to a circle if FlagRight > 0: #Then the cut. Choose 0.95*SizeCut because the actual circle is NOT centered of this vertical edge but shifted by thickness self.path.LineTo(self.top_right_corner.x_corner, self.bottom_right_corner.y_corner-SizeCut*0.95) #Then the rounded cut, almost a quarter of circle, radius SizeCut self.path.Bezier(self.top_right_corner.x_corner-SizeCut*0.23, self.bottom_right_corner.y_corner-SizeCut*0.90, self.top_right_corner.x_corner-SizeCut+thickness, self.bottom_right_corner.y_corner-SizeCut*0.551916, self.top_right_corner.x_corner-SizeCut+thickness, self.bottom_right_corner.y_corner) #No notches on bottom line, just go to next corner self.path.LineTo(0, self.bottom_left_corner.y_corner) else: self.path.LineTo(self.top_right_corner.x_corner, self.bottom_right_corner.y_corner) #Up to corner self.path.LineTo(SizeCut-thickness, self.bottom_left_corner.y_corner) #Bottom line up to circle cut #Draw the rounded cut, almost a quarter of circle, radius ExtRadius self.path.Bezier(SizeCut-thickness, self.bottom_left_corner.y_corner-SizeCut*0.551916 , SizeCut*0.23, self.bottom_left_corner.y_corner-SizeCut*0.90 , 0, self.bottom_left_corner.y_corner-SizeCut*0.95) #Left edge self.LeftLine.drawNotchLine(self.path) self.path.LineTo(0, -thickness) #Up to starting point #Get bounding box of path self.BoundingBox = (self.path.xmin, self.path.ymin, self.path.xmax, self.path.ymax) #Close the path if asked if ClosePath: self.path.Close() self.path.GenPath() #DebugMsg("Closing path, BoundingBox="+str(self.BoundingBox)+'\n') class GenericBox(inkex.Effect): """ Creates a new layer with the drawings for a parametrically generated box. """ def __init__(self): ''' init for all parameters ''' inkex.Effect.__init__(self) self.knownUnits = ['in', 'pt', 'px', 'mm', 'cm', 'm', 'km', 'pc', 'yd', 'ft'] self.arg_parser.add_argument('--unit', action = 'store', type = str, dest = 'unit', default = 'mm', help = 'Unit, should be one of ') self.arg_parser.add_argument('--thickness', action = 'store', type = float, dest = 'thickness', default = '3.0', help = 'Material thickness') self.arg_parser.add_argument('--lid_type', action = 'store', type = str, dest = 'lid_type', default = 'Simple', help = 'Box lid style ') self.arg_parser.add_argument('--n_slot_x', action = 'store', type = int, dest = 'n_slot_x', default = '2', help = 'Number of columns of slots') self.arg_parser.add_argument('--n_slot_y', action = 'store', type = int, dest = 'n_slot_y', default = '2', help = 'Number of rows of slots') self.arg_parser.add_argument('--z', action = 'store', type = float, dest = 'z', default = '40.0', help = "box height") self.arg_parser.add_argument('--y', action = 'store', type = float, dest = 'y', default = '60.0', help = "box depth") self.arg_parser.add_argument('--x', action = 'store', type = float, dest = 'x', default = '40.0', help = "box width") self.arg_parser.add_argument('--z_lid', action = 'store', type = float, dest = 'z_lid', default = '20.0', help = 'lid height') self.arg_parser.add_argument('--z_dome_lid', action = 'store', type = float, dest = 'z_dome_lid', default = '20.0', help = 'dome lid height') self.arg_parser.add_argument('--SkipFlexLines', action = 'store', type = inkex.Boolean, dest = 'SkipFlexLines', default = 'true', help = 'Skip flex lines when possible') self.arg_parser.add_argument('--burn', action = 'store', type = float, dest = 'burn', default = '0.1', help = 'laser burn size') self.arg_parser.add_argument('--StraigthCorners', action = 'store', type = inkex.Boolean, dest = 'StraigthCorners', default = 'true', help = 'Straight corners') self.arg_parser.add_argument('--back_left_radius', action = 'store', type = float, dest = 'back_left_radius', default = '10.0', help = 'Radius of top left rounded corner') self.arg_parser.add_argument('--back_right_radius', action = 'store', type = float, dest = 'back_right_radius', default = '10.0', help = 'Radius of top right rounded corner') self.arg_parser.add_argument('--front_left_radius', action = 'store', type = float, dest = 'front_left_radius', default = '10.0', help = 'Radius of bottom left rounded corner') self.arg_parser.add_argument('--front_right_radius', action = 'store', type = float, dest = 'front_right_radius', default = '10.0', help = 'Radius of bottom right rounded corner') self.arg_parser.add_argument('--AutoSize', action = 'store', type = inkex.Boolean, dest = 'AutoSizeJoints', default = 'true', help = 'Size of finger joints computed from box dimlensions') self.arg_parser.add_argument('--x_joint', action = 'store', type = float, dest = 'x_joint', default = '10.0', help = 'Size of finger joints in X direction') self.arg_parser.add_argument('--y_joint', action = 'store', type = float, dest = 'y_joint', default = '10.0', help = 'Size of finger joints in Y direction') self.arg_parser.add_argument('--z_joint', action = 'store', type = float, dest = 'z_joint', default = '10.0', help = 'Size of finger joints in Z direction') self.arg_parser.add_argument('--Topic', action = 'store', type = str, dest = 'TopicPage', help = 'Size of finger joints in Z direction') self.BoundingBox = [0, 0, 0, 0] self.HingeList = [] try: inkex.Effect.unittouu # unitouu has moved since Inkscape 0.91 except AttributeError: try: def unittouu(self, unit): return inkex.unittouu(unit) except AttributeError: pass def UpdateBoundingBox(self, Face): if Face.BoundingBox[0] < self.BoundingBox[0]: self.BoundingBox[0] = Face.BoundingBox[0] if Face.BoundingBox[1] < self.BoundingBox[1]: self.BoundingBox[1] = Face.BoundingBox[1] if Face.BoundingBox[2] > self.BoundingBox[2] - 2: self.BoundingBox[2] = Face.BoundingBox[2] + 2 if Face.BoundingBox[3] > self.BoundingBox[3] - 2: self.BoundingBox[3] = Face.BoundingBox[3] + 2 def CalcNotchPos(self, n_slot, size_slot): ''' Compute the position of notches for a vertical or horizontal line No offset, i.e. position is relative to internal side Return a list of positions, each position is a tuple with 3 elements, giving start, size of notch and group number These positions are NOT sensitive to burn factor. The burn factor should be added later if needed ''' NPos = [] if size_slot < 25: #Small size, only one notch i_notch_number = 1 notch_size = size_slot / 3 # Notch is center aligned elif size_slot < 80: #Medium size, draw 5mm notches notch_number = size_slot / 5 if (notch_number % 2) == 0: notch_number -= 1 #should be odd notch_size = size_slot / notch_number i_notch_number = int(notch_number // 2) else: #Large size, draw 10mm notches notch_number = size_slot / 10 if (notch_number % 2) == 0: notch_number -= 1 #should be odd notch_size = size_slot / notch_number i_notch_number = int(notch_number // 2) for j in range(n_slot): #For each slot for i in range(i_notch_number): NPos.append((j*(size_slot+thickness)+notch_size+2*i*notch_size, notch_size, j)) #Add a tuple with 3 elements for start, size of notch and group number return NPos def ComputeJointSize(self, xbox, ybox, zbox, back_left_radius, back_right_radius, front_right_radius, front_left_radius): ''' This function compute finger joint size It will try to have identical finger joint, but if not possible we will have different joint sizes Basic joint size : if l < 100, size = 5mm, when l > 100 --> size = 0.5*sqrt(l) ''' #First take into account radius x = min(xbox - back_left_radius - back_right_radius, xbox - front_right_radius - front_left_radius) if x < 18: inkex.errormsg('Error: box length too small, should be at least 18mm + round radius') exit() y = min(ybox - back_left_radius - front_left_radius, ybox - front_right_radius - back_right_radius) if y < 18: inkex.errormsg('Error: box depth too small, should be at least 18mm + round radius') exit() if x <= 100: basic_size_x = 5.0 else: basic_size_x = 5.0*math.pow(x/100,0.8) if y <= 100: basic_size_y = 5.0 else: basic_size_y = 5.0*math.pow(y/100,0.8) if zbox <= 100: basic_size_z = 5.0 else: basic_size_z = 5.0*math.pow(zbox/100,0.8) #DebugMsg("Basic joint sizes (1) :"+str((basic_size_x, basic_size_y, basic_size_z))+' \n') #Now try to converge towards a single size # First with x and y if basic_size_x > basic_size_y and y >= 3.0*basic_size_x + 1: #x is greater, but at least 3 joints in y direction (one notch) basic_size_y = basic_size_x if basic_size_y > basic_size_x and x >= 3.0*basic_size_y + 1: #y is greater, but at least 3 joints in x direction (one notch) basic_size_x = basic_size_y # For z direction, should have at least 3 joint size (one notch) if basic_size_x > basic_size_y: if zbox > 3*basic_size_x + 1: basic_size_z = basic_size_x else: basic_size_z = (zbox-1) / 3 #If not possible, set max finger size else: if zbox > 3*basic_size_y + 1: basic_size_z = basic_size_y else: basic_size_z = (zbox-1) / 3 #If not possible, set max finger size return(basic_size_x, basic_size_y, basic_size_z) def drawSteelHingeElement(self, idx, thickness, xOffset, yOffset, parent): StartOffset = (xOffset, yOffset) xOffset -= 2*thickness path = th_inkscape_path((xOffset, yOffset), parent, 'HingeElt_'+str(idx)) path.MoveTo(0, 0) #Start at upper right path.LineToVRel(thickness) path.LineToHRel(-thickness) path.LineToVRel(thickness) path.LineToHRel(thickness) path.LineToVRel(thickness) #Now draw half circle (radius is 1.5*thickness) #Position is now 0,3*thickness path.Bezier(1.5*thickness*0.551916, 3*thickness, 1.5*thickness, 3*thickness+1.5*thickness*0.551916, 1.5*thickness, 4.5*thickness) path.Bezier(1.5*thickness, 4.5*thickness+1.5*thickness*0.551916, 1.5*thickness*(1-0.551916), 6*thickness, 0, 6*thickness) #Second part of circle has a radius of 2*thickness path.Bezier(-2*thickness*0.551916, 6*thickness, -2*thickness, 6*thickness-2*thickness*0.551916, -2*thickness, 4*thickness) path.LineTo(-2*thickness, thickness) path.Bezier(-2*thickness, thickness*(1-0.551916), thickness*-1.551916, 0, -thickness, 0) path.LineTo(0,0) #and last the circle at center for this axis, radius is RadiusSteelHingeAxis mm path.drawCircle(0, 4.5*thickness, RadiusSteelHingeAxis) path.Close() path.GenPath() if path.xmin < self.BoundingBox[0]: self.BoundingBox[0] = path.xmin if path.ymin < self.BoundingBox[1]: self.BoundingBox[1] = path.ymin if path.xmax > self.BoundingBox[2] - 2: self.BoundingBox[2] = path.xmax + 2 if path.ymax > self.BoundingBox[3] - 2: self.BoundingBox[3] = path.ymax + 2 def BuildTop(self, xbox, ybox, back_left_radius, back_right_radius, front_right_radius, front_left_radius): ''' Draw the top of the box. It depends on the lid style ''' if self.options.lid_type == 'Without': return # Nothing in this case if self.options.lid_type == 'Sliding': #Specific case, top is a rectangle which is xbox long and ybox wide with finger joints on top #Not compatible with rounded cornerson back, so radius is set to 0 #On top, corner are internal on x and external on y #Position is set at 0,0 (first element) #There is also a line of finger joints which is xbox long and thickness wide, begin with this one TopLineBottomRight = CornerPoint((xbox+2*thickness,thickness), 0, 1, 1) TopLineBottomLeft = CornerPoint((0,thickness), 0, 1, 1) #Modify Bottom right corner to change start of line TopLineBottomRight.x_start_joint -= thickness #idem for bottom left TopLineBottomLeft.x_end_joint += thickness TopLine = BoxFace('Lid_Joints', CornerPoint((0,0), 0, 1, 1), 0, CornerPoint((xbox+2*thickness,0), 0, 1, 1), 0, TopLineBottomRight, self.x_joint, TopLineBottomLeft, 0, self.group, [0.0,0.0]) TopLine.drawSimpleFace(True) self.UpdateBoundingBox(TopLine) Top = BoxFace('Lid_Top', CornerPoint((0,0), back_left_radius, 1, 0), self.x_joint, CornerPoint((xbox,0), back_right_radius, 1, 0), 0, CornerPoint((xbox,ybox), front_right_radius, 1, 1), 0, CornerPoint((0,ybox), front_left_radius, 1, 1), 0, self.group, [-thickness,-self.BoundingBox[3]]) Top.drawSimpleFace(True) self.UpdateBoundingBox(Top) return if self.options.lid_type != 'Coffin': #For all cases except coffin, draw a rounded rectangle with internal corners Top = BoxFace('Lid_Top', CornerPoint((0,0), back_left_radius, 1, 1), self.x_joint, CornerPoint((xbox,0), back_right_radius, 1, 1), self.y_joint, CornerPoint((xbox,ybox), front_right_radius, 1, 1), self.x_joint, CornerPoint((0,ybox), front_left_radius, 1, 1), self.y_joint, self.group, [0.0, 0.0]) Top.drawSimpleFace(False) if self.options.lid_type == 'Simple': #Add a hole in the top, which the same rounded rectangle, but with thickness less in each direction TopHole = BoxFace('Lid_Int', CornerPoint((thickness,thickness), back_left_radius-thickness, 1, 1), 0, CornerPoint((xbox-thickness,thickness), back_right_radius-thickness, 1, 1), 0, CornerPoint((xbox-thickness,ybox-thickness), front_right_radius-thickness, 1, 1), 0, CornerPoint((thickness,ybox-thickness), front_left_radius-thickness, 1, 1), 0, self.group, [0.0, 0.0], Top.path) TopHole.drawSimpleFace(False) Top.Close() #Close and generate path (both if simple lid) self.UpdateBoundingBox(Top) if self.options.lid_type == 'Simple': #In this case, draw a simple face without notches, external at all corners in both directions Top = BoxFace('Lid', CornerPoint((0,0), back_left_radius, 0, 0), 0, CornerPoint((xbox,0), back_right_radius, 0, 0), 0, CornerPoint((xbox,ybox), front_right_radius, 0, 0), 0, CornerPoint((0,ybox), front_left_radius, 0, 0), 0, self.group, [-self.BoundingBox[2]-thickness-2, 0.0]) Top.drawSimpleFace(True) self.UpdateBoundingBox(Top) return def BuildBottom(self, xbox, ybox, back_left_radius, back_right_radius, front_right_radius, front_left_radius): ''' Draw the bottom of the box. It is a rounded rectangle Also draw the holes used to secure the internal walls Should exchange left and right from top to draw the external face ''' Bottom = BoxFace('Bottom', CornerPoint((0,0), back_right_radius, 1, 1), self.x_joint, CornerPoint((xbox,0), back_left_radius, 1, 1), self.y_joint, CornerPoint((xbox,ybox), front_left_radius, 1, 1), self.x_joint, CornerPoint((0,ybox), front_right_radius, 1, 1), self.y_joint, self.group, [-self.BoundingBox[2], 0.0]) #Draw it right of top, same Y Bottom.drawSimpleFace(False) #now the holes used to fix the walls #Start with columns, compute holes position self.ListNotchColumns = self.CalcNotchPos(self.n_slot_y, self.y_slot_size) DebugMsg("List Column Notches:"+str( self.ListNotchColumns)+'\n') for i in range(1, self.n_slot_x): #For each wall, draw holes corresponding at each notch_y for notch in self.ListNotchColumns: drawHole(Bottom.path, i*(self.x_slot_size+thickness), notch[0] + thickness, thickness, notch[1], burn) #Then rows self.ListNotchRows = self.CalcNotchPos(self.n_slot_x, self.x_slot_size) DebugMsg("List Row Notches:"+str( self.ListNotchRows)+'\n') for i in range(1, self.n_slot_y): #For each wall, draw holes corresponding at each notch_y for notch in self.ListNotchRows: drawHole(Bottom.path, notch[0] + thickness, i*(self.y_slot_size+thickness), notch[1], thickness, burn) Bottom.Close() self.UpdateBoundingBox(Bottom) return def drawColumWall(self, index, n_slot_y, y_slot_size, ListNotchPos, length, zbox, xOffset, yOffset, parent): ''' Draw the face, specific case for columns walls This is a specific face with cuts for row walls on top ''' DebugMsg("\nDrawColumWall, index="+str(index)+" n_Slot="+str(n_slot_y)+" Slot_Size="+str(y_slot_size)+" Length="+str(length)+" Height="+str(zbox)+" Offset="+str((xOffset, yOffset))+'\n') path = th_inkscape_path((xOffset-thickness, yOffset), parent, 'COL_WALL_'+str(index+1)) VNotchLine1 = NotchLine((length,0,1), (length, zbox, 1), math.pi/2, self.z_joint ) #Vertical Notch line VNotchLine2 = NotchLine((0,zbox,1), (0, 0, 1), -math.pi/2, self.z_joint ) #Vertical Notch line, reverse path.MoveTo(0,0) #first H line with cut to accomodate with row walls for i in range(1, n_slot_y): path.LineToHRel(y_slot_size) path.LineToVRel(zbox/2) path.LineToHRel(thickness) path.LineToVRel(-zbox/2) path.LineTo(length, 0) #Second line (V), this is a notch line path.LineTo(length, thickness) VNotchLine1.drawNotchLine(path) path.LineTo(length, zbox) #Third line (H) with notches, but at specific positions. Use reversed because, draw from right to left for Notch in reversed(ListNotchPos): path.LineTo(Notch[0]+Notch[1], zbox) path.LineToVRel(thickness) path.LineToHRel(-Notch[1]) path.LineToVRel(-thickness) path.LineTo(0, zbox) #and last one path.LineTo(0, zbox-thickness) VNotchLine2.drawNotchLine(path) path.LineTo(0, 0) #Apply bounding box of path DebugMsg("Path Bounding box="+str(((path.xmin, path.ymin), (path.xmax, path.ymax)))+'\n') if path.xmin < self.BoundingBox[0]: self.BoundingBox[0] = path.xmin if path.ymin < self.BoundingBox[1]: self.BoundingBox[1] = path.ymin if path.xmax > self.BoundingBox[2] - 2: self.BoundingBox[2] = path.xmax + 2 if path.ymax > self.BoundingBox[3] - 2: self.BoundingBox[3] = path.ymax + 2 #Close the path path.Close() path.GenPath() #DebugMsg("Closing path, BoundingBox="+str(self.BoundingBox)+'\n') def drawRowWall(self, index, n_slot_x, x_slot_size, ListNotchPos, length, zbox, xOffset, yOffset, parent): ''' Draw the face, specific case for row walls This is a specific face with cuts for columns walls on bottom ''' DebugMsg("\nDrawRowWall, index="+str(index)+" n_Slot="+str(n_slot_x)+" Slot_Size="+str(x_slot_size)+" Length="+str(length)+" Height="+str(zbox)+" Offset="+str((xOffset, yOffset))+'\n') path = th_inkscape_path((xOffset-thickness, yOffset), parent, 'ROW_WALL_'+str(index+1)) VNotchLine1 = NotchLine((length,0,1), (length, zbox, 1), math.pi/2, self.z_joint ) #Vertical Notch line VNotchLine2 = NotchLine((0,zbox,1), (0, 0, 1), -math.pi/2, self.z_joint ) #Vertical Notch line, reverse path.MoveTo(0,0) #first H line without cur, so up to length path.LineTo(length, 0) #Second line (V), this is a notch line path.LineTo(length, thickness) VNotchLine1.drawNotchLine(path) path.LineTo(length, zbox) #Third line (H) with notches, but at specific positions. Use reversed because, draw from right to left, also cut openings for columns # At each change of group, draw a cut group_num = n_slot_x - 1 for Notch in reversed(ListNotchPos): if group_num != Notch[2]: # Change of group, draw cut path.LineTo(group_num * (x_slot_size + thickness) , zbox) path.LineToVRel(-zbox/2) path.LineToHRel(-thickness) path.LineToVRel(zbox/2) group_num = Notch[2] #Change group for next pass path.LineTo(Notch[0]+Notch[1], zbox) path.LineToVRel(thickness) path.LineToHRel(-Notch[1]) path.LineToVRel(-thickness) path.LineTo(0, zbox) #and last one path.LineTo(0, zbox-thickness) VNotchLine2.drawNotchLine(path) path.LineTo(0, 0) #Apply bounding box of path DebugMsg("Path Bounding box="+str(((path.xmin, path.ymin), (path.xmax, path.ymax)))+'\n') if path.xmin < self.BoundingBox[0]: self.BoundingBox[0] = path.xmin if path.ymin < self.BoundingBox[1]: self.BoundingBox[1] = path.ymin if path.xmax > self.BoundingBox[2] - 2: self.BoundingBox[2] = path.xmax + 2 if path.ymax > self.BoundingBox[3] - 2: self.BoundingBox[3] = path.ymax + 2 #Close the path path.Close() path.GenPath() #DebugMsg("Closing path, BoundingBox="+str(self.BoundingBox)+'\n') def drawCoffinSide(self, FlagRight, ybox, zlid, z_dome_lid, xOffset, yOffset, parent): ''' Draw the sides of the coffin style lid. This is a rectangle ybox x zlid with an ellipse (ybox, z_dome_lid) on top of the rectangle There a "normal notches on the rectangle, then small notches on the ellipse, because the "front/top/Back" part will be flex ''' DebugMsg("\ndrawCoffinSide, FlagRight="+str(FlagRight)+" ybox="+str(ybox)+" zlid="+str(zlid)+" z_dome_lid="+str(z_dome_lid)+'\n') name = 'Lid_Left' if FlagRight=='Right': name = 'Lid_Right' #Change offset in y direction because this one will be drawn from bottom left. path = th_inkscape_path((xOffset-thickness, yOffset-zlid - z_dome_lid-thickness), parent, name) #First build the notch lines for the rectangle VNotchLine1 = NotchLine((0,0,1), (0, -zlid, 1), -math.pi/2, self.z_joint ) #Vertical Notch line (left side) VNotchLine2 = NotchLine((ybox,-zlid,1), (ybox, 0, 1), math.pi/2, self.z_joint ) #Vertical Notch line, right side #First point on (0,0) : bottom/left of the lid path.MoveTo(0, 0) #The draw left notch line VNotchLine1.drawNotchLine(path) #The draw the notched ellipse, this ellipse has parameters ybox/2 and z_dome_lid TopLid = Ellipse(ybox/2.0, z_dome_lid) TopLid.drawNotchedEllipse(path, math.pi, 2*math.pi, (0, -zlid)) #Now the second Notch line VNotchLine2.drawNotchLine(path) #And end with bottom line (straight) path.LineTo(0,0) #Apply bounding box of path DebugMsg("Path Bounding box="+str(((path.xmin, path.ymin), (path.xmax, path.ymax)))+'\n') if path.xmin < self.BoundingBox[0]: self.BoundingBox[0] = path.xmin if path.ymin < self.BoundingBox[1]: self.BoundingBox[1] = path.ymin if path.xmax > self.BoundingBox[2] - 2: self.BoundingBox[2] = path.xmax + 2 if path.ymax > self.BoundingBox[3] - 2: self.BoundingBox[3] = path.ymax + 2 path.Close() path.GenPath() def drawCoffinTop(self, xbox, ybox, zlid, z_dome_lid, xOffset, yOffset, parent): ''' Draw the top of the coffin style lid. This is 2 rectangle xbox x zlid separated by a flex pattern which has the length half of the ellipse (ybox, z_dome_lid), flex height is xbox ''' DebugMsg("\ndrawCoffinTop, xbox="+str(xbox)+" ybox="+str(ybox)+" zlid="+str(zlid)+" z_dome_lid="+str(z_dome_lid)+'\n') #Change offset in y direction because this one will be drawn from bottom left. path = th_inkscape_path((xOffset, yOffset - thickness), parent, 'Coffin_Top') DebugMsg("Offset ="+str((xOffset, yOffset))+" Path_Offset="+str((path.offsetX, path.offsetY))+'\n') #Create the ellipse object used to draw the flex FlexBand = Ellipse(ybox/2.0, z_dome_lid) FlexBand.Compute_Ellipse_Params(math.pi, 2*math.pi) l = FlexBand.length_ellipse #First build the notch lines for the rectangle HNotchLine1 = NotchLine((zlid, xbox+thickness, 0), (0, xbox+thickness, 0), math.pi, self.z_joint ) #Horizontal Notch line, bottom left HNotchLine2 = NotchLine((0,-thickness,0), (zlid, -thickness, 0), 0, self.z_joint ) #Horizontal Notch line, top left HNotchLine3 = NotchLine((zlid+l, xbox+thickness, 1), (2*zlid+l, xbox+thickness, 1), 0, self.z_joint ) #Horizontal Notch line, bottom right HNotchLine4 = NotchLine((2*zlid+l, -thickness, 1), (zlid+l, -thickness, 1), math.pi, self.z_joint ) #Horizontal Notch line, bottom left #In order to minimize move effects, draw the holes for the hinge first #Draw holes for the hinge(s) for Hinge in self.HingeList: HingePos = Hinge[2] + 2*thickness path.MoveTo(3.5*thickness, HingePos + 0.5*SteelHingeSpacing) path.LineToVRel(thickness) path.LineToHRel(thickness) path.LineToVRel(-thickness) path.LineToHRel(-thickness) path.MoveTo(3.5*thickness, HingePos + 2*thickness + 1.5*SteelHingeSpacing) path.LineToVRel(thickness) path.LineToHRel(thickness) path.LineToVRel(-thickness) path.LineToHRel(-thickness) #First point on (zlid,0) : bottom/left of the lid path.MoveTo(zlid, xbox+thickness) #The draw left notch line HNotchLine1.drawNotchLine(path) #The draw the bottom line with cuts for the hinge(s) #Now draw holes for the hinge(s), reverse because draw from right to left for Hinge in reversed(self.HingeList): HingePos = Hinge[2] + thickness #First H line up to end of 2nd hinge path.LineTo(0, HingePos + 5*thickness + 2.5*SteelHingeSpacing) #Then Hinge path.LineToHRel(1.5*thickness + 0.5*SteelHingeSpacing) path.LineToVRel(-thickness - SteelHingeSpacing) path.LineToHRel(thickness - 0.5*SteelHingeSpacing) path.LineToVRel(-thickness) path.LineToHRel(-thickness + 0.5*SteelHingeSpacing) path.LineToVRel(-thickness - SteelHingeSpacing) path.LineToHRel(thickness - 0.5*SteelHingeSpacing) path.LineToVRel(-thickness) path.LineToHRel(-thickness + 0.5*SteelHingeSpacing) path.LineToVRel(-thickness - SteelHingeSpacing) path.LineToHRel(-1.5*thickness - 0.5*SteelHingeSpacing) #Then draw up to corner path.LineTo(0, -thickness) #Now the second Notch line HNotchLine2.drawNotchLine(path) #Then the flex band FlexBand.drawFlexEllipse(path, xbox, self.options.SkipFlexLines, (zlid, -thickness)) #Then the third notch line HNotchLine3.drawNotchLine(path) #Then the straight line up to the next corner (top right) path.LineTo(2*zlid+l, -thickness) #And the last line HNotchLine4.drawNotchLine(path) #Apply bounding box of path DebugMsg("Path Bounding box="+str(((path.xmin, path.ymin), (path.xmax, path.ymax)))+'\n') if path.xmin < self.BoundingBox[0]: self.BoundingBox[0] = path.xmin if path.ymin < self.BoundingBox[1]: self.BoundingBox[1] = path.ymin if path.xmax > self.BoundingBox[2] - 2: self.BoundingBox[2] = path.xmax + 2 if path.ymax > self.BoundingBox[3] - 2: self.BoundingBox[3] = path.ymax + 2 path.GenPath() def effect(self): """ Draws a card box box, based on provided parameters """ global burn, thickness # input sanity check error = False if self.options.thickness < 1 or self.options.thickness > 10: inkex.errormsg('Error: thickness should be at least 1mm and less than 10mm') error = True if error: exit() self.n_slot_x = self.options.n_slot_x self.n_slot_y = self.options.n_slot_y # convert units unit = self.options.unit xbox = self.svg.unittouu(str(self.options.x) + unit) ybox = self.svg.unittouu(str(self.options.y) + unit) zbox = self.svg.unittouu(str(self.options.z) + unit) zlid = self.svg.unittouu(str(self.options.z_lid) + unit) z_dome_lid = self.svg.unittouu(str(self.options.z_dome_lid) + unit) if self.options.StraigthCorners: back_left_radius = 0 back_right_radius = 0 front_right_radius = 0 front_left_radius = 0 else: back_left_radius = self.svg.unittouu(str(self.options.back_left_radius) + unit) back_right_radius = self.svg.unittouu(str(self.options.back_right_radius) + unit) front_right_radius = self.svg.unittouu(str(self.options.front_right_radius) + unit) front_left_radius = self.svg.unittouu(str(self.options.front_left_radius) + unit) max_radius = max(back_left_radius, back_right_radius, front_right_radius, front_left_radius) thickness = self.svg.unittouu(str(self.options.thickness) + unit) burn = self.svg.unittouu(str(self.options.burn) + unit) self.x_joint = self.svg.unittouu(str(self.options.x_joint) + unit) self.y_joint = self.svg.unittouu(str(self.options.y_joint) + unit) self.z_joint = self.svg.unittouu(str(self.options.z_joint) + unit) self.x_slot_size = (xbox - (1+self.n_slot_x)*thickness)/self.n_slot_x self.y_slot_size = (ybox - (1+self.n_slot_y)*thickness)/self.n_slot_y if self.x_slot_size < 18 or self.y_slot_size < 18: inkex.errormsg('Error: each slot should be at least 18mm large, here x_slot_size='+str(self.x_slot_size)+ ' y_slot_size='+str(self.y_slot_size)) exit() if self.x_slot_size < max_radius or self.y_slot_size < max_radius: inkex.errormsg('Error: slot size should be greater than rounded corner radius, here x_slot_size='+str(self.x_slot_size)+ ' y_slot_size='+str(self.y_slot_size)) exit() svg = self.document.getroot() docWidth = self.svg.unittouu(svg.get('width')) docHeigh = self.svg.unittouu(svg.attrib['height']) layer = etree.SubElement(svg, 'g') layer.set(inkex.addNS('label', 'inkscape'), 'Generic Box') layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer') self.group = etree.SubElement(layer, 'g') OpenDebugFile() HasLid = False HasNormalLid = False #Compute joint size if auto is chosen if self.options.AutoSizeJoints: self.x_joint, self.y_joint, self.z_joint = self.ComputeJointSize(xbox, ybox, zbox, back_left_radius, back_right_radius, front_right_radius, front_left_radius) #Default case, for the top lines, front and back joints are x_joint in size, left and right joints are y_joint in size self.front_joint = self.x_joint self.back_joint = self.x_joint self.right_joint = self.y_joint self.left_joint = self.y_joint DebugMsg("Joints size ="+str((self.x_joint, self.y_joint, self.z_joint))+'\n') DebugMsg("Slots X N="+str(self.n_slot_x)+" size="+str(self.x_slot_size)+'\n') DebugMsg("Slots Y N="+str(self.n_slot_y)+" size="+str(self.y_slot_size)+'\n') #Now, check if internal walls should be drawn self.InternalWalls_LR = False self.InternalWalls_FB = False zbox_internal_walls = zbox #Height of internal walls #If there are slots inside the box, also draw internal walls if self.n_slot_x > 1: self.InternalWalls_FB = True if self.n_slot_y > 1: self.InternalWalls_LR = True # If lid is sliding, there are always internal walls left and right if self.options.lid_type == 'Sliding': self.InternalWalls_LR = True zbox += thickness #Also increase box height to take into account the sliding top, but NOT internal walls height zbox_internal_walls -= 0.2 #Indeed, reduce internal wall height to ease sliding if back_left_radius > 0 or back_right_radius > 0: inkex.errormsg('Error: Sliding lid is incompatible with rounded corners on back') exit() self.front_joint = 0 #No joint on front top # If there is no lid, no notches on top if self.options.lid_type == 'Without': self.front_joint = 0 #No joint on front top self.back_joint = 0 #No joint on back top self.right_joint = 0 #No joint on right top self.left_joint = 0 #No joint on left top #As top edges are external, but without notches, just decrease height by thickness zbox -= thickness # If this is a real lid, no round corners allowed on back if self.options.lid_type == 'WoodHinge' or self.options.lid_type == 'SteelHinge' or self.options.lid_type == 'Coffin': if back_left_radius > 0 or back_right_radius > 0: inkex.errormsg('Error: real lid option is incompatible with rounded corners on back') exit() self.front_joint = 0 #No joint on front top self.back_joint = 0 #No joint on back top self.right_joint = 0 #No joint on right top self.left_joint = 0 #No joint on left top #As top edges are external, but without notches, just decrease height by thickness zbox -= thickness zlid -= thickness if self.options.lid_type == 'Coffin': if front_left_radius > 0 or front_right_radius > 0: inkex.errormsg('Error: coffin lid option is incompatible with rounded corners') exit() HasCoffinlid = True HasLid = False else: HasCoffinlid = False HasLid = True if self.options.lid_type == 'SteelHinge' or self.options.lid_type == 'Coffin': #Compute placement of hinges #First compute hinge width. Each hinge has 5 elements with thickness width whiche should be slighly spaced for the main box elements (3) hingeWidth = 5*thickness + 3*SteelHingeSpacing if ( hingeWidth > self.x_slot_size - 3 ): inkex.errormsg('Error: no space for hinge within slots, slots should be at least '+str(hingeWidth+3)+'mm wide') exit(1) #if the box is small with only one slot in x direction try with only one hinge if self.n_slot_x == 1 and self.x_slot_size < 2 * hingeWidth + 30: self.HingeList.append = (0, (self.x_slot_size - hingeWidth)/2.0, (self.x_slot_size - hingeWidth)/2.0) # One hinge, starting at the middle of slot 0 (the only one) elif self.n_slot_x == 2: #in this case place hinge in first and last slot. # Exact position depend on slot width, try to place hinge at about 1/3 of the slot HingePos = max(self.x_slot_size/3 - hingeWidth/2, 2) if HingePos < 8: HingePos = max(self.x_slot_size/2.5 - hingeWidth/2, 2) #1/3 is very close from start, so change to 1/2.5 self.HingeList.append((0, HingePos, HingePos)) self.HingeList.append((self.n_slot_x-1, self.x_slot_size - HingePos, (self.n_slot_x-1)*(self.x_slot_size+thickness) + (self.x_slot_size - HingePos - hingeWidth) )) elif self.n_slot_x <= 6: #in this case place hinge in first and last slot. # Exact position depend on slot width, try to place hinge at about 1/2 of the slot HingePos = (self.x_slot_size - hingeWidth)/2.0 self.HingeList.append((0, HingePos, HingePos)) self.HingeList.append((self.n_slot_x-1, self.x_slot_size - HingePos, (self.n_slot_x-1)*(self.x_slot_size+thickness) + (self.x_slot_size - HingePos - hingeWidth) )) else: #a lot of slots, place hinge in second and before last slot, at center of slots HingePos = (self.x_slot_size - hingeWidth)/2.0 self.HingeList.append((1, HingePos, self.x_slot_size + thickness + HingePos )) self.HingeList.append((self.n_slot_x-2, HingePos, (self.n_slot_x-2)*(self.x_slot_size+thickness) + (self.x_slot_size - HingePos - hingeWidth))) DebugMsg("Lid with steel hinge\n") DebugMsg("Hinge width="+str(hingeWidth)+", Hinge pos="+str(self.HingeList)+"\n") #Draw external faces which are planes, begin with top self.BuildTop(xbox, ybox, back_left_radius, back_right_radius, front_right_radius, front_left_radius) self.BuildBottom(xbox, ybox, back_left_radius, back_right_radius, front_right_radius, front_left_radius) ''' Draw sides, which could be rounded (with flex) For boxes with lid, draw also the lid, just above the side. There are 16 cases TL TR BR BL Flex Straight 0 0 0 0 NO ALL OK 0 0 0 1 Left → Front Back, Right OK 0 0 1 0 Front → Right Back, Left OK 0 0 1 1 Left → Front → Right Back OK 0 1 0 0 Right → Back Front, Left OK 0 1 0 1 Right → Back, Left → Front No OK 0 1 1 0 Front --> Right --> Back Left OK 0 1 1 1 Left → Front → Right → Back No OK 1 0 0 0 Back → Left Right, Front OK 1 0 0 1 Back → Left → Front Right OK 1 0 1 0 Back → Left, Front → Right No OK 1 0 1 1 Back → Left → Front → Right No OK 1 1 0 0 Right → Back → Left Front OK 1 1 0 1 Right → Back → Left → Front No OK 1 1 1 0 Front → Right → Back → Left No OK 1 1 1 1 All Flex No ''' FlexBandList = [] #empty list at init RightFace = None LeftFace = None ypos = -self.BoundingBox[3] yposface = ypos xpos = 0.0 LidFace = None if front_left_radius == 0 and front_right_radius == 0: if HasLid: DebugMsg("Draw font lid\n") LidFace = BoxFace('Lid_Front', CornerPoint((0,0), 0, 0, 0), self.x_joint, CornerPoint((xbox,0), 0, 0, 0), self.z_joint, CornerPoint((xbox,zlid), 0, 0, 0), self.front_joint, CornerPoint((0,zlid), 0, 0, 0), self.z_joint, self.group, [xpos, ypos]) #Draw face just below previous drawings LidFace.drawSimpleFace(True) self.UpdateBoundingBox(LidFace) #Now update bounding box, to place back face just below yposface = -self.BoundingBox[3] DebugMsg("\nStraight face for front\n") #No round, front is straight #Front is xbox * zbox, all corners are external in each direction Face = BoxFace('Front', CornerPoint((0,0), 0, 0, 0), self.front_joint, CornerPoint((xbox,0), 0, 0, 0), self.z_joint, CornerPoint((xbox,zbox), 0, 0, 0), self.x_joint, CornerPoint((0,zbox), 0, 0, 0), self.z_joint, self.group, [xpos, yposface]) #Draw face just below previous drawings Face.drawSimpleFace(True) xpos = -Face.BoundingBox[2]-2 self.UpdateBoundingBox(Face) #Now update bounding box elif front_left_radius == 0: #Rounded corner on Front right #Straight corner on Front/left, there is a flex band starting on front left if back_right_radius == 0: #Straight corner on Front / right, Flex on front --> right, BL to TR DebugMsg("\nFlex on front --> Right\n") FlexBand = ('Flex_Front_Right', 0, 1, #Draw Front then Right so first element is external and last internal (xbox, self.front_joint, front_right_radius, self.x_joint), #Then Front Notch Line and round corner r= front_right_radius #Then Right notch line withount rounded corner, the last parameter is used when WoodHinge to draw the top circle (ybox, self.right_joint, 0, self.y_joint, self.options.lid_type == 'WoodHinge')) FlexBandList.append(FlexBand) elif back_left_radius == 0: #Straight corner on back left, flex band is front + right + back DebugMsg("\nFlex on front --> right --> back\n") FlexBand = ('Flex_Front_Right_Back', 0, 0, #Draw Front then Right and Back so first element is external and last external (xbox, self.front_joint, front_right_radius, self.x_joint), #Then Front Notch Line and round corner r= front_right_radius (ybox, self.right_joint, back_right_radius, self.y_joint), #Then Right notch line and Back/Right rounded corner (xbox, self.back_joint, 0, self.x_joint)) #Then Back notch line withount rounded corner FlexBandList.append(FlexBand) else: #flex band is front + right + back + left DebugMsg("\nFlex on front --> right --> back --> left\n") FlexBand = ('Flex_Front_Right_Back_Left', 0, 1, #Draw Front then Right, Back and left so first element is external and last internal (xbox, self.front_joint, front_right_radius, self.x_joint), #Then Front Notch Line and round corner r= front_right_radius (ybox, self.right_joint, back_right_radius, self.y_joint), #Then Right notch line and Back/Right rounded corner (xbox, self.back_joint, back_left_radius, self.x_joint), #Then Back notch line with Back/Left rounded corner (ybox, self.left_joint, 0)) #At last, Left line without rounded corner FlexBandList.append(FlexBand) if back_left_radius == 0 and back_right_radius == 0: if HasLid: DebugMsg("Draw back lid\n") LidFace = BoxFace('Lid_Back', CornerPoint((0,0), 0, 0, 0), self.x_joint, CornerPoint((xbox,0), 0, 0, 0), self.z_joint, CornerPoint((xbox,zlid), 0, 0, 0), self.back_joint, CornerPoint((0,zlid), 0, 0, 0), self.z_joint, self.group, [xpos, ypos]) #Draw face just right previous drawings if self.options.lid_type == 'WoodHinge': LidFace.drawLidBackWoodHinge(True) else: #This is SteelHinge or Coffin LidFace.drawLidBackSteelHinge(self.HingeList, True) if yposface == ypos: self.UpdateBoundingBox(LidFace) #Now update bounding box, if not already done, to place back face just below yposface = -self.BoundingBox[3] #Back is xbox * zbox, all corners are external in each direction DebugMsg("\nStraight face for Back\n") if self.options.lid_type == 'Sliding': #In this case, not a simple face, so we use a specific function. Also, top line is internal in y and external in x Face = BoxFace('Back', CornerPoint((0,0), 0, 0, 1), self.back_joint, CornerPoint((xbox,0), 0, 0, 1), self.z_joint, CornerPoint((xbox,zbox), 0, 0, 0), self.x_joint, CornerPoint((0,zbox), 0, 0, 0), self.z_joint, self.group, [xpos, yposface]) #Draw face just right from previous one Face.drawExternalBackSlidingLid(True) elif self.options.lid_type == 'WoodHinge': #In this case, not a simple face, so we use a specific function. Face = BoxFace('Back', CornerPoint((0,0), 0, 0, 0), 0, CornerPoint((xbox,0), 0, 0, 0), #No joint here ! self.z_joint, CornerPoint((xbox,zbox), 0, 0, 0), self.x_joint, CornerPoint((0,zbox), 0, 0, 0), self.z_joint, self.group, [xpos, yposface]) #Draw face just right from previous one Face.drawExternalBackWoodHingeLid(True) elif self.options.lid_type == 'SteelHinge' or self.options.lid_type == 'Coffin': #In this case, not a simple face, so we use a specific function. Face = BoxFace('Back', CornerPoint((0,0), 0, 0, 0), 0, CornerPoint((xbox,0), 0, 0, 0), #No joint here ! self.z_joint, CornerPoint((xbox,zbox), 0, 0, 0), self.x_joint, CornerPoint((0,zbox), 0, 0, 0), self.z_joint, self.group, [xpos, yposface]) #Draw face just right from previous one Face.drawExternalBackSteelHingeLid(self.HingeList, True) else: Face = BoxFace('Back', CornerPoint((0,0), 0, 0, 0), self.back_joint, CornerPoint((xbox,0), 0, 0, 0), self.z_joint, CornerPoint((xbox,zbox), 0, 0, 0), self.x_joint, CornerPoint((0,zbox), 0, 0, 0), self.z_joint, self.group, [xpos, yposface]) #Draw face just right from previous one Face.drawSimpleFace(True) self.UpdateBoundingBox(Face) #Now update bounding box xpos = -Face.BoundingBox[2]-2 elif back_right_radius == 0: #Rounded corner on Back left #Straight corner on Back/right, there is a flex band starting on back right if front_left_radius == 0: #Straight corner on front / left, flex band is back + left DebugMsg("\nFlex on back --> left\n") FlexBand = ('Flex_Back_Left', 0, 1, #Draw Back then Left so first element is external and last internal (xbox, self.back_joint, back_left_radius, self.x_joint), #Back Notch Line and round corner r= front_right_radius (ybox, self.left_joint, 0, self.y_joint)) #Then Left notch line without rounded corner FlexBandList.append(FlexBand) elif front_right_radius == 0: #Straight corner on bottom right, flex band is back + left + front DebugMsg("\nFlex on back --> left --> front\n") FlexBand = ('Flex_Back_Left_Front', 0, 0, #Draw Back then Left then Front so first element is external and last External (xbox, self.back_joint, back_left_radius, self.x_joint), #Back Notch Line and round corner r= front_right_radius (ybox, self.left_joint, front_left_radius, self.y_joint), #Then Left notch line and Front/Left rounded corner (xbox, self.front_joint, 0, self.x_joint)) #At last, Front line without rounded corner FlexBandList.append(FlexBand) else: #flex band is back + left + front + right DebugMsg("\nFlex on back --> left --> front --> right\n") FlexBand = ('Flex_Back_Left_Front_Right', 0, 1, #Draw Back then Left then Front Then Right so first element is external and last Inetrnal (xbox, self.back_joint, back_left_radius, self.x_joint), #Back Notch Line and round corner r= front_right_radius (ybox, self.left_joint, front_left_radius, self.y_joint), #Then Left notch line and Front/Left rounded corner (xbox, self.front_joint, front_right_radius, self.x_joint), #Then Front line with Front/Right rounded corner (ybox, self.right_joint, 0, self.y_joint)) #At last Right line without rounded corner FlexBandList.append(FlexBand) if back_left_radius == 0 and front_left_radius == 0: if HasLid: DebugMsg("Draw left lid\n") LidFace = BoxFace('Lid_Left', CornerPoint((0,0), 0, 1, 0), self.y_joint, CornerPoint((ybox,0), 0, 1, 0), self.z_joint, CornerPoint((ybox,zlid), 0, 1, 0), self.left_joint, CornerPoint((0,zlid), 0, 1, 0), self.z_joint, self.group, [xpos, ypos]) #Draw face just right previous drawings if self.options.lid_type == 'WoodHinge': LidFace.drawLidSideWoodHinge(0, True) elif self.options.lid_type == 'SteelHinge': #This is SteelHinge LidFace.drawSimpleFace(True) # No round for left face # Left is ybox * zbox, corners are external in y but internal in x DebugMsg("\nStraight face for Left\n") if self.options.lid_type == 'Sliding': delta_yposface = 2*thickness + 2 else: delta_yposface = 0 LeftFace = BoxFace('Left', CornerPoint((0,0), 0, 1, 0, self.options.lid_type == 'WoodHinge'), self.left_joint, CornerPoint((ybox,0), 0, 1, 0), self.z_joint, CornerPoint((ybox,zbox), 0, 1, 0), self.y_joint, CornerPoint((0,zbox), 0, 1, 0), self.z_joint, self.group, [xpos, yposface-delta_yposface]) #Draw face just right from previous drawings LeftFace.drawSimpleFace(True) self.UpdateBoundingBox(LeftFace) #Now update bounding box if self.options.lid_type == 'Sliding': LeftFace.drawSideLineNotches(xpos, yposface) #Right face is straight xpos = -LeftFace.BoundingBox[2]-2 elif back_left_radius == 0: #Rounded corner on Front left #Straight corner on Back/left, there is a flex band starting on Back left if front_right_radius == 0: #Straight corner on Front / Right, flex band is Left + Front DebugMsg("\nFlex on Left --> Front\n") FlexBand = ('Flex_Left_Front', 1, 0, #Draw Left then Front so first element is internal and last external #Left Notch Line and round corner r= front_left_radius, last parameter used when WoodHing to draw top circles (ybox, self.left_joint, front_left_radius, self.y_joint, self.options.lid_type == 'WoodHinge'), (xbox, self.front_joint, 0, self.x_joint)) #Then Front notch line without rounded corner FlexBandList.append(FlexBand) elif back_right_radius == 0: #Straight corner on Back right, flex band is Left + Back + Right DebugMsg("\nFlex on Left --> Front --> Right\n") FlexBand = ('Flex_Left_Front_Right', 1, 1, #Draw Left then Front and Right so first element is internal and last internal #Left Notch Line and round corner r= front_left_radius, last parameter used when WoodHing to draw top circles (ybox, self.left_joint, front_left_radius, self.y_joint, self.options.lid_type == 'WoodHinge'), (xbox, self.front_joint, front_right_radius, self.x_joint), #Then Front notch line with Front/Right rounded corner (ybox, self.right_joint, 0, self.y_joint, self.options.lid_type == 'WoodHinge')) #And Right notch line without rounded corner FlexBandList.append(FlexBand) else: #flex band on Left --> front --> right --> Back DebugMsg("\nFlex on Left --> front --> right --> Back\n") FlexBand = ('Flex_Left_Front_Right_Back', 1, 0, #Draw Left then Front, Right and Back so first element is internal and last external (ybox, self.left_joint, front_left_radius, self.y_joint), #Left Notch Line and round corner r= front_left_radius (xbox, self.front_joint, front_right_radius, self.x_joint), #Then Front notch line with Front/Right rounded corner (ybox, self.right_joint, back_right_radius, self.y_joint), #And Right notch line with Back/Right rounded corner (xbox, self.back_joint, 0, self.x_joint)) FlexBandList.append(FlexBand) if back_right_radius == 0 and front_right_radius == 0: #Right is the same if HasLid: DebugMsg("Draw Right lid\n") LidFace = BoxFace('Lid_Right', CornerPoint((0,0), 0, 1, 0), self.y_joint, CornerPoint((ybox,0), 0, 1, 0), self.z_joint, CornerPoint((ybox,zlid), 0, 1, 0), self.right_joint, CornerPoint((0,zlid), 0, 1, 0), self.z_joint, self.group, [xpos, ypos]) #Draw face just right previous drawings if self.options.lid_type == 'WoodHinge': LidFace.drawLidSideWoodHinge(1, True) elif self.options.lid_type == 'SteelHinge': #This is SteelHinge LidFace.drawSimpleFace(True) # Right is ybox * zbox, corners are external in y but internal in x DebugMsg("\nStraight face for Right\n") if self.options.lid_type == 'Sliding': delta_yposface = 2*thickness + 2 else: delta_yposface = 0 RightFace = BoxFace('Right', CornerPoint((0,0), 0, 1, 0), self.right_joint, CornerPoint((ybox,0), 0, 1, 0, self.options.lid_type == 'WoodHinge'), self.z_joint, CornerPoint((ybox,zbox), 0, 1, 0), self.y_joint, CornerPoint((0,zbox), 0, 1, 0), self.z_joint, self.group, [xpos, yposface-delta_yposface]) #Draw face just below previous drawings RightFace.drawSimpleFace(True) if self.options.lid_type == 'Sliding': RightFace.drawSideLineNotches(xpos, yposface) #Right face is straight self.UpdateBoundingBox(RightFace) #Now update bounding box xpos = -RightFace.BoundingBox[2]-2 elif front_right_radius == 0: #Rounded corner on Back right #Straight corner on Front right if back_left_radius == 0: #Straight corner on top / left, flex band is Left + Back DebugMsg("\nFlex on Right --> Back\n") FlexBand = ( 'Flex_Right_Back', 1, 0, #Draw Right then Back so first element is internal and last external (ybox, self.right_joint, back_right_radius, self.y_joint), #Left Notch Line and round corner r= back_right_radius (xbox, self.back_joint, 0, self.x_joint)) #Then Back notch line without rounded corner FlexBandList.append(FlexBand) elif front_left_radius == 0: #Straight corner on Front left, flex band is Right --> Back --> Left DebugMsg("\nFlex on Right --> Back --> Left\n") FlexBand = ('Flex_Right_Back_Left', 1, 1, #Draw Right then Back and left so first element is internal and last internal (ybox, self.right_joint, back_right_radius, self.y_joint), #Left Notch Line and round corner r= back_right_radius (xbox, self.back_joint, back_left_radius, self.x_joint), #Then Back notch line with Back/Left rounded corner (ybox, self.left_joint, 0, self.y_joint)) #And left Notch line without rounded corner FlexBandList.append(FlexBand) else: #flex band on Left --> front --> right --> Back --> Front DebugMsg("\nFlex on Right --> Back --> Left --> Front\n") FlexBand = ('Flex_Right_Back_Left_Front', 1, 1, #Draw Right then Back and left so first element is internal and last internal (ybox, self.right_joint, back_right_radius, self.y_joint), #Left Notch Line and round corner r= back_right_radius (xbox, self.back_joint, back_left_radius, self.x_joint), #Then Back notch line with Back/Left rounded corner (ybox, self.left_joint, front_left_radius, self.y_joint), #Then left Notch line with Front/Left rounded corner (xbox, self.front_joint, 0, self.x_joint)) #And Front notch line without rounded corner FlexBandList.append(FlexBand) if front_right_radius > 0 and back_right_radius > 0 and back_left_radius > 0 and front_left_radius > 0: #Specific case, all corners are rounded FlexBand = ('Flex_All', 1, 1, #Draw flex all around the box with clips (xbox, self.back_joint, back_right_radius, self.x_joint), #(Half) Back Notch Line and round corner r= back_right_radius (ybox, self.right_joint, front_right_radius, self.y_joint), #Then Right notch line with Front/Right rounded corner (xbox, self.front_joint, front_left_radius, self.x_joint), #Then front notch line with Front/Left rounded corner (ybox, self.left_joint, back_left_radius, self.y_joint), #Then Laft notch line with Back/Left rounded corner (xbox, self.back_joint, back_right_radius, self.x_joint)) #And another back line, (half) Face = FlexFace(FlexBand, 0, zbox, self.z_joint, self.group, [xpos, ypos]) Face.drawRoundedFlexFace(True) self.UpdateBoundingBox(Face) #Now update bounding box else: for FlexBand in FlexBandList: if HasLid: FaceLid = FlexFace(FlexBand, 1, zlid, self.z_joint, self.group, [xpos, ypos]) FaceLid.drawFlexFace(True) if yposface == ypos: yposface = ypos - FaceLid.BoundingBox[3] - 2 Face = FlexFace(FlexBand, 0, zbox, self.z_joint, self.group, [xpos, yposface]) Face.drawFlexFace(True) xpos -= Face.BoundingBox[2] + 2 #if sliding top, generate specific elements to let the lid slide if self.options.lid_type == 'Sliding': if len(FlexBandList) > 0: #Case with flex #This code works because with sliding top, there is AT MOST one flex band. Face.drawSideLineNotches() self.UpdateBoundingBox(Face) #Now update bounding box ypos = -self.BoundingBox[3] xpos = 0.0 # If coffin draw the lid here if self.options.lid_type == 'Coffin': self.drawCoffinSide('Left', ybox, zlid+thickness, z_dome_lid, xpos, ypos, self.group) xpos -= ybox + 2*thickness + 2 self.drawCoffinSide('Right', ybox, zlid+thickness, z_dome_lid, xpos, ypos, self.group) xpos -= ybox + 2*thickness + 2 self.drawCoffinTop(xbox, ybox, zlid+thickness, z_dome_lid, xpos, ypos, self.group) ypos = -self.BoundingBox[3] xpos = 0.0 # Then draw internal walls # First Back and front # Rectangle with joints on sides, not on top and bottom # if self.InternalWalls_FB: DebugMsg("\nDrawing Internal Back\n") if self.InternalWalls_LR: left_joint = self.z_joint else: left_joint = 0 #Only draw joints if there is a left side ! #If rounded corner, shorten size by radius, if not by thickness if back_left_radius > 0: left_joint = 0 d1 = back_left_radius else: d1 = thickness if self.InternalWalls_LR: right_joint = self.z_joint else: right_joint = 0 #Only draw joints if there is a right side ! #If rounded corner, shorten size by radius, if not by thickness if back_right_radius > 0: right_joint = 0 d2 = back_right_radius else: d2 = thickness InternalBack = BoxFace('Int_Back', CornerPoint((0,0), 0, 0, 1), #First corner, external on X, internal on Y sides 0, CornerPoint((xbox-d1-d2,0), 0, 0, 1), right_joint, CornerPoint((xbox-d1-d2, zbox_internal_walls), 0, 0, 1), 0, CornerPoint((0,zbox_internal_walls), 0, 0, 1), left_joint, self.group, [xpos, ypos]) #Draw face just below previous drawings if self.options.lid_type == 'SteelHinge' or self.options.lid_type == 'Coffin': #Special case, should cut some spce for the hinge in the back, so add the last parameter InternalBack.drawFaceWithHoles(self.n_slot_x, self.x_slot_size, d1 - thickness, self.z_joint, True, self.HingeList) else: InternalBack.drawFaceWithHoles(self.n_slot_x, self.x_slot_size, d1 - thickness, self.z_joint, True) xpos = -InternalBack.BoundingBox[2]-2 if self.InternalWalls_LR: left_joint = self.z_joint else: left_joint = 0 #Only draw joints if there is a left side ! if front_left_radius > 0: left_joint = 0 d1 = front_left_radius else: d1 = thickness if self.InternalWalls_LR: right_joint = self.z_joint else: right_joint = 0 #Only draw joints if there is a right side ! if front_right_radius > 0: right_joint = 0 d2 = front_right_radius else: d2 = thickness DebugMsg("\nDrawing Internal Front\n") InternalFront = BoxFace('Int_Front', CornerPoint((0,0), 0, 0, 1), #First corner, external on X, internal on Y sides 0, CornerPoint((xbox-d1-d2,0), 0, 0, 1), right_joint, CornerPoint((xbox-d1-d2, zbox_internal_walls), 0, 0, 1), 0, CornerPoint((0,zbox_internal_walls), 0, 0, 1), left_joint, self.group, [xpos, ypos]) #Draw face just below previous drawings InternalFront.drawFaceWithHoles(self.n_slot_x, self.x_slot_size, d1 - thickness, self.z_joint, True) xpos = -InternalFront.BoundingBox[2]-2 # Then Left and right internal walls if needed. if self.InternalWalls_LR: DebugMsg("\nDrawing Internal Left\n") if self.InternalWalls_FB: left_joint = self.z_joint else: left_joint = 0 #Only draw joints if there is a left side ! if back_left_radius > 0: left_joint = 0 d1 = back_left_radius else: d1 = thickness if self.InternalWalls_FB: right_joint = self.z_joint else: right_joint = 0 #Only draw joints if there is a right side ! if front_left_radius > 0: right_joint = 0 d2 = front_left_radius else: d2 = thickness InternalLeft = BoxFace('Int_Left', CornerPoint((0,0), 0, 1, 1), #First corner, internal on both sides 0, CornerPoint((ybox-d1-d2,0), 0, 1, 1), right_joint, CornerPoint((ybox-d1-d2, zbox_internal_walls), 0, 1, 1), 0, CornerPoint((0,zbox_internal_walls), 0, 1, 1), left_joint, self.group, [xpos, ypos]) #Draw face just below previous drawings InternalLeft.drawFaceWithHoles(self.n_slot_y, self.y_slot_size, d1 - thickness, self.z_joint, True) xpos = -InternalLeft.BoundingBox[2]-2 if self.InternalWalls_FB: left_joint = self.z_joint else: left_joint = 0 #Only draw joints if there is a left side ! if front_right_radius > 0: left_joint = 0 d1 = front_right_radius else: d1 = thickness if self.InternalWalls_FB: right_joint = self.z_joint else: right_joint = 0 #Only draw joints if there is a right side ! if back_right_radius > 0: right_joint = 0 d2 = back_right_radius else: d2 = thickness DebugMsg("\nDrawing Internal Right\n") InternalRight = BoxFace('Int_Right', CornerPoint((0,0), 0, 1, 1), #First corner, internal on both sides 0, CornerPoint((ybox-d1-d2,0), 0, 1, 1), right_joint, CornerPoint((ybox-d1-d2, zbox_internal_walls), 0, 1, 1), 0, CornerPoint((0,zbox_internal_walls), 0, 1, 1), left_joint, self.group, [xpos, ypos]) #Draw face just below previous drawings InternalRight.drawFaceWithHoles(self.n_slot_y, self.y_slot_size, d1 - thickness, self.z_joint, True) self.UpdateBoundingBox(InternalRight) #Now update bounding box elif self.InternalWalls_FB: #Udate bounding box with front and back value self.UpdateBoundingBox(InternalFront) #Now update bounding box #Then internal walls #Columns first xpos = 0 ypos = -self.BoundingBox[3] for i in range(self.n_slot_x-1): self.drawColumWall(i, self.n_slot_y, self.y_slot_size, self.ListNotchColumns, ybox-2*thickness, zbox_internal_walls, xpos, ypos, self.group) xpos -= ybox + 2 #Next position for drawing #Then rows, nearly the same, but opening at the bottom edge xpos = 0 ypos -= zbox_internal_walls + thickness + 2 for i in range(self.n_slot_y-1): self.drawRowWall(i, self.n_slot_x, self.x_slot_size, self.ListNotchRows, xbox-2*thickness, zbox_internal_walls, xpos, ypos, self.group) xpos -= xbox + 2 #Next position for drawing # if self.options.lid_type == 'SteelHinge' or self.options.lid_type == 'Coffin': #the elements of the hinge HingeNum = 0 ypos = -self.BoundingBox[3] - 2 xpos = -2 for Hinge in self.HingeList: for i in range(5): self.drawSteelHingeElement(HingeNum*5+i, thickness, xpos, ypos, self.group) xpos -= 3.5*thickness + 2 HingeNum += 1 xpos -= 3 CloseDebugFile() if __name__ == '__main__': GenericBox().run()