mightyscape-1.2/extensions/fablabchemnitz/strip_line/strip_line.py

239 lines
9.2 KiB
Python
Raw Normal View History

2022-10-13 00:05:56 +02:00
#!/usr/bin/env python3
import math
import os
import inkex
from inkex.paths import Path
from geometry.Circle import Circle
from geometry.Vertex import Vertex
from geometry.Triangle import Triangle
from geometry.Plus import Plus
from geometry.Minus import Minus
from lxml import etree
ALL=".//"
def fixTo360(radian):
if radian < 0:
return math.pi * 2.0 + radian
return radian
def widenDir(start, end):
d21x = end.x - start.x;
d21y = end.y - start.y;
return fixTo360(-math.atan2(d21x, d21y));
def lineDir(start, end):
d21x = end.x - start.x;
d21y = end.y - start.y;
#inkex.errormsg("d21y "+str(d21y)+" d21x "+str(d21x)+" d21y/d21x"+str(d21y/d21x))
rad=math.atan2(d21y, d21x);
#inkex.errormsg(u"Line direction"+str(math.degrees(rad)))
return fixTo360(rad)
#radian<The assumption is that 0 will not come
def invert(radian):
return radian - math.pi
def fixWithin90(radian):
if math.fabs(radian) > math.pi / 2.0: #I want you to be +-90 (forward direction)
return invert(radian)
return radian
def fixOver90(radian):
if math.fabs(radian) < math.pi / 2.0:
return invert(radian)
return radian
def fixWithinAb180(radian):
if math.fabs(radian) < math.pi:
return radian
if radian < 0:
return math.pi * 2.0 + radian
return radian - math.pi * 2.0
def printRadian(fp, message, radian):
fp.write(message+":"+str(math.degrees(radian))+"\n")
def stripline(bone, line_width, log_directory, log_filename):
try:
with open(os.path.join(log_directory, log_filename),'w', encoding = 'utf-8') as fp:
i = 0;
segmentNum = len(bone) - 1;
elementNum = (segmentNum * 2 + 2) * 5
outVertexArray = []
#4 vertices per line segment+Extra amount added to the end point
vertexIdx = 0
#First apex
start = bone[0]
end = bone[1]
lastRad = 0
lastUsedRad = 0
radY = widenDir(start, end)
lineRad=lineDir(start, end)
fp.write(u"0th vertex")
printRadian(fp, u"lineRad", lineRad)
originalRad = radY
#Indicates the direction of bending
cornerDir = radY - lastRad
printRadian(fp, u"radY", radY)
diffRad = 0
printRadian(fp, u"diffRad:", diffRad)
printRadian(fp, u"radY-lineRad:", radY - lineRad)
printRadian(fp, u"sin(radY-lineRad:)", math.sin(radY - lineRad))
adjustedRad = radY
printRadian(fp, u"The first drawing angle", adjustedRad)
fp.write("\n")
direction=True
lastRad=radY
lastUsedRad = adjustedRad
LEFT = Vertex(line_width, 0)
RIGHT = Vertex(-line_width, 0)
#variable
v = Vertex(0,0)
v.set(LEFT)
v.rotate(adjustedRad)
flag = False #if radY < 0 else False
outVertexArray.append([start + v, flag])
v.set(RIGHT)
v.rotate(adjustedRad)
flag = True# if radY< 0 else False
outVertexArray.append([start + v, flag])
for i in range(1, segmentNum, 1):
start = bone[i]
end = bone[i + 1]
originalRad = widenDir(start,end)
radY = (originalRad + lastRad) * 0.5 #Values from 0 to 360 degrees
fp.write(str(i) + u"Th vertex")
diffRad = (originalRad - lastRad)
if math.fabs(math.fabs(diffRad) - math.pi) <= (45.0 * math.pi / 180.0):#To erase the pointed triangle when making a U-turn
printRadian(fp, u"Correction of U-turn point:diffRad", diffRad)
fp.write(u"Difference" + str(math.fabs(math.fabs(diffRad) - math.pi)))
radY = originalRad
printRadian(fp, u"radY:", radY)
printRadian(fp, u"diffRad:", diffRad)
printRadian(fp, u"radY - lineRad:", radY - lineRad)
printRadian(fp, u"sin(radY - lineRad:)", math.sin(radY - lineRad))
#Twist prevention
if math.sin(radY - lineRad) > 0:
radY = invert(radY)
lineRad = lineDir(start, end)
printRadian(fp, u"lineRad:", lineRad)
adjustedRad = radY
printRadian(fp, u"diffRad:", diffRad)
squareRad = lineDir(start, end)
#printRadian(u"squareRad",squareRad)
printRadian(fp, u"Drawing angle after conversion:", radY)
v.set(LEFT)
#1〜√2 I want you to be in the range
coef = (1 + 0.41421356237 * math.fabs(math.sin(diffRad * 0.5)))
fp.write("coef=" + str(coef))
v.x *= coef
v.rotate(adjustedRad)
flag = False
outVertexArray.append([start + v, flag])
v.set(RIGHT)
v.x *= coef
v.rotate(adjustedRad)
flag = True
outVertexArray.append([start + v , flag])
lastRad = originalRad
lastUsedRad = adjustedRad
fp.write("\n")
#The last round
fp.write(str(i) + u"Th vertex")
adjustedRad = originalRad
printRadian(fp, u"Last drawing angle:",originalRad)
v.set(LEFT)
v.rotate(adjustedRad)
flag = False # if originalRad< 0 else False
outVertexArray.append([end + v, flag])
v.set(RIGHT)
v.rotate(adjustedRad)
flag = True # if originalRad< 0 else False
outVertexArray.append([end + v, flag])
fp.close()
return outVertexArray
except IOError as error: # parent of IOError, OSError *and* WindowsError where available
inkex.utils.debug(str("Directory error. Please select another one and try again!"))
exit()
class StripLine(inkex.EffectExtension):
def add_arguments(self, pars):
pars.add_argument("--line_width", type = int, default = "10", help = "Line thickness")
pars.add_argument("--unit", default = "mm", help = "Width unit")
pars.add_argument("--log_directory", default = "~/", help = "Log directory")
pars.add_argument("--log_filename", default = "stripline.log", help = "Log file name")
def effect(self):
line_width = self.svg.unittouu(str(self.options.line_width) + self.options.unit)
# Get the main root element SVG
svg = self.document.getroot()
pathlist = svg.findall(ALL + "{" + inkex.NSS['svg'] + "}path")
for path in pathlist:
if path == None:
inkex.errormsg("Please write the path! !")
#Get vertex coordinates of path
vals = path.path.to_arrays()
bone = []
for cmd, vert in vals:
#Sometimes there is an empty, so countermeasures against it
#inkex.utils.debug("{},{}".format(cmd, vert))
if len(vert) != 0:
bone.append(Vertex(vert[0], vert[1]))
if len(bone) != 0:
outVertexArray = stripline(bone, line_width, self.options.log_directory, self.options.log_filename)
pointer = 0
for t in range(len(outVertexArray) - 2):
tri = Triangle(outVertexArray[pointer][0], outVertexArray[pointer+1][0], outVertexArray[pointer+2][0])
stripstr = tri.toSVG()
color2 = "blue"
if outVertexArray[pointer][1]:
color = "blue"
else:
color = "red"
pointer += 1
attributes = {"points": stripstr,
"style":"fill:" + color2 + ";stroke:" + color2 + ";stroke-width:" + str(line_width / 3), "fill-opacity": "0.5"}
pth = etree.Element("polygon", attributes)
svg.append(pth)
pointer = 0
#Draw a point indicating +-
for t in range(len(outVertexArray)):
if outVertexArray[pointer][1]:
point = Plus(outVertexArray[pointer][0].x, outVertexArray[pointer][0].y, line_width / 3)
color = "blue"
else:
point = Minus(outVertexArray[pointer][0].x, outVertexArray[pointer][0].y, line_width / 3)
color = "red"
if pointer == 0:
color = "#6f0018"#Dark red
point.appendToSVG(color, svg)
#svg.append(Circle.toSVG(outVertexArray[pointer][0].x,outVertexArray[pointer][0].y,line_width/3,color,0))
pointer += 1
pointer = 0
pathstr = "M "
for t in range(len(outVertexArray)):
pathstr += str(outVertexArray[pointer][0].x) + " "+str(outVertexArray[pointer][0].y) + " "
pointer += 1
att3 = {"d":pathstr,"r":"1","fill":"none","stroke-width":"1","stroke":"white"}
pt = etree.Element("path", att3)
if __name__ == '__main__':
StripLine().run()