different large refactorings (subdirectores, removed obsolete stuff) and
bug fixes
This commit is contained in:
@ -0,0 +1,820 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# sewing_patterns.py
|
||||
# Inkscape extension-Effects-Sewing Patterns
|
||||
# Copyright (C) 2010, 2011, 2012 Susan Spencer, Steve Conklin < www.taumeta.org >
|
||||
#
|
||||
# This program is free software:you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version. Attribution must be given in
|
||||
# all derived works.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see < http://www.gnu.org/licenses/ >
|
||||
|
||||
import subprocess, math, inkex, gettext
|
||||
from lxml import etree
|
||||
|
||||
def debug(errmsg, file = 'bell'):
|
||||
#audio files directory: /usr/share/sounds/ubuntu/stereo
|
||||
sounds(file)
|
||||
inkex.errormsg(gettext.gettext(errmsg))
|
||||
|
||||
def sounds(file):
|
||||
subprocess.call(['/usr/bin/canberra-gtk-play', '--id', file ])
|
||||
|
||||
#---
|
||||
class Point():
|
||||
'''Python object class to create variables that represent a named Cartesian point.
|
||||
Accepts id, x, y. Returns object with .id, .x, .y attributes.
|
||||
Example: a5 = Point('a5', 10.0, 15.32) returns variable a5 where a5.id = 'a5', a5.x = 10.0, a5.y = 15.32xt
|
||||
If called with no parameters the defaults are id = '', x = 0, y = 0
|
||||
The python object's id attribute enables it to be represented on the canvas as an svg object with the same id.
|
||||
'''
|
||||
def __init__(self, id = '', x = 0.0, y = 0.0): #if no parameters are passed in then the default values id = '', x = 0, y = 0 are used
|
||||
self.id = id
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.y = y
|
||||
|
||||
def patternPointXY(parent, id, x, y):
|
||||
'''Accepts parent, id, x, y. Returns object of class Point. Calls addPoint() & addText() to create a pattern point on canvas.'''
|
||||
# create python variable
|
||||
pnt = Point(id, x, y)
|
||||
# create svg circle red 5px radius
|
||||
addCircle(parent, id, x, y, radius = 5, fill = 'red', stroke = 'red', stroke_width = '1', reference = 'true')
|
||||
#draw label 8px right and 8px above circle
|
||||
addText(parent, id + '_text', x + 8, y-8, id, fontsize = '30', textalign = 'left', textanchor = 'left', reference = 'true') #the id is used for two things here: the text object's id and the text object's content.
|
||||
return pnt # return python variable for use in remainder of pattern
|
||||
|
||||
def patternPoint(parent, id, pnt):
|
||||
"""Wrapper for patternPointXY. Accepts a Point object instead of X & Y values."""
|
||||
return patternPointXY(parent, id, pnt.x, pnt.y)
|
||||
|
||||
def controlPointXY(parent, id, x, y):
|
||||
'''Accepts parent, id, x, y. Returns object of class Point. Calls addPoint() & addText() to create a pattern point with label on canvas.'''
|
||||
# create python variable
|
||||
pnt = Point(id, x, y)
|
||||
# create unfilled grey circle 5px radius
|
||||
addCircle(parent, id, x, y, radius = 5, fill = 'none', stroke = 'gray', stroke_width = '1', reference = 'true')
|
||||
#draw label 8px right and 8px above circle
|
||||
addText(parent, id + '_text', x + 8, y-8, id, fontsize = '30', textalign = 'left', textanchor = 'left', reference = 'true') #the id is used twice: the text object id and the text object content.
|
||||
return pnt # return python variable for use in remainder of pattern
|
||||
|
||||
def controlPoint(parent, id, pnt):
|
||||
"""Wrapper for controlPointXY. Accepts a Point object instead of X & Y values."""
|
||||
return controlPointXY(parent, id, pnt.x, pnt.y)
|
||||
|
||||
def pointList( * args):
|
||||
"""Accepts list of args. Returns array of args."""
|
||||
list = []
|
||||
for arg in args:
|
||||
list.append(arg)
|
||||
return list
|
||||
|
||||
#---tests for position---
|
||||
def isRight(pnt1, pnt2):
|
||||
'''returns 1 if pnt2 is to the right of pnt1'''
|
||||
right = 0
|
||||
if pnt2.x > pnt1.x:
|
||||
right = 1
|
||||
return right
|
||||
|
||||
def isLeft(pnt1, pnt2):
|
||||
'''returns 1 if pnt2 is to the left of pnt1'''
|
||||
left = 0
|
||||
if pnt2.x < pnt1.x:
|
||||
left = 1
|
||||
return left
|
||||
|
||||
def isAbove(pnt1, pnt2):
|
||||
'''returns 1 if pnt2 is above pnt1'''
|
||||
up = 0
|
||||
if pnt2.y < pnt1.y:
|
||||
up = 1
|
||||
return up
|
||||
|
||||
def isBelow(pnt1, pnt2):
|
||||
'''returns 1 if pnt2 is below pnt1'''
|
||||
down = 0
|
||||
if pnt2.y > pnt1.y:
|
||||
down = 1
|
||||
return down
|
||||
|
||||
def lowest(pnts):
|
||||
"""Accepts array pnts[]. Returns lowest point in array."""
|
||||
low = Point('', pnts[0].x, pnts[0].y)
|
||||
for item in pnts:
|
||||
if isBelow(low, item): #if item is below current low
|
||||
updatePoint('', low, item)
|
||||
return low
|
||||
|
||||
def highest(pnts):
|
||||
"""Accepts array pnts[]. Returns highest point in array."""
|
||||
high = Point('', pnts[0].x, pnts[0].y)
|
||||
for item in pnts:
|
||||
if isAbove(high, item): #if item is above current high
|
||||
updatePoint(high, item)
|
||||
return high
|
||||
|
||||
def leftmost(pnts):
|
||||
"""Accepts array pnts[]. Returns leftmost point in array."""
|
||||
left = Point('', pnts[0].x, pnts[0].y)
|
||||
for item in pnts:
|
||||
if isLeft(left, item):
|
||||
updatePoint(left, item)
|
||||
return left
|
||||
|
||||
def rightmost(pnts):
|
||||
"""Accepts array pnts[]. Returns rightmost point in array."""
|
||||
right = Point('', pnts[0].x, pnts[0].y)
|
||||
for item in pnts:
|
||||
if isRight(right, item):
|
||||
updatePoint(right, item)
|
||||
return right
|
||||
|
||||
#---functions to calculate points. These functions do not create SVG objects---
|
||||
|
||||
def updatePoint(p1, p2):
|
||||
'''Accepts p1 and p2 of class Point. Updates p1 with x & y values from p2'''
|
||||
p1.x = p2.x
|
||||
p1.y = p2.y
|
||||
return
|
||||
|
||||
def right(p1, n):
|
||||
'''Accepts point p1 and float n. Returns (x,y) to the right of p1 at (p1.x + n, p1.y)'''
|
||||
return Point('', p1.x + n, p1.y)
|
||||
|
||||
def left(p1, n):
|
||||
'''Accepts point p1 and float n. Returns p2 to the left of p1 at (p1.x-n, p1.y)'''
|
||||
return Point('', p1.x-n, p1.y)
|
||||
|
||||
def up(p1, n):
|
||||
'''Accepts point p1 and float n. Returns p2 above p1 at (p1.x, p1.y-n)'''
|
||||
return Point('', p1.x, p1.y-n)
|
||||
|
||||
def down(p1, n):
|
||||
'''Accepts point p1 and float n. Returns p2 below p1 at (p1.x, p1.y + n)'''
|
||||
return Point('', p1.x, p1.y + n)
|
||||
|
||||
def symmetric(p1, p2, type = 'vertical'):
|
||||
"""
|
||||
Accepts p1 and p2 of class Point, and optional type is either 'vertical' or 'horizontal with default 'vertical'.
|
||||
Returns p3 of class Point as "mirror image" of p1 relative to p2
|
||||
If type == 'vertical': pnt is on opposite side of vertical line x = p2.x from p1
|
||||
If type == 'horizontal': pnt is on opposite side of horizontal line y = p2.y from p1
|
||||
"""
|
||||
p3 = Point()
|
||||
dx = p2.x - p1.x
|
||||
dy = p2.y - p1.y
|
||||
if (type == 'vertical'):
|
||||
p3.x = p2.x + dx
|
||||
p3.y = p1.y
|
||||
elif (type == 'horizontal'):
|
||||
p3.x = p1.x
|
||||
p3.y = p2.y + dy
|
||||
return p3
|
||||
|
||||
def polar(p1, length, angle):
|
||||
'''
|
||||
Adapted from http://www.teacherschoice.com.au/maths_library/coordinates/polar_-_rectangular_conversion.htm
|
||||
Accepts p1 as type Point, length as float, angle as float. angle is in radians
|
||||
Returns p2 as type Point, calculated at length and angle from p1,
|
||||
Angles start at position 3:00 and move clockwise due to y increasing downwards on Cairo Canvas
|
||||
'''
|
||||
id = ''
|
||||
r = length
|
||||
x = p1.x + (r * math.cos(angle))
|
||||
y = p1.y + (r * math.sin(angle))
|
||||
p2 = Point(id, x, y)
|
||||
return p2
|
||||
|
||||
def midPoint(p1, p2, n = 0.5):
|
||||
'''Accepts points p1 & p2, and n where 0 < n < 1. Returns point p3 as midpoint b/w p1 & p2'''
|
||||
p3 = Point('', (p1.x + p2.x) * n, (p1.y + p2.y) * n)
|
||||
return p3
|
||||
|
||||
|
||||
#---measurements
|
||||
def distance(p1, p2):
|
||||
'''Accepts two points p1 & p2. Returns the distance between p1 & p2.'''
|
||||
return ( ((p2.x-p1.x) ** 2) + ((p2.y-p1.y) ** 2) ) ** 0.5
|
||||
|
||||
def angleOfDegree(degree):
|
||||
'''Accepts degree. Returns radians.'''
|
||||
return degree * math.pi/180.0
|
||||
|
||||
def angleOfLine(p1, p2):
|
||||
""" Accepts points p1 & p2. Returns the angle of the vector between them. Uses atan2."""
|
||||
return math.atan2(p2.y-p1.y, p2.x-p1.x)
|
||||
|
||||
def angleOfVector(p1, v, p2):
|
||||
'''Accepts three points o1, v, and p2. Returns radians of the angle formed between the three points.'''
|
||||
return abs(angleOfLine(v, p1)-angleOfLine(v, p2))
|
||||
|
||||
def slopeOfLine(p1, p2):
|
||||
""" Accepts two point objects and returns the slope """
|
||||
if ((p2.x-p1.x) != 0):
|
||||
m = (p2.y-p1.y)/(p2.x-p1.x)
|
||||
else:
|
||||
#TODO: better error handling here
|
||||
debug('Vertical Line in slopeOfLine')
|
||||
m = None
|
||||
return m
|
||||
|
||||
def slopeOfAngle(radians):
|
||||
'''
|
||||
Accepts angle (radians)
|
||||
Returns the slope as tangent radians
|
||||
'''
|
||||
#get tangent of radians
|
||||
return math.tan(radians)
|
||||
|
||||
#---intersections & extensions
|
||||
|
||||
def extendLine(p1, p2, length, rotation=0):
|
||||
"""
|
||||
Accepts two directed points of a line, and a length to extend the line
|
||||
Finds point along line at length from p2 in direction p1->p2
|
||||
"""
|
||||
return onLineAtLength(p2, p1, -length)
|
||||
|
||||
def onLineAtLength(p1, p2, length, rotation=0):
|
||||
"""
|
||||
Accepts points p1 and p2, distance, and an optional rotation angle.
|
||||
Returns coordinate pair on the line at length measured from p1 towards p2
|
||||
If length is negative, will return a coordinate pair at length measured
|
||||
from p1 in opposite direction from p2.
|
||||
The result is optionally rotated about the first point by the rotation angle in degrees
|
||||
"""
|
||||
lineangle = angleOfLine(p1, p2)
|
||||
angle = lineangle + rotation * (math.pi/180)
|
||||
x = (length * math.cos(angle)) + p1.x
|
||||
y = (length * math.sin(angle)) + p1.y
|
||||
return Point('', x, y)
|
||||
|
||||
def onLineAtX(p1, p2, x):
|
||||
#on line p1-p2, given x find y
|
||||
if (p1.x == p2.x):# vertical line
|
||||
raise ValueError('Points form a vertical line, infinite answers possible')
|
||||
return None
|
||||
else:
|
||||
m = (p2.y - p1.y)/(p2.x - p1.x)
|
||||
b = p2.y - (m * p2.x)
|
||||
return Point('', x, (m * x) + b)
|
||||
|
||||
def onLineAtY(p1, p2, y):
|
||||
#on line p1-p2, find x given y
|
||||
if (p1.y == p2.y): #if horizontal line
|
||||
raise ValueError('Points form a horizontal line, infinite answers possible')
|
||||
return None
|
||||
elif (p1.x == p2.x): # if vertical line
|
||||
return Point('', p1.x, y)
|
||||
else:
|
||||
m = (p1.y - p2.y)/(p1.x - p2.x)
|
||||
b = p2.y - (m * p2.x)
|
||||
return Point('', (y - b)/m, y)
|
||||
|
||||
def intersectLines(p1, p2, p3, p4):
|
||||
"""
|
||||
Find intersection between two lines. Accepts p1, p2, p3, p4 as class Point. Returns p5 as class Point
|
||||
Intersection does not have to be within the supplied line segments
|
||||
"""
|
||||
x, y = 0.0, 0.0
|
||||
if (p1.x == p2.x): #if 1st line vertical, use slope of 2nd line
|
||||
x = p1.x
|
||||
m2 = slopeOfLine(p3, p4)
|
||||
b2 = p3.y-m2 * p3.x
|
||||
y = m2 * x + b2
|
||||
elif (p3.x == p4.x): #if 2nd line vertical, use slope of 1st line
|
||||
x = p3.x
|
||||
m1 = slopeOfLine(p1, p2)
|
||||
b1 = p1.y-m1 * p1.x
|
||||
y = m1 * x + b1
|
||||
else: #otherwise use ratio of difference between points
|
||||
m1 = (p2.y-p1.y)/(p2.x-p1.x)
|
||||
m2 = (p4.y-p3.y)/(p4.x-p3.x)
|
||||
b1 = p1.y-m1 * p1.x
|
||||
b2 = p3.y-m2 * p3.x
|
||||
#if (abs(b1-b2) < 0.01) and (m1 == m2):
|
||||
#x = p1.x
|
||||
#else:
|
||||
#x = (b2-b1)/(m1-m2)
|
||||
if (m1 == m2):
|
||||
#TODO: better error handling here
|
||||
debug(' ** ** * Parallel lines in intersectLines ** ** * ')
|
||||
else:
|
||||
x = (b2-b1)/(m1-m2)
|
||||
y = (m1 * x) + b1 # arbitrary choice, could have used m2 & b2
|
||||
p5 = Point("", x, y)
|
||||
return p5
|
||||
|
||||
def intersectLineRay(P1, P2, R1, angle):
|
||||
'''
|
||||
Accepts two points defining a line, and a point and angle defining a ray.
|
||||
Returns point where they intersect.
|
||||
'''
|
||||
#define a line R1-R2 by finding point R2 along ray 25 pixels (arbitary) from R1
|
||||
R2 = polar(R1, 1 * 25, angle)
|
||||
pnt = intersectLines(P1, P2, R1, R2)
|
||||
return pnt
|
||||
|
||||
def onRayAtX(P, angle, x):
|
||||
'''
|
||||
Accepts point P and angle of line.
|
||||
Returns point along ray at x
|
||||
'''
|
||||
#convert degrees to slope
|
||||
m = slopeOfAngle(angle)
|
||||
#solve for y
|
||||
#(P.y - y)/(P.x - x) = m
|
||||
y = P.y - m * (P.x - x)
|
||||
return Point('', x, y)
|
||||
|
||||
def onRayAtY(P, angle, y):
|
||||
'''
|
||||
Accepts point P and angle of line.
|
||||
Returns point along ray at y
|
||||
'''
|
||||
#convert degrees to slope
|
||||
m = slopeOfAngle(angle)
|
||||
#solve for x
|
||||
#(P.y - y)/(P.x - x) = m
|
||||
x = P.x - (P.y - y)/m
|
||||
return Point('', x, y)
|
||||
|
||||
def intersectCircles(C1, r1, C2, r2):
|
||||
"""
|
||||
Accepts C1, r1, C2, r2 where C1 & C2 are center points of each circle, and r1 & r2 are the radius of each circle.
|
||||
Returns an array of points of intersection.
|
||||
"""
|
||||
x0, y0 = C1.x, C1.y
|
||||
x1, y1 = C2.x, C2.y
|
||||
d = distance(C1, C2) # distance b/w circle centers
|
||||
dx, dy = (x1-x0), (y1-y0) # negate y b/c canvas increases top to bottom
|
||||
pnts = []
|
||||
if (d == 0):
|
||||
#intersections = 0
|
||||
#TODO: better error handling here
|
||||
debug('center of both circles are the same in intersectCircles()')
|
||||
debug('C1 = ', C1.x, C1.y, 'radius1 = ', r1)
|
||||
debug('C2 = ', C2.x, C2.y, 'radius1 = ', r2)
|
||||
return
|
||||
elif (d < abs(r1-r2)):
|
||||
#intersections = 0
|
||||
#TODO: better error handling here
|
||||
debug('one circle is within the other in intersectCircles()')
|
||||
debug('d = ', d)
|
||||
debug('r1 - r2 = ', (r1-r2))
|
||||
debug('d < abs(r1 - r2) ?', (d < abs(r1-r2)))
|
||||
debug('C1 = ', C1.x, C1.y, 'radius1 = ', r1)
|
||||
debug('C2 = ', C2.x, C2.y, 'radius1 = ', r2)
|
||||
return
|
||||
elif (d > (r1 + r2)):
|
||||
#intersections = 0
|
||||
#TODO: better error handling here
|
||||
debug('circles do not intersect in intersectCircles()')
|
||||
debug('d = ', d)
|
||||
debug('r1 + r2 = ', (r1 + r2))
|
||||
debug('d > abs(r1 + r2) ?', (d > abs(r1 + r2)))
|
||||
debug('C1 = ', C1.x, C1.y, 'radius1 = ', r1)
|
||||
debug('C2 = ', C2.x, C2.y, 'radius1 = ', r2)
|
||||
# TODO:possible kluge -check if this is acceptable using a small margin of error between r1 & r2 (0.5 * CM)?:
|
||||
#r2 = d-r1
|
||||
return
|
||||
else:
|
||||
#intersections = 2 or intersections = 1
|
||||
a = ((r1 * r1)-(r2 * r2) + (d * d))/(2.0 * d)
|
||||
x2 = x0 + (dx * a/d)
|
||||
y2 = y0 + (dy * a/d)
|
||||
h = math.sqrt((r1 * r1)-(a * a))
|
||||
rx = -dy * (h/d)
|
||||
ry = dx * (h/d)
|
||||
X1 = x2 + rx
|
||||
Y1 = y2 + ry
|
||||
X2 = x2-rx
|
||||
Y2 = y2-ry
|
||||
pnts.append(Point("", X1, Y1))
|
||||
pnts.append(Point("", X2, Y2))
|
||||
return pnts
|
||||
|
||||
def onCircleAtX(C, r, x):
|
||||
"""
|
||||
Finds points on circle where p.x=x
|
||||
Accepts C as an object of class Point or xy coords for the center of the circle,
|
||||
r as the radius, and x to find the points on the circle
|
||||
Returns an array P
|
||||
Based on paulbourke.net/geometry/sphereline/sphere_line_intersection.py
|
||||
"""
|
||||
#print 'C =', C.x, C.y
|
||||
#print 'r =', r
|
||||
#print 'x =', x
|
||||
P = []
|
||||
if abs(x - C.x) > r:
|
||||
print('abs(x - C.x) > r ...', abs(x - C.x), ' > ', r)
|
||||
print('x is outside radius of circle in intersections.onCircleAtX()')
|
||||
else:
|
||||
translated_x = x - C.x # center of translated circle is (0, 0) as translated_x is the difference b/w C.x & x
|
||||
translated_y1 = abs(math.sqrt(r**2 - translated_x**2))
|
||||
translated_y2 = -(translated_y1)
|
||||
y1 = translated_y1 + C.y # translate back to C.y
|
||||
y2 = translated_y2 + C.y # translate back to C.y
|
||||
P.append(Point('', x, y1))
|
||||
P.append(Point('', x, y2))
|
||||
return P
|
||||
|
||||
def onCircleAtY(C, r, y):
|
||||
"""
|
||||
Finds points one or two points on circle where P.y=y
|
||||
Accepts C of class Point or coords as circle center, r of type float as radius, and y of type float)
|
||||
Returns an array P
|
||||
Based on paulbourke.net/geometry/sphereline/sphere_line_intersection.py
|
||||
"""
|
||||
#print('C =', C.x, C.y)
|
||||
#print('r =', r)
|
||||
#print('x = ', y))
|
||||
P = []
|
||||
if abs(y - C.y) > r:
|
||||
print('abs(y - C.y) > r ...', abs(y - C.y), ' > ', r)
|
||||
print('y is outside radius in onCircleAtY() -- no intersection')
|
||||
else:
|
||||
translated_y = y - C.y
|
||||
translated_x1 = abs(math.sqrt(r**2 - translated_y**2))
|
||||
translated_x2 = -translated_x1
|
||||
x1 = translated_x1 + C.x
|
||||
x2 = translated_x2 + C.x
|
||||
P.append(Point('', x1, y))
|
||||
P.append(Point('', x2, y))
|
||||
return P
|
||||
|
||||
def intersectLineCircle(P1, P2, C, r):
|
||||
"""
|
||||
Finds intersection of a line segment and a circle.
|
||||
Accepts circle center point object C, radius r, and two line point objects P1 & P2
|
||||
Returns an array P with up to two coordinate pairs as P.intersections P[0] & P[1]
|
||||
Based on paulbourke.net/geometry/sphereline/sphere_line_intersection.py
|
||||
"""
|
||||
|
||||
#print('C =', C.x, C.y)
|
||||
#print('P1 =', P1.x, P1.y)
|
||||
#print('P2 =', P2.x, P2.y)
|
||||
#print('r =', r, 'pts', ', ', r / CM, 'cm')
|
||||
|
||||
p1, p2 = Point('', '', ''), Point('', '', '')
|
||||
P = []
|
||||
|
||||
if P1.x == P2.x: #vertical line
|
||||
if abs(P1.x - C.x) > r:
|
||||
print('no intersections for vertical line P1', P1.name, P1.x, P1.y, ', P2', P2.name, P2.x, P2.y, ', and Circle', C.name, C.x, C.y, ', radius', r)
|
||||
return None
|
||||
else:
|
||||
#print('Vertical line')
|
||||
p1.x = P1.x
|
||||
p2.x = P1.x
|
||||
p1.y = C.y + sqrt(r**2 - (P1.x - C.x)**2)
|
||||
p2.y = C.y - sqrt(r**2 - (P1.x - C.x)**2)
|
||||
elif P1.y == P2.y: #horizontal line
|
||||
if abs(P1.y-C.y) > r:
|
||||
print('no intersections for horizontal line P1', P1.name, P1.x, P1.y, ', P2', P2.name, P2.x, P2.y, ', and Circle', C.name, C.x, C.y, ', radius', r)
|
||||
return None
|
||||
else:
|
||||
#print('Horizontal line')
|
||||
p1.y = P1.y
|
||||
p2.y = P1.y
|
||||
p1.x = C.x + sqrt(r**2 - (P1.y - C.y)**2)
|
||||
p2.x = C.x - sqrt(r**2 - (P1.y - C.y)**2)
|
||||
else:
|
||||
a = (P2.x - P1.x)**2 + (P2.y - P1.y)**2
|
||||
b = 2.0 * ((P2.x - P1.x) * (P1.x - C.x)) + ((P2.y - P1.y) * (P1.y - C.y))
|
||||
c = C.x**2 + C.y**2 + P1.x**2 + P1.y**2 - (2.0 * (C.x * P1.x + C.y * P1.y)) - r**2
|
||||
i = b**2 - 4.0 * a * c
|
||||
if i < 0.0:
|
||||
print('no intersections b/w line', P1.name, P1.x, P1.y, '--', P2.name, P2.x, P2.y, 'and Circle', C.name, C.x, C.y, 'with radius', r)
|
||||
return None
|
||||
elif i == 0.0:
|
||||
# one intersection
|
||||
#print('one intersection')
|
||||
mu = -b/(2.0 * a)
|
||||
p1.x, p1.y = P1.x + mu * (P2.x - P1.x), P1.y + mu * (P2.y - P1.y)
|
||||
elif i > 0.0:
|
||||
# two intersections
|
||||
#print('two intersections')
|
||||
# first intersection
|
||||
mu1 = (-b + math.sqrt(i)) / (2.0*a)
|
||||
p1.x, p1.y = P1.x + mu1 * (P2.x - P1.x), P1.y + mu1 * (P2.y - P1.y)
|
||||
# second intersection
|
||||
mu2 = (-b - math.sqrt(i)) / (2.0*a)
|
||||
p2.x, p2.y = P1.x + mu2 * (P2.x - P1.x), P1.y + mu2 * (P2.y - P1.y)
|
||||
P.append(p1)
|
||||
P.append(p2)
|
||||
return P
|
||||
|
||||
def intersectChordCircle(C, r, P, chord_length):
|
||||
''' Accepts center of circle, radius of circle, a point on the circle, and chord length.
|
||||
Returns an array of two points on the circle at chord_length distance away from original point'''
|
||||
d = chord_length
|
||||
# point on circle given chordlength & starting point = 2 * asin(d/2r)
|
||||
d_div_2r = d/(2.0 * r)
|
||||
angle = 2 * asin(d_div_2r)
|
||||
pnts = []
|
||||
pnts.append(polar(C, r, angle))
|
||||
pnts.append(polar(C, r, - angle))
|
||||
return pnts
|
||||
|
||||
def intersectLineCurve(P1, P2, curve, n = 100):
|
||||
'''
|
||||
Accepts two points of a line P1 & P2, and an array of connected bezier curves [P11, C11, C12, P12, C21, C22, P22, C31, C32, P32, ...]
|
||||
Returns an array points_found[] of point objects where line intersected with the curve, and tangents_found[] of tangent angle at that point
|
||||
'''
|
||||
# get polar equation for line for P1-P2
|
||||
# point furthest away from 1st point in curve[] is the fixed point & sets the direction of the angle towards the curve
|
||||
#if distance(P1, curve[0]) > = distance(P2, curve[0] ):
|
||||
# fixed_pnt = P1
|
||||
# angle = angleOfLine(P1, P2)
|
||||
#else:
|
||||
# fixed_pnt = P2
|
||||
# angle = angleOfLine(P2, P1)
|
||||
#debug('intersectLineCurve...')
|
||||
#debug('....P1 = ' + P1.id + ' ' + str(P1.x) + ', ' + str(P1.y))
|
||||
#debug('....P2 = ' + P2.id + ' ' + str(P2.x) + ', ' + str(P2.y))
|
||||
#for pnt in curve:
|
||||
#debug( '....curve = ' + pnt.id + ' ' + str(pnt.x) + ', ' + str(pnt.y))
|
||||
fixed_pnt = P1
|
||||
angle = angleOfLine(P1, P2)
|
||||
intersections = 0
|
||||
points_found = []
|
||||
tangents_found = []
|
||||
pnt = Point()
|
||||
j = 0
|
||||
while j <= len(curve) -4: # for each bezier curve in curveArray
|
||||
intersection_estimate = intersectLines(P1, P2, curve[j], curve[j + 3]) # is there an intersection?
|
||||
if intersection_estimate != None or intersection_estimate != '':
|
||||
interpolatedPoints = interpolateCurve(curve[j], curve[j + 1], curve[j + 2], curve[j + 3], n) #interpolate this bezier curve, n = 100
|
||||
k = 0
|
||||
while k < len(interpolatedPoints)-1:
|
||||
length = distance(fixed_pnt, interpolatedPoints[k])
|
||||
pnt_on_line = polar(fixed_pnt, length, angle)
|
||||
range = distance(interpolatedPoints[k], interpolatedPoints[k + 1]) # TODO:improve margin of error
|
||||
length = distance(pnt_on_line, interpolatedPoints[k])
|
||||
#debug(str(k) + 'pntOnCurve = ' + \
|
||||
# str(interpolatedPoints[k].x) + ', ' + str(interpolatedPoints[k].y) + \
|
||||
# 'intersectLineAtLength = ' + str(pnt_on_line.x) + ', ' + str( pnt_on_line.y)\
|
||||
# + 'length = ' + str(length) + 'range = ' + str(range))
|
||||
if ( length <= range):
|
||||
#debug('its close enough!')
|
||||
if k > 1:
|
||||
if (interpolatedPoints[k-1] not in points_found) and (interpolatedPoints[k-2] not in points_found):
|
||||
points_found.append(interpolatedPoints[k])
|
||||
tangents_found.append(angleOfLine(interpolatedPoints[k-1], interpolatedPoints[k + 1]))
|
||||
intersections += 1
|
||||
elif k == 1:
|
||||
if (curve[0] not in intersections):
|
||||
points_found.append(interpolatedPoints[1])
|
||||
tangents_found.append(angleOfLine(curve[0], interpolatedPoints[2]))
|
||||
intersections += 1
|
||||
else:
|
||||
intersections.append(curve[0])
|
||||
tangents_found.append(angleOfLine(curve[0], curve[1]))
|
||||
k += 1
|
||||
j += 3 # skip j up to P3 of the current curve to be used as P0 start of next curve
|
||||
if intersections == 0:
|
||||
#TODO: better error handling here
|
||||
debug('no intersections found in intersectLineCurve(' + P1.id + ', ' + P2.id + ' and curve')
|
||||
#return points_found, tangents_found
|
||||
return points_found
|
||||
|
||||
def interpolateCurve(P0, C1, C2, P1, t = 100):
|
||||
'''
|
||||
Accepts curve points P0, C1, C2, P1 & number of interpolations t
|
||||
Returns array of interpolated points of class Point
|
||||
Adapted from http://www.planetclegg.com/projects/WarpingTextToSplines.htm
|
||||
'''
|
||||
# calculate coefficients for two knot points P0 & P1 ; C1 & C2 are the controlpoints.
|
||||
# x coefficients
|
||||
A = P1.x-(3 * C2.x) + (3 * C1.x)-P0.x
|
||||
B = (3 * C2.x)-(6 * C1.x) + (3 * P0.x)
|
||||
C = (3 * C1.x)-(3 * P0.x)
|
||||
D = P0.x
|
||||
# y coefficients
|
||||
E = P1.y-(3 * C2.y) + (3 * C1.y)-P0.y
|
||||
F = (3 * C2.y)-(6 * C1.y) + (3 * P0.y)
|
||||
G = (3 * C1.y)-(3 * P0.y)
|
||||
H = P0.y
|
||||
# calculate interpolated points
|
||||
interpolatedPoints = []
|
||||
maxPoint = float(t)
|
||||
i = 0
|
||||
while ( i <= t):
|
||||
j = i/maxPoint # j can't be an integer, i/t is an integer..always 0.
|
||||
x = A * (j ** 3) + B * (j ** 2) + C * j + D
|
||||
y = E * (j ** 3) + F * (j ** 2) + G * j + H
|
||||
interpolatedPoints.append(Point('', x, y))
|
||||
i += 1
|
||||
return interpolatedPoints
|
||||
|
||||
#---rotations
|
||||
def slashAndSpread(pivot, angle, *args):
|
||||
"""
|
||||
Accepts pivot point, angle of rotation, and the points to be rotated.
|
||||
Accepts positive & negative angles.
|
||||
"""
|
||||
if (angle == 0.0):
|
||||
print('Angle = 0 -- Slash and Spread not possible')
|
||||
else:
|
||||
list = []
|
||||
for arg in args:
|
||||
list.append(arg)
|
||||
i = 0
|
||||
for pnt in list:
|
||||
length = distance(pivot, pnt)
|
||||
rotated_pnt = polar(pivot, length, angleOfLine(pivot, pnt) + angle) # if angle > 0 spread clockwise. if angle < 0 spread counterclockwise
|
||||
updatePoint(pnt, rotated_pnt)
|
||||
return
|
||||
|
||||
#---darts
|
||||
def foldDart(dart, inside_pnt, seam_allowance):
|
||||
'''
|
||||
Accepts dart, and the nearest point in the direction dart will be folded
|
||||
Returns dart.m, dart.oc, dart.ic, dart.angle
|
||||
dart.m = middle dart leg at seamline (to be included in seamline path)
|
||||
dart.oc = inside dart leg at cuttingline (to be included in dartline path)
|
||||
dart.oc = outside dart leg at cuttingline (to be included in dartline path)
|
||||
'''
|
||||
mid_pnt = midPoint(dart.i, dart.o)
|
||||
dart_length = distance(dart, dart.i)
|
||||
i_angle = angleOfLine(dart, dart.i)
|
||||
c_angle = angleOfLine(dart, inside_pnt)
|
||||
dart_angle = abs(angleOfVector(dart.i, dart, dart.o))
|
||||
dart_half_angle = dart_angle/2.0
|
||||
|
||||
#determine which direction the dart will be folded
|
||||
#if ((dart.i.x > dart.x) and (dart.i.y > dart.y)) or ((dart.i.x < dart.x) and (dart.i.y > dart.y)):
|
||||
#x & y vectors not the same sign
|
||||
#dart_half_angle = -dart_half_angle
|
||||
if i_angle > c_angle:
|
||||
dart_half_angle = -dart_half_angle
|
||||
elif dart_angle < c_angle:
|
||||
#dart straddles 0 angle
|
||||
dart_half_angle = -dart_half_angle
|
||||
|
||||
fold_angle = i_angle + dart_half_angle
|
||||
fold_pnt = intersectLineRay(dart.i, inside_pnt, dart, fold_angle)
|
||||
dart.m = onLineAtLength(dart, mid_pnt, distance(dart, fold_pnt)) #dart midpoint at seamline
|
||||
dart.oc = polar(dart, distance(dart, dart.o) + seam_allowance, angleOfLine(dart, dart.o)) #dart outside leg at cuttingline
|
||||
dart.ic = extendLine(dart, dart.i, seam_allowance) #dart inside leg at cuttingline
|
||||
#create or update dart.angles
|
||||
dart.angle = angleOfVector(dart.i, dart, dart.o)
|
||||
return
|
||||
|
||||
#---base, pattern & patternpiece groups
|
||||
def base(parent, id):
|
||||
'''Create a base group to contain all patterns, parent should be the document'''
|
||||
newBase = addGroup(parent, id)
|
||||
newBase.set(inkex.addNS('label', 'inkscape'), id)
|
||||
newBase.set(inkex.addNS('groupmode', 'inkscape'), 'layer')
|
||||
return newBase
|
||||
|
||||
def pattern(parent, id):
|
||||
'''Create a pattern group to hold a single pattern, parent should be the base group'''
|
||||
newPattern = addGroup(parent, id)
|
||||
newPattern.set(inkex.addNS('label', 'inkscape'), id)
|
||||
newPattern.set(inkex.addNS('groupmode', 'inkscape'), 'layer')
|
||||
return newPattern
|
||||
|
||||
def patternPiece(parent, id, name, fabric = 2, interfacing = 0, lining = 0):
|
||||
'''Create a pattern piece group to hold a single pattern piece, parent should be a pattern group'''
|
||||
newPatternPiece = addGroup(parent, id)
|
||||
newPatternPiece.set(inkex.addNS('label', 'inkscape'), name)
|
||||
newPatternPiece.set(inkex.addNS('groupmode', 'inkscape'), 'layer')
|
||||
return newPatternPiece
|
||||
|
||||
#---svg
|
||||
|
||||
def addCircle(parent, id, x, y, radius = 5, fill = 'red', stroke = 'red', stroke_width = '1', reference = 'false'):
|
||||
'''create & write a circle to canvas & set it's attributes'''
|
||||
circ = etree.SubElement(parent, inkex.addNS('circle', 'svg'))
|
||||
circ.set('id', id)
|
||||
circ.set('cx', str(x))
|
||||
circ.set('cy', str(y))
|
||||
circ.set('r', str(radius))
|
||||
circ.set('fill', fill)
|
||||
circ.set('stroke', stroke)
|
||||
circ.set('stroke-width', stroke_width)
|
||||
if reference == 'true':
|
||||
circ.attrib['reference'] = 'true'
|
||||
return
|
||||
|
||||
def addSquare(parent, id, w, h, x, y, reference='false'):
|
||||
# create & write a square element, set its attributes
|
||||
square = etree.SubElement(parent, inkex.addNS('rect', 'svg'))
|
||||
square.set('id', id)
|
||||
square.set('width', str(w))
|
||||
square.set('height', str(h))
|
||||
square.set('x', str(x))
|
||||
square.set('y', str(y))
|
||||
square.set('stroke', 'none')
|
||||
square.set('fill', '#000000')
|
||||
square.set('stroke-width', '1')
|
||||
if (reference == 'true'):
|
||||
square.attrib['reference'] = 'true'
|
||||
return
|
||||
|
||||
def addText(parent, id, x, y, text, fontsize = '12', textalign = 'left', textanchor = 'left', reference = 'false'):
|
||||
'''Create a text element, set its attributes, then write to canvas.
|
||||
The text element is different than other elements -- > Set attributes first then write to canvas using append method.
|
||||
There is no etree.SubElement() method for creating a text element & placing it into the document in one step.
|
||||
Use inkex's etree.Element() method to create an unattached text svg object,
|
||||
then use a document object's append() method to place it on the document canvas'''
|
||||
#create a text element with inkex's Element()
|
||||
txt = etree.Element(inkex.addNS('text', 'svg'))
|
||||
#set attributes of the text element
|
||||
txt.set('id', id)
|
||||
txt.set('x', str(x))
|
||||
txt.set('y', str(y))
|
||||
txt.text = text
|
||||
style = {'text-align':textalign, 'text-anchor':textanchor, 'font-size':fontsize}
|
||||
txt.set('style', str(inkex.Style(style)))
|
||||
if reference == 'true':
|
||||
txt.attrib['reference'] = 'true'
|
||||
#txt.setAttribute('reference', 'true') #alternative syntax
|
||||
#add to canvas in the parent group
|
||||
parent.append(txt)
|
||||
return
|
||||
|
||||
def addLayer(parent, id):
|
||||
'''Create & write an inkscape group-layer to canvas'''
|
||||
new_layer = etree.SubElement(parent, 'g')
|
||||
new_layer.set('id', id)
|
||||
new_layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer')
|
||||
new_layer.set(inkex.addNS('label', 'inkscape'), '%s layer' % (id))
|
||||
return new_layer
|
||||
|
||||
def addGroup(parent, id):
|
||||
'''Create & write an svg group to canvas'''
|
||||
new_layer = etree.SubElement(parent, 'g')
|
||||
new_layer.set('id', id)
|
||||
return new_layer
|
||||
|
||||
def addPath(parent, id, path_str, path_type):
|
||||
'''Accepts parent, id, path string, path type. Creates attribute dictionary. Creates & writes path.'''
|
||||
reference = 'false'
|
||||
if path_type == 'seamline':
|
||||
path_style = {'stroke':'green', 'stroke-width':'4', 'fill':'none', 'opacity':'1', 'stroke-dasharray':'15, 5', 'stroke-dashoffset':'0'}
|
||||
elif path_type == 'cuttingline':
|
||||
path_style = {'stroke':'green', 'stroke-width':'4', 'fill':'none', 'opacity':'1'}
|
||||
elif path_type == 'gridline':
|
||||
path_style = {'stroke':'gray', 'stroke-width':'4', 'fill':'none', 'opacity':'1', 'stroke-dasharray':'6, 6', 'stroke-dashoffset':'0'}
|
||||
reference = 'true'
|
||||
elif path_type == 'dartline':
|
||||
path_style = {'stroke':'gray', 'stroke-width':'4', 'fill':'none', 'opacity':'1'}
|
||||
elif path_type == 'grainline':
|
||||
path_style = {'stroke':'DimGray', 'stroke-width':'3', 'fill':'none', 'opacity':'1', \
|
||||
'marker-start':'url(#ArrowStart)', 'marker-end':'url(#ArrowEnd)'}
|
||||
elif path_type == 'slashline':
|
||||
path_style = {'stroke':'green', 'stroke-width':'4', 'fill':'none', 'opacity':'1'}
|
||||
svg_path = etree.SubElement(parent, inkex.addNS('path', 'svg'))
|
||||
svg_path.set('id', id)
|
||||
svg_path.set('d', path_str)
|
||||
svg_path.set('style', str(inkex.Style(path_style)))
|
||||
if reference == 'true':
|
||||
svg_path.attrib['reference'] = 'true'
|
||||
return svg_path
|
||||
|
||||
def formatPath( * args):
|
||||
"""
|
||||
Accepts a series of pseudo svg path arguments 'M', 'L', 'C' , and point objects.
|
||||
Returns path_string which is a string formatted for use as the 'd' path attribute in an svg object.
|
||||
"""
|
||||
tokens = [] # initialize an empty array
|
||||
# put all the parameters in * args into the array
|
||||
for arg in args:
|
||||
tokens.append(arg)
|
||||
com = ', '
|
||||
path_string = ''
|
||||
i = 0
|
||||
while (i < len(tokens)):
|
||||
cmd = tokens[i]
|
||||
if (cmd == 'M') or (cmd == 'L'):
|
||||
path_string += " %s %g %g" % (cmd, tokens[i + 1].x, tokens[i + 1].y)
|
||||
i = i + 2
|
||||
elif (cmd == 'C'):
|
||||
path_string += " %s %g %g %g %g %g %g" % (cmd, tokens[i + 1].x, \
|
||||
tokens[i + 1].y, tokens[i + 2].x, tokens[i + 2].y, tokens[i + 3].x, tokens[i + 3].y)
|
||||
i = i + 4
|
||||
return path_string
|
||||
|
||||
def addDefs(doc):
|
||||
'''Add defs group with markers to the document'''
|
||||
defs = etree.SubElement(doc, inkex.addNS('defs', 'svg'))
|
||||
#add start arrow
|
||||
marker = etree.SubElement(defs, 'marker', {'id':'ArrowStart', 'orient':'auto', 'refX':'0.0', 'refY':'0.0', 'style':'overflow:visible'})
|
||||
etree.SubElement(marker, 'path', {'d':'M 0, 0 L 0, 5 L -20, 0 L 0, -5 z', 'style':'fill:DimGray; stroke:DimGray; stroke-width:0.5'})
|
||||
#add end arrow
|
||||
marker = etree.SubElement(defs, 'marker', {'id':'ArrowEnd', 'orient':'auto', 'refX':'0.0', 'refY':'0.0', 'style':'overflow:visible'})
|
||||
etree.SubElement(marker, 'path', {'d':'M 0, 0 L 0, 5 L 20, 0 L 0, -5 z', 'style':'fill:DimGray; stroke:DimGray; stroke-width:0.5'})
|
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||
<name>Shirt Waist (Sara May Allington)</name>
|
||||
<id>fablabchemnitz.de.shirt_waist</id>
|
||||
<param name="m_unit" type="optiongroup" appearance="combo" gui-text="Select measurement: ">
|
||||
<option value="Inches">Inches</option>
|
||||
<option value="Centimeters">Centimeters</option>
|
||||
</param>
|
||||
<param name="m_front_waist_length" type="float" min="1.0" max="100.0" gui-text="Front Waist Length">15.0</param>
|
||||
<param name="m_back_waist_length" type="float" min="1.0" max="100.0" gui-text="Back Waist Length">15.5</param>
|
||||
<param name="m_neck_circumference" type="float" min="1.0" max="100.0" gui-text="Neck Circumference">13.5</param>
|
||||
<param name="m_bust_circumference" type="float" min="1.0" max="100.0" gui-text="Bust Circumference">39.0</param>
|
||||
<param name="m_waist_circumference" type="float" min="1.0" max="100.0" gui-text="Waist Circumference">25.0</param>
|
||||
<param name="m_armscye_circumference" type="float" min="1.0" max="100.0" gui-text="Armscye Circumference">15.0</param>
|
||||
<param name="m_across_back" type="float" min="1.0" max="100.0" gui-text="Across Back">13.5</param>
|
||||
<param name="m_side" type="float" min="1.0" max="100.0" gui-text="Side">7.75</param>
|
||||
<param name="m_upper_front_height" type="float" min="1.0" max="100.0" gui-text="Upper Front Height">10.75</param>
|
||||
<param name="m_overarm_length" type="float" min="1.0" max="100.0" gui-text="Overarm Length">20.00</param>
|
||||
<param name="m_elbow_height" type="float" min="1.0" max="100.0" gui-text="Elbow height - from wrist to elbow">9.50</param>
|
||||
<param name="m_elbow_circumference" type="float" min="1.0" max="100.0" gui-text="Elbow Circumference">12.50</param>
|
||||
<param name="m_hand_circumference" type="float" min="1.0" max="100.0" gui-text="Hand Circumference">8.00</param>
|
||||
<effect>
|
||||
<object-type>all</object-type>
|
||||
<effects-menu>
|
||||
<submenu name="FabLab Chemnitz">
|
||||
<submenu name="Dimensioning/Measuring"/>
|
||||
</submenu>
|
||||
</effects-menu>
|
||||
</effect>
|
||||
<script>
|
||||
<command location="inx" interpreter="python">fablabchemnitz_shirt_waist_allington.py</command>
|
||||
</script>
|
||||
</inkscape-extension>
|
@ -0,0 +1,460 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# shirt_waist_allington.py
|
||||
# Inkscape extension-Effects-Sewing Patterns-Shirt Waist Allington
|
||||
# Copyright (C) 2010, 2011, 2012 Susan Spencer, Steve Conklin <www.taumeta.org>
|
||||
|
||||
'''
|
||||
Licensing paragraph:
|
||||
|
||||
1. CODE LICENSE: GPL 2.0+
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
2. PATTERN LICENSE: CC BY-NC 3.0
|
||||
The output of this code is a pattern and is considered a
|
||||
visual artwork. The pattern is licensed under
|
||||
Attribution-NonCommercial 3.0 (CC BY-NC 3.0)
|
||||
<http://creativecommons.org/licenses/by-nc/3.0/>
|
||||
Items made from the pattern may be sold;
|
||||
the pattern may not be sold.
|
||||
|
||||
End of Licensing paragraph.
|
||||
'''
|
||||
|
||||
import math, inkex
|
||||
from fablabchemnitz_sewing_patterns import *
|
||||
|
||||
class ShirtWaistAllington(inkex.Effect):
|
||||
def __init__(self):
|
||||
|
||||
inkex.Effect.__init__(self)
|
||||
self.arg_parser.add_argument('--m_unit', default = 'Inches', help = 'Centimeters or Inches?')
|
||||
self.arg_parser.add_argument('--m_front_waist_length', type = float, default = '15.0', help = 'Front Waist Length')
|
||||
self.arg_parser.add_argument('--m_back_waist_length', type = float, default = '15.5', help = 'Back Waist Length')
|
||||
self.arg_parser.add_argument('--m_neck_circumference', type = float, default = '13.5', help = 'Neck Circumference')
|
||||
self.arg_parser.add_argument('--m_bust_circumference', type = float, default = '39.0', help = 'Bust Circumference')
|
||||
self.arg_parser.add_argument('--m_waist_circumference', type = float, default = '25.0', help = 'Waist Circumference')
|
||||
self.arg_parser.add_argument('--m_armscye_circumference', type = float, default = '15.0', help = 'Armscye circumference')
|
||||
self.arg_parser.add_argument('--m_across_back', type = float, default = '13.5', help = 'Across Back')
|
||||
self.arg_parser.add_argument('--m_shoulder', type = float, default = '6.5', help = 'Shoulder')
|
||||
self.arg_parser.add_argument('--m_side', type = float, default = '7.75', help = 'Side')
|
||||
self.arg_parser.add_argument('--m_upper_front_height', type = float, default = '10.75', help = 'Upper Front Height')
|
||||
self.arg_parser.add_argument('--m_overarm_length', type = float, default = '20.00', help = 'Overarm Length')
|
||||
self.arg_parser.add_argument('--m_elbow_height', type = float, default = '9.50', help = 'Elbow Height - from wrist to elbow')
|
||||
self.arg_parser.add_argument('--m_elbow_circumference', type = float, default = '12.50', help = 'Elbow Circumference - arm bent')
|
||||
self.arg_parser.add_argument('--m_hand_circumference', type = float, default = '8.00', help = 'Hand Circumference')
|
||||
|
||||
def effect(self):
|
||||
|
||||
def printPoint(pnt):
|
||||
debug(' %s = %f, %f')%pnt.id, pnt.x, pnt.y
|
||||
|
||||
INCH_to_PX = 96.0 #inkscape 1.0 uses 96 pixels per 1 inch
|
||||
CM_to_INCH = 1/2.54
|
||||
CM_to_PX = CM_to_INCH*INCH_to_PX
|
||||
CM = CM_to_PX # CM - shorthand when using centimeters
|
||||
IN = INCH_to_PX # IN - shorthand when using inches
|
||||
|
||||
#all measurements must be converted to px
|
||||
munit = self.options.m_unit
|
||||
if munit == 'Centimeters':
|
||||
MEASUREMENT_CONVERSION = CM
|
||||
else:
|
||||
MEASUREMENT_CONVERSION = IN
|
||||
|
||||
#convert measurements
|
||||
front_waist_length = self.options.m_front_waist_length * MEASUREMENT_CONVERSION
|
||||
neck_circumference = self.options.m_neck_circumference * MEASUREMENT_CONVERSION
|
||||
bust_circumference = self.options.m_bust_circumference * MEASUREMENT_CONVERSION
|
||||
waist_circumference = self.options.m_waist_circumference * MEASUREMENT_CONVERSION
|
||||
armscye_circumference = self.options.m_armscye_circumference * MEASUREMENT_CONVERSION
|
||||
across_back = self.options.m_across_back * MEASUREMENT_CONVERSION
|
||||
shoulder = self.options.m_shoulder * MEASUREMENT_CONVERSION
|
||||
side = self.options.m_side * MEASUREMENT_CONVERSION
|
||||
upper_front_height = self.options.m_upper_front_height * MEASUREMENT_CONVERSION
|
||||
overarm_length = self.options.m_overarm_length * MEASUREMENT_CONVERSION
|
||||
elbow_height = self.options.m_elbow_height * MEASUREMENT_CONVERSION
|
||||
elbow_circumference = self.options.m_elbow_circumference * MEASUREMENT_CONVERSION
|
||||
hand_circumference = self.options.m_hand_circumference * MEASUREMENT_CONVERSION
|
||||
|
||||
#constants
|
||||
ANGLE90 = angleOfDegree(90)
|
||||
ANGLE180 = angleOfDegree(180)
|
||||
SEAM_ALLOWANCE = (5/8.0)*IN
|
||||
BORDER = 1*IN
|
||||
NOTE_HEIGHT = 1*IN
|
||||
|
||||
#get the document, set initial width & height
|
||||
doc = self.document.getroot() # self.document is the canvas seen in Inkscape
|
||||
#add defs group with markers to document
|
||||
addDefs(doc)
|
||||
|
||||
#width_orig = inkex.unittouu(doc.get('width'))
|
||||
#height_orig = inkex.unittouu(doc.get('height'))
|
||||
#doc_width = 4*BORDER+4*SEAM_ALLOWANCE + bust_circumference/2.0
|
||||
#doc_height = 2*BORDER+3*SEAM_ALLOWANCE+(upper_front_height+side)
|
||||
#doc.set('width', str(doc_width)) #temporary document width, doc is resized near end of pattern file
|
||||
#doc.set('height', str(doc_height)) #temporary document height, doc is resized near end of pattern file
|
||||
|
||||
|
||||
#create a base group in the document to hold all patterns
|
||||
pattern_base = base(doc, 'pattern_base')
|
||||
#create a pattern group for each pattern, put pattern group in base group - there can be multiple patterns
|
||||
bodice = pattern(pattern_base, 'bodice')
|
||||
# create a group for each pattern piece, put pattern piece group in pattern group
|
||||
A = patternPiece(bodice, 'A', 'bodice_front', fabric = 2, interfacing = 0, lining = 0)
|
||||
B = patternPiece(bodice, 'B', 'bodice_back', fabric = 2, interfacing = 0, lining = 0)
|
||||
C = patternPiece(bodice, 'C', 'bodice_sleeve', fabric = 2, interfacing = 0, lining = 0)
|
||||
D = patternPiece(bodice, 'D', 'bodice_cuff', fabric = 2, interfacing = 0, lining = 0)
|
||||
|
||||
#pattern notes
|
||||
notes = []
|
||||
notes.append('Define Seam Allowances: Select File/Inkscape Preferences/Steps and set Outset to 56.25px (5/8" seam allowance)')
|
||||
notes.append('Create Seam Allowances: Press CTRL-F, type "cuttingline" in the ID field, click the Find button, press CTRL-)')
|
||||
notes.append('Remove Points & Gridlines: Press CTRL-F, type "reference" in the Attribute field, click Find button, press DELETE')
|
||||
notes.append('Print: Save as a PDF file, open PDF with PDF viewer (Adobe, Evince, Okular, xPDF), print from Print Preview option')
|
||||
|
||||
#pattern points
|
||||
b1 = patternPointXY(B, 'b1', 0, 0) #B
|
||||
b2 = patternPoint(B, 'b2', down(b1, front_waist_length)) #A
|
||||
b3 = patternPoint(B, 'b3', up(b2, side)) #C
|
||||
a1 = patternPoint(A, 'a1', left(b3, bust_circumference/2.0)) #D
|
||||
b4 = patternPoint(B, 'b4', left(b3, across_back/2.0)) #E
|
||||
b5 = patternPoint(B, 'b5', up(b4, armscye_circumference/3.0)) #F
|
||||
b6 = patternPoint(B, 'b6', up(b1, 0.5*IN)) #G
|
||||
b7 = patternPoint(B, 'b7', left(b6, 1.5*IN)) #H
|
||||
b8 = patternPoint(B, 'b8', onLineAtLength(b5, b7, -0.5*IN)) #I
|
||||
a2 = patternPoint(A, 'a2', left(b4, armscye_circumference/4.0)) #J
|
||||
a3 = patternPoint(A, 'a3', midPoint(a2, b4)) #K
|
||||
a4 = patternPoint(A, 'a4', up(a2, 2.5*IN)) #L
|
||||
a5 = patternPoint(A, 'a5', up(b5, 1.5*IN)) #M
|
||||
a6 = patternPoint(A, 'a6', left(a5, 2*IN)) #N
|
||||
a7 = patternPoint(A, 'a7', left(a6, distance(b7, b8))) #O
|
||||
a8 = patternPointXY(A, 'a8', a7.x, b3.y - (upper_front_height - distance(b1, b7))) #P
|
||||
a9 = patternPoint(A, 'a9', down(a8, neck_circumference/4.0)) #Q
|
||||
a10 = patternPoint(A, 'a10', up(a9, 0.5*IN)) #R
|
||||
a11 = patternPoint(A, 'a11', left(a10, (neck_circumference/6.0)+0.25*IN )) #S
|
||||
b9 = patternPoint(B, 'b9', midPoint(a3, b4)) #T on back bodice B
|
||||
a12 = patternPoint(A, 'a12', b9) #T on front bodice A
|
||||
b10 = patternPoint(B, 'b10', down(b9, side)) #U
|
||||
b11 = patternPoint(B , 'b11', right(b10, 1*IN)) #V
|
||||
a13 = patternPoint(A, 'a13', left(b10, 1*IN)) #W
|
||||
a14 = patternPoint(A, 'a14', onLineAtLength(a11, a1, front_waist_length)) #X
|
||||
a15 = patternPoint(A, 'a15', down(a8, distance(a8, a14))) #Y - new point at front waist
|
||||
b12 = patternPoint(B, 'b12', up(b4, distance(b5, b4)/3.0)) #Z - new point at back armscye
|
||||
#temporary armscye curve from a3 to b12 to find top point of side seam
|
||||
length = distance(a3, b12)/3.0
|
||||
temp_b12_c1 = right(a3, length) #don't create an svg controlpoint circle for this point
|
||||
temp_b12_c2 = down(b12, length) #or for this point
|
||||
#find top point of side seam with intersection of side and armscye curve, save to two points a16 and b13
|
||||
curve1 = pointList(a3, temp_b12_c1, temp_b12_c2, b12)
|
||||
intersections = intersectLineCurve(b10, b9, curve1) #this line is directional from b10 to b9
|
||||
b13 = patternPoint(B, 'b13', intersections[0]) # AA on bodice back B -use 1st intersection found, in this case there's only one intersection
|
||||
a16 = patternPoint(A, 'a16', b13) #AA on bodice back A
|
||||
|
||||
#front control points - path runs counterclockwise from front neck center a11
|
||||
#front neck control points from a8 to a11
|
||||
length = distance(a8, a11)/3.0
|
||||
a11.c2 = controlPoint(A, 'a11.c2', right(a11, 1.5*length))
|
||||
a11.c1 = controlPoint(A, 'a11.c1', polar(a8, length, angleOfLine(a8, a11.c2)))
|
||||
#front waist control points from a14 to a15
|
||||
length = distance(a14, a15)/3.0
|
||||
a15.c1 = controlPoint(A, 'a15.c1', polar(a14, length, angleOfLine(a14, a11)+ANGLE90)) #control handle line is perpendicular to line a14-a11
|
||||
a15.c2 = controlPoint(A, 'a15.c2', left(a15, length))
|
||||
#front waist control points from a15 to a13
|
||||
length = distance(a15, a13)/3.0
|
||||
a13.c1 = controlPoint(A, 'a13.c1', right(a15, 1.5*length))
|
||||
a13.c2 = controlPoint(A, 'a13.c2', polar(a13, length, angleOfLine(a13, a13.c1))) #second control aimed at first control point
|
||||
#front side control points from a13 to a12
|
||||
length = distance(a13, a12)/3.0
|
||||
a12.c1 = controlPoint(A, 'a12.c1', up(a13, length))
|
||||
a12.c2 = controlPoint(A, 'a12.c2', down(a12, length))
|
||||
#front armscye control points from a16 to a3 to a4 to 16
|
||||
length1 = distance(a16, a3)/3.0
|
||||
length2 = distance(a3, a4)/3.0
|
||||
length3 = distance(a4, a6)/3.0
|
||||
angle1 = angleOfLine(a16, a3)
|
||||
angle2 = ANGLE180
|
||||
angle3 = (angle1+angle2)/2.0
|
||||
a3.c1 = controlPoint(A, 'a3.c1', polar(a16, length1, angle1))
|
||||
a3.c2 = controlPoint(A, 'a3.c2', polar(a3, length1, angle3-ANGLE180))
|
||||
a4.c1 = controlPoint(A, 'a4.c1', polar(a3, length2, angle3))
|
||||
angle4 = angleOfLine(a3, a6)
|
||||
angle5 = angleOfLine(a4, a6)
|
||||
angle6 = (angle4+angle5)/2.0
|
||||
a4.c2 = controlPoint(A, 'a4.c2', polar(a4, 1.5*length2, angle6-ANGLE180))
|
||||
a6.c1 = controlPoint(A, 'a6.c1', polar(a4, length3, angle6))
|
||||
a6.c2 = controlPoint(A, 'a6.c2', polar(a6, length3/2.0, angleOfLine(a8, a6)+ANGLE90))
|
||||
|
||||
#back control points - path runs clockwise from back nape b1
|
||||
#back neck control points from b7 to b1
|
||||
length = distance(b7, b1)/3.0
|
||||
b1.c1 = controlPoint(B, 'b1.c1', down(b7, length/2.0)) #short control point handle
|
||||
b1.c2 = controlPoint(B, 'b1.c2', left(b1, length*2)) #long control point handle
|
||||
#back side control points from b11 to b9
|
||||
length = distance(b11, b9)/3.0
|
||||
b9.c1 = controlPoint(B, 'b9.c1', up(b11, length))
|
||||
b9.c2 = controlPoint(B, 'b9.c2', down(b9, length))
|
||||
#back armscye points from b13 to b12 to b8
|
||||
length1 = distance(b13, b12)/3.0
|
||||
length2 = distance(b12, b8)/3.0
|
||||
angle1 = angleOfLine(b13, b8)
|
||||
b12.c1 = controlPoint(B, 'b12.c1', polar(b13, length1, angleOfLine(a3.c1, a16)))
|
||||
b12.c2 = controlPoint(B, 'b12.c2', polar(b12, length1, angle1-ANGLE180))
|
||||
b8.c1 = controlPoint(B, 'b8.c1', polar(b12, length2, angle1))
|
||||
b8.c2 = controlPoint(B, 'b8.c2', polar(b8, length2/2.0, angleOfLine(b7, b8)-ANGLE90))
|
||||
|
||||
#sleeve C
|
||||
c1 = patternPointXY(C, 'c1', 0.0, 0.0) #A
|
||||
c2 = patternPoint(C, 'c2', down(c1, overarm_length)) #B
|
||||
c3 = patternPoint(C, 'c3', up(c2, elbow_height)) #C
|
||||
c4 = patternPoint(C, 'c4', right(c2, 1*IN)) #D
|
||||
c5 = patternPoint(C, 'c5', right(c3, 0.5*IN)) #E
|
||||
c6 = patternPoint(C, 'c6', left(c1, 1*IN)) #F
|
||||
c7 = patternPoint(C, 'c7', right(c4, 1*IN)) #G
|
||||
c8 = patternPoint(C, 'c8', right(c7, hand_circumference+2*IN)) #H
|
||||
c9 = patternPoint(C, 'c9', right(c8, 1*IN)) #I
|
||||
c10 = patternPoint(C, 'c10', right(c5, 1*IN) )#J
|
||||
c11 = patternPoint(C, 'c11', right(c10, elbow_circumference)) #K
|
||||
c12 = patternPoint(C, 'c12', right(c11, 0.5*IN)) #L
|
||||
c13 = patternPoint(C, 'c13', right(c1, armscye_circumference)) #M
|
||||
c14 = patternPoint(C, 'c14', right(c13, 2*IN)) #N
|
||||
c15 = patternPoint(C, 'c15', up(c1, 2.5*IN)) #O
|
||||
c16 = patternPoint(C, 'c16', right(c1, 1.5*IN)) #P
|
||||
c17 = patternPoint(C, 'c17', left(c13, 3*IN)) #Q
|
||||
c18 = patternPointXY(C, 'c18', c16.x, c15.y) #R
|
||||
c19 = patternPointXY(C, 'c19', c17.x, c15.y) #S
|
||||
c20 = patternPoint(C, 'c20', midPoint(c16, c17)) #T
|
||||
c21 = patternPoint(C, 'c21', up(c20, distance(c20, c18))) #U - above T
|
||||
c22 = patternPoint(C, 'c22', down(midPoint(c7, c8), 0.75*IN)) #V - was U
|
||||
c23 = patternPoint(C, 'c23', right(c4, distance(c4, c8)*3/5.0)) #W
|
||||
c24 = patternPoint(C, 'c24', up(c23, distance(c4, c3)/3.0)) #X - was V
|
||||
c25 = patternPoint(C, 'c25', down(c23, 0.75*IN)) #Y - new point
|
||||
# sleeve C control points
|
||||
# sleevecap c6 to c18 to c21 to c19 to c13 to c14
|
||||
length1 = distance(c6, c18)/3.0
|
||||
length2 = distance(c18, c21)/3.0
|
||||
c21.c2 = controlPoint(C, 'c21.c2', left(c21, length2))
|
||||
c21.c1 = controlPoint(C, 'c21.c1', polar(c18, length2, angleOfLine(c18, c21.c2)))
|
||||
angle = angleOfLine(c6, c18)+angleOfVector(c18, c6, c1)/2.0
|
||||
c18.c1 = controlPoint(C, 'c18.c1', polar(c6, length1, angle))
|
||||
c18.c2 = controlPoint(C, 'c18.c2', polar(c18, length1, angleOfLine(c21.c1, c18)))
|
||||
length1 = distance(c21, c19)/3.0
|
||||
length2 = distance(c19, c13)/3.0
|
||||
length3 = distance(c13, c14)/3.0
|
||||
c19.c1 = controlPoint(C, 'c19.c1', right(c21, length1))
|
||||
c19.c2 = controlPoint(C, 'c19.c2', polar(c19, length1, angleOfLine(c19, c19.c1)))
|
||||
c13.c1 = controlPoint(C, 'c13.c1', polar(c19, length2, angleOfLine(c19.c2, c19)))
|
||||
angle1 = angleOfLine(c13.c1, c13)/2.0
|
||||
c13.c2 = controlPoint(C, 'c13.c2', polar(c13, length2, angle1+ANGLE180))
|
||||
c14.c1 = controlPoint(C, 'c14.c1', polar(c13, length3, angle1))
|
||||
c14.c2 = controlPoint(C, 'c14.c2', polar(c14, length3, angleOfLine(c18.c1, c6)))
|
||||
# c14 to c12
|
||||
length = distance(c14, c12)/3.0
|
||||
c12.c2 = controlPoint(C, 'c12.c2', polar(c12, length, angleOfLine(c9, c12)))
|
||||
c12.c1 = controlPoint(C, 'c12.c1', polar(c14, length, angleOfLine(c14, c12.c2)))
|
||||
# c9 to c25
|
||||
length = distance(c9, c25)/3.0
|
||||
c25.c2 = controlPoint(C, 'c25.c2', right(c25, length))
|
||||
c25.c1 = controlPoint(C, 'c25.c1', polar(c9, length, angleOfLine(c9, c25.c2)))
|
||||
#c22 to c4
|
||||
length = distance(c22, c4)/3.0
|
||||
c4.c1 = controlPoint(C, 'c4.c1', left(c22, length))
|
||||
c4.c2 = controlPoint(C, 'c4.c2', polar(c4, length, angleOfLine(c4, c4.c1)))
|
||||
#c5 to c6
|
||||
length = distance(c5, c6)/3.0
|
||||
c6.c1 = controlPoint(C, 'c6.c1', polar(c5, length, angleOfLine(c4, c5)))
|
||||
c6.c2 = controlPoint(C, 'c6.c2', polar(c6, length, angleOfLine(c6, c6.c1)))
|
||||
|
||||
|
||||
#cuff D
|
||||
d1 = patternPointXY(D, 'd1', 0, 0)
|
||||
d2 = patternPoint(D, 'd2', right(d1, hand_circumference+2*IN))
|
||||
d3 = patternPoint(D, 'd3', down(d2, 3*IN))
|
||||
d4 = patternPoint(D, 'd4', up(d3, 0.75*IN))
|
||||
d5 = patternPoint(D, 'd5', left(d3, 1*IN))
|
||||
d6 = patternPoint(D, 'd6', down(d1, 3*IN))
|
||||
d7 = patternPoint(D, 'd7', right(d6, 1*IN))
|
||||
d8 = patternPoint(D, 'd8', up(d6, 0.75*IN))
|
||||
length1 = 0.7*distance(d1, d6)
|
||||
length2 = 0.75*IN
|
||||
d9 = patternPointXY(D, 'd9', d1.x+0.5*IN, d1.y+length1)
|
||||
d10 = patternPoint(D, 'd10', right(d9, length2))
|
||||
d11 = patternPointXY(D, 'd11', d2.x-0.5*IN, d2.y+length1)
|
||||
d12 = patternPoint(D, 'd12', left(d11, length2))
|
||||
#cuff D control points
|
||||
length = distance(d4, d5)/3.0
|
||||
d5.c1 = controlPoint(D, 'd5.c1', down(d4, length))
|
||||
d5.c2 = controlPoint(D, 'd5.c2', right(d5, length))
|
||||
d8.c1 = controlPoint(D, 'd8.c1', left(d7, length))
|
||||
d8.c2 = controlPoint(D, 'd8.c2', down(d8, length))
|
||||
|
||||
# all points are defined, now create paths with them...
|
||||
# pattern marks, labels, grainlines, seamlines, cuttinglines, darts, etc.
|
||||
|
||||
#bodice front A
|
||||
#letter
|
||||
pnt1 = Point('', a8.x, a6.c1.y)
|
||||
addText(A, 'A_letter', pnt1.x, pnt1.y, 'A', fontsize = '72')
|
||||
#label
|
||||
pnt2 = down(pnt1, 0.5*IN)
|
||||
addText(A, 'A_label', pnt2.x, pnt2.y, 'Bodice Front', fontsize = '48')
|
||||
#label
|
||||
pnt3 = down(pnt2, 0.5*IN)
|
||||
addText(A, 'A_fabric', pnt3.x, pnt3.y, 'Cut 2 of fabric', fontsize = '38')
|
||||
#grainline points
|
||||
aG1 = down(a11, front_waist_length/3.0)
|
||||
aG2 = polar(aG1, front_waist_length/2.0, angleOfLine(a11, a14))
|
||||
path_str = formatPath('M', aG1, 'L', aG2)
|
||||
A_grainline = addPath(A, 'A_grainline', path_str, 'grainline')
|
||||
# gridline - helpful for troubleshooting during design phase
|
||||
path_str = formatPath('M', a1, 'L', a3, 'M', a4, 'L', a2, 'M', a8, 'L', a15, 'M', a11, 'L', a10, 'M', a7, 'L', a5)
|
||||
A_gridline = addPath(A, 'A_gridline', path_str, 'gridline')
|
||||
#seamline & cuttingline
|
||||
path_str = formatPath('M', a11, 'L', a14, 'C', a15.c1, a15.c2, a15, 'C', a13.c1, a13.c2, a13, 'C', a12.c1, a12.c2, a12)
|
||||
path_str = path_str+formatPath('L', a16, 'C', a3.c1, a3.c2, a3, 'C', a4.c1, a4.c2, a4, 'C', a6.c1, a6.c2, a6, 'L', a8, 'C', a11.c1, a11.c2, a11)
|
||||
A_seamline = addPath(A, 'A_seamline', path_str, 'seamline')
|
||||
A_cuttingline = addPath(A, 'A_cuttingline', path_str, 'cuttingline')
|
||||
|
||||
#bodice back B
|
||||
#letter
|
||||
pnt1 = Point('', b8.x*2/3.0, b8.c2.y)
|
||||
addText(B, 'B_letter', pnt1.x, pnt1.y, 'B', fontsize = '72') #
|
||||
#label
|
||||
pnt2 = down(pnt1, 0.5*IN)
|
||||
addText(B, 'B_name', pnt2.x, pnt2.y, 'Bodice Back', fontsize = '48')
|
||||
#label
|
||||
pnt3 = down(pnt2, 0.5*IN)
|
||||
addText(B, 'B_fabric', pnt3.x, pnt3.y, 'Cut 2 of fabric', fontsize = '38')
|
||||
#grainline points
|
||||
bG1 = down(b7, front_waist_length/3.0)
|
||||
bG2 = down(bG1, front_waist_length/2.0)
|
||||
path_str = formatPath('M', bG1, 'L', bG2)
|
||||
B_grainline = addPath(B, 'B_grainline', path_str, 'grainline')
|
||||
# gridline
|
||||
path_str = formatPath('M', b1, 'L', b2, 'M', b11, 'L', b9, 'M', b9, 'L', b10, 'M', b7, 'L', b6, 'L', b1, 'M', b11, 'L', b10)
|
||||
B_gridline = addPath(B, 'B_gridline', path_str, 'gridline')
|
||||
#seamline & cuttingline
|
||||
path_str = formatPath('M', b1, 'L', b2, 'L', b11, 'C', b9.c1, b9.c2, b9, 'L', b13, 'C', b12.c1, b12.c2, b12, 'C', b8.c1, b8.c2, b8, 'L', b7, 'C', b1.c1, b1.c2, b1)
|
||||
B_seamline = addPath(B, 'B_seamline', path_str, 'seamline')
|
||||
B_cuttingline = addPath(B, 'B_cuttingline', path_str, 'cuttingline')
|
||||
|
||||
#bodice sleeve C
|
||||
#letter
|
||||
pnt1 = Point('', c19.c1.x, c12.c1.y)
|
||||
addText(C, 'C_letter', pnt1.x, pnt1.y, 'C', fontsize = '72') #
|
||||
#label
|
||||
pnt2 = down(pnt1, 0.5*IN)
|
||||
addText(C, 'C_name', pnt2.x, pnt2.y, 'Bodice Sleeve', fontsize = '48')
|
||||
#label
|
||||
pnt3 = down(pnt2, 0.5*IN)
|
||||
addText(C, 'C_fabric', pnt3.x, pnt3.y, 'Cut 2 of fabric', fontsize = '38')
|
||||
#grainline points
|
||||
cG1 = c20
|
||||
cG2 = down(cG1, overarm_length/2.0)
|
||||
path_str = formatPath('M', cG1, 'L', cG2)
|
||||
C_grainline = addPath(C, 'C_grainline', path_str, 'grainline')
|
||||
# gridline
|
||||
path_str = formatPath('M', c15, 'L', c2, 'M', c15, 'L', c19, 'M', c2, 'L', c9, 'M', c3, 'L', c12, 'M', c6, 'L', c14, 'M', c18, 'L', c16, 'M', c19, 'L', c17)
|
||||
C_gridline = addPath(C, 'C_gridline', path_str, 'gridline')
|
||||
# slashline
|
||||
path_str = formatPath('M', c24, 'L', c25)
|
||||
C_slashline = addPath(C, 'C_slashline', path_str, 'slashline')
|
||||
#seamline & cuttingline
|
||||
path_str = formatPath('M', c6, 'C', c18.c1, c18.c2, c18, 'C', c21.c1, c21.c2, c21, 'C', c19.c1, c19.c2, c19, 'C', c13.c1, c13.c2, c13, 'C', c14.c1, c14.c2, c14)
|
||||
path_str += formatPath('C', c12.c1, c12.c2, c12, 'L', c9, 'C', c25.c1, c25.c2, c25, 'L', c22, 'C', c4.c1, c4.c2, c4, 'L', c5, 'C', c6.c1, c6.c2, c6)
|
||||
C_seamline = addPath(C, 'C_seamline', path_str, 'seamline')
|
||||
C_cuttingline = addPath(C, 'C_cuttingline', path_str, 'cuttingline')
|
||||
|
||||
#bodice cuff D
|
||||
#letter
|
||||
pnt1 = Point('', d7.x, d6.y/4.0)
|
||||
addText(D, 'D_letter', pnt1.x, pnt1.y, 'D', fontsize = '38') #
|
||||
#label
|
||||
pnt2 = right(pnt1, 1*IN)
|
||||
addText(D, 'C_name', pnt2.x, pnt2.y, 'Bodice Sleeve Cuff', fontsize = '30')
|
||||
#label
|
||||
pnt3 = right(pnt2, 4*IN)
|
||||
addText(D, 'C_fabric', pnt3.x, pnt3.y, 'Cut 2 of fabric', fontsize = '24')
|
||||
pnt3 = down(pnt3, 0.3*IN)
|
||||
addText(D, 'C_finterfacing', pnt3.x, pnt3.y, 'Cut 2 of interfacing', fontsize = '24')
|
||||
#grainline points
|
||||
pnt1 = midPoint(d1, d6)
|
||||
dG1 = right(pnt1, distance(d1, d2)/4.0)
|
||||
dG2 = right(dG1, distance(d1, d2)/2.0)
|
||||
path_str = formatPath('M', dG1, 'L', dG2)
|
||||
D_grainline = addPath(D, 'D_grainline', path_str, 'grainline')
|
||||
# gridline
|
||||
path_str = formatPath('M', d1, 'L', d2, 'L', d4, 'L', d5, 'L', d7, 'L', d8, 'L', d1)
|
||||
D_gridline = addPath(D, 'D_gridline', path_str, 'gridline')
|
||||
# slashline
|
||||
path_str = formatPath('M', d9, 'L', d10, 'M', d11, 'L', d12)
|
||||
D_slashline = addPath(D, 'D_slashline', path_str, 'slashline')
|
||||
#seamline & cuttingline
|
||||
path_str = formatPath('M', d1, 'L', d2, 'L', d4, 'C', d5.c1, d5.c2, d5, 'L', d7, 'C', d8.c1, d8.c2, d8, 'L', d1)
|
||||
D_seamline = addPath(D, 'D_seamline', path_str, 'seamline')
|
||||
D_cuttingline = addPath(D, 'D_cuttingline', path_str, 'cuttingline')
|
||||
|
||||
#layout patterns on document in rows
|
||||
dx = BORDER+SEAM_ALLOWANCE #left border, allow width for seam allowance
|
||||
dy = BORDER+NOTE_HEIGHT+2*SEAM_ALLOWANCE # print pattern under the note header, allow height for seam allowance plus extra space
|
||||
pattern_buffer = 3*SEAM_ALLOWANCE #between any two patterns need 2 seam allowances plus additional space
|
||||
# first row
|
||||
pattern_offset = dx
|
||||
row_offset = dy
|
||||
#layout bodice front A
|
||||
adx = pattern_offset-a14.x #left border offset dx, translate leftmost A point a14 to this offset
|
||||
ady = row_offset-a8.y #upper height offset dy, translate highest A point a8
|
||||
A.set('transform', 'translate('+str(adx)+' '+str(ady)+')')
|
||||
pattern_offset = adx+a12.x+pattern_buffer
|
||||
#layout bodice front B
|
||||
bdx = pattern_offset-b9.x #translate leftmost B point
|
||||
bdy = row_offset-b6.y #translate highest B point
|
||||
B.set('transform', 'translate('+str(bdx)+' '+str(bdy)+')')
|
||||
|
||||
#2nd row
|
||||
pattern_offset = dx
|
||||
row_offset = ady+a15.y+pattern_offset # row_offset + lowest point from previous row, plus pattern_offset
|
||||
#layout sleeve C
|
||||
cdx = pattern_offset-c6.x
|
||||
cdy = row_offset-c21.y
|
||||
C.set('transform', 'translate('+str(cdx)+' '+str(cdy)+')')
|
||||
pattern_offset = cdx+c14.x+pattern_buffer
|
||||
#layout cuff D
|
||||
ddx = pattern_offset-d1.x
|
||||
ddy = row_offset-d1.y
|
||||
D.set('transform', 'translate('+str(ddx)+' '+str(ddy)+')')
|
||||
#3rd row, use this to calculate document height
|
||||
row_offset = cdy+c25.y
|
||||
|
||||
#resize document to fit pattern piece layout
|
||||
width = ddx+d2.x # use pattern piece that appears farthest to the right in Inkscape canvas
|
||||
doc_width = width+2*SEAM_ALLOWANCE+2*BORDER
|
||||
doc_height = row_offset+SEAM_ALLOWANCE+BORDER
|
||||
root = self.svg.getElement('//svg:svg');
|
||||
root.set('viewBox', '%f %f %f %f' % (0,0,doc_width,doc_height))
|
||||
root.set('width', str(doc_width))
|
||||
root.set('height', str(doc_height))
|
||||
|
||||
#Place notes on document after pattern pieces are transformed so that notes are centered on correct width
|
||||
x = doc_width/2.0
|
||||
y = BORDER
|
||||
i = 0
|
||||
for item in notes:
|
||||
addText(bodice, 'note'+str(i), x, y, item, fontsize = '28', textalign = 'center', textanchor = 'middle', reference = 'false')
|
||||
y = y+0.33*IN
|
||||
|
||||
if __name__ == '__main__':
|
||||
ShirtWaistAllington().run()
|
Reference in New Issue
Block a user