239 lines
9.2 KiB
Python
239 lines
9.2 KiB
Python
|
#!/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()
|