def path(self, centerradius=None, bezierradius=None, beziersoftness=None): pathitems = [] if centerradius is not None and self.center is not None: r = unit.topt(centerradius) pathitems.append(path.arc_pt(self.center[0], self.center[1], r, 0, 360)) pathitems.append(path.closepath()) if bezierradius is not None or beziersoftness is not None: raise ValueError("smooth functionality removed; apply smooth deformer on path") pathitems.append(path.moveto_pt(self.corners[0][0], self.corners[0][1])) for x, y in self.corners[1:]: pathitems.append(path.lineto_pt(x, y)) pathitems.append(path.closepath()) return path.path(*pathitems)
def path(self, centerradius=None, bezierradius=None, beziersoftness=None): pathitems = [] if centerradius is not None and self.center is not None: r = unit.topt(centerradius) pathitems.append( path.arc_pt(self.center[0], self.center[1], r, 0, 360)) pathitems.append(path.closepath()) if bezierradius is not None or beziersoftness is not None: raise ValueError( "smooth functionality removed; apply smooth deformer on path") pathitems.append(path.moveto_pt(self.corners[0][0], self.corners[0][1])) for x, y in self.corners[1:]: pathitems.append(path.lineto_pt(x, y)) pathitems.append(path.closepath()) return path.path(*pathitems)
def __init__(self, box1, box2, absangle1=None, absangle2=None, relangle1=None, relangle2=None, relangleM=None, length1=None, length2=None, bezierradius=None, beziersoftness=1, arcradius=None, boxdists=[0,0]): # The connection with two lines can be done in the following ways: # 1. an angle at each box-center # 2. two armlengths (if they are long enough) # 3. angle and armlength at the same box # 4. angle and armlength at different boxes # 5. one armlength and the angle between the arms # # Angles at the box-centers can be relative or absolute # The angle in the middle is always relative # lengths are always absolute self.box1 = box1 self.box2 = box2 begin = self.box1.center end = self.box2.center rel = (self.box2.center[0] - self.box1.center[0], self.box2.center[1] - self.box1.center[1]) distance = hypot(*rel) dangle = atan2(rel[1], rel[0]) # find out what arguments are given: if relangle1 is not None: relangle1 = radians(relangle1) if relangle2 is not None: relangle2 = radians(relangle2) if relangleM is not None: relangleM = radians(relangleM) # absangle has priority over relangle: if absangle1 is not None: relangle1 = dangle - radians(absangle1) if absangle2 is not None: relangle2 = math.pi - dangle + radians(absangle2) # check integrity of arguments no_angles, no_lengths=0,0 for anangle in (relangle1, relangle2, relangleM): if anangle is not None: no_angles += 1 for alength in (length1, length2): if alength is not None: no_lengths += 1 if no_angles + no_lengths != 2: raise NotImplementedError, "Please specify exactly two angles or lengths" # calculate necessary angles and armlengths # always length1 and relangle1 # the case with two given angles # use the "sine-theorem" for calculating length1 if no_angles == 2: if relangle1 is None: relangle1 = math.pi - relangle2 - relangleM elif relangle2 is None: relangle2 = math.pi - relangle1 - relangleM elif relangleM is None: relangleM = math.pi - relangle1 - relangle2 length1 = distance * abs(sin(relangle2)/sin(relangleM)) middle = self._middle_a(begin, dangle, length1, relangle1) # the case with two given lengths # uses the "cosine-theorem" for calculating length1 elif no_lengths == 2: relangle1 = acos((distance**2 + length1**2 - length2**2) / (2.0*distance*length1)) middle = self._middle_a(begin, dangle, length1, relangle1) # the case with one length and one angle else: if relangle1 is not None: if length1 is not None: middle = self._middle_a(begin, dangle, length1, relangle1) elif length2 is not None: length1 = self._missinglength(length2, distance, relangle1) middle = self._middle_a(begin, dangle, length1, relangle1) elif relangle2 is not None: if length1 is not None: length2 = self._missinglength(length1, distance, relangle2) middle = self._middle_b(end, dangle, length2, relangle2) elif length2 is not None: middle = self._middle_b(end, dangle, length2, relangle2) elif relangleM is not None: if length1 is not None: length2 = self._missinglength(distance, length1, relangleM) relangle1 = acos((distance**2 + length1**2 - length2**2) / (2.0*distance*length1)) middle = self._middle_a(begin, dangle, length1, relangle1) elif length2 is not None: length1 = self._missinglength(distance, length2, relangleM) relangle1 = acos((distance**2 + length1**2 - length2**2) / (2.0*distance*length1)) middle = self._middle_a(begin, dangle, length1, relangle1) else: raise NotImplementedError, "I found a strange combination of arguments" connectorpath = path.path(path.moveto_pt(*self.box1.center), path.lineto_pt(*middle), path.lineto_pt(*self.box2.center)) connector_pt.__init__(self, connectorpath.normpath().normsubpaths) self.omitends(box1, box2) self.shortenpath(boxdists)
def _halfbracepath_pt(self, length_pt, height_pt, ilength_pt, olength_pt, # <<< ithick_pt, othick_pt, bthick_pt, cos_iangle, sin_iangle, cos_oangle, sin_oangle, cos_slangle, sin_slangle): ismooth = self.innerstrokessmoothness osmooth = self.outerstrokessmoothness # these two parameters are not important enough to be seen outside inner_cap_param = 1.5 outer_cap_param = 2.5 outerextracurved = 0.6 # in (0, 1] # 1.0 will lead to F=G, the outer strokes will not be curved at their ends. # The smaller, the more curvature # build an orientation path (three straight lines) # # \q1 # / \ # / \ # _/ \______________________________________q5 # q2 q3 q4 \ # \ # \ # \q6 # # get the points for that: q1 = (0, height_pt - inner_cap_param * ithick_pt + 0.5*ithick_pt/sin_iangle) q2 = (q1[0] + ilength_pt * sin_iangle, q1[1] - ilength_pt * cos_iangle) q6 = (length_pt, 0) q5 = (q6[0] - olength_pt * sin_oangle, q6[1] + olength_pt * cos_oangle) bardir = (q5[0] - q2[0], q5[1] - q2[1]) bardirnorm = math.hypot(*bardir) bardir = (bardir[0]/bardirnorm, bardir[1]/bardirnorm) ismoothlength_pt = ilength_pt * ismooth osmoothlength_pt = olength_pt * osmooth if bardirnorm < ismoothlength_pt + osmoothlength_pt: ismoothlength_pt = bardirnorm * ismoothlength_pt / (ismoothlength_pt + osmoothlength_pt) osmoothlength_pt = bardirnorm * osmoothlength_pt / (ismoothlength_pt + osmoothlength_pt) q3 = (q2[0] + ismoothlength_pt * bardir[0], q2[1] + ismoothlength_pt * bardir[1]) q4 = (q5[0] - osmoothlength_pt * bardir[0], q5[1] - osmoothlength_pt * bardir[1]) # # P _O # / | \A2 # / A1\ \ # / \ B2C2________D2___________E2_______F2___G2 # \______________________________________ \ # B1,C1 D1 E1 F1 G1 \ # \ \ # \ \H2 # H1\_/I2 # I1 # # the halfbraces meet in P and A1: P = (0, height_pt) A1 = (0, height_pt - inner_cap_param * ithick_pt) # A2 is A1, shifted by the inner thickness A2 = (A1[0] + ithick_pt * cos_iangle, A1[1] + ithick_pt * sin_iangle) s, t = deformer.intersection(P, A2, (cos_slangle, sin_slangle), (sin_iangle, -cos_iangle)) O = (P[0] + s * cos_slangle, P[1] + s * sin_slangle) # from D1 to E1 is the straight part of the brace # also back from E2 to D1 D1 = (q3[0] + bthick_pt * bardir[1], q3[1] - bthick_pt * bardir[0]) D2 = (q3[0] - bthick_pt * bardir[1], q3[1] + bthick_pt * bardir[0]) E1 = (q4[0] + bthick_pt * bardir[1], q4[1] - bthick_pt * bardir[0]) E2 = (q4[0] - bthick_pt * bardir[1], q4[1] + bthick_pt * bardir[0]) # I1, I2 are the control points at the outer stroke I1 = (q6[0] - 0.5 * othick_pt * cos_oangle, q6[1] - 0.5 * othick_pt * sin_oangle) I2 = (q6[0] + 0.5 * othick_pt * cos_oangle, q6[1] + 0.5 * othick_pt * sin_oangle) # get the control points for the curved parts of the brace s, t = deformer.intersection(A1, D1, (sin_iangle, -cos_iangle), bardir) B1 = (D1[0] + t * bardir[0], D1[1] + t * bardir[1]) s, t = deformer.intersection(A2, D2, (sin_iangle, -cos_iangle), bardir) B2 = (D2[0] + t * bardir[0], D2[1] + t * bardir[1]) s, t = deformer.intersection(E1, I1, bardir, (-sin_oangle, cos_oangle)) G1 = (E1[0] + s * bardir[0], E1[1] + s * bardir[1]) s, t = deformer.intersection(E2, I2, bardir, (-sin_oangle, cos_oangle)) G2 = (E2[0] + s * bardir[0], E2[1] + s * bardir[1]) # at the inner strokes: use curvature zero at both ends C1 = B1 C2 = B2 # at the outer strokes: use curvature zero only at the connection to # the straight part F1 = (outerextracurved * G1[0] + (1 - outerextracurved) * E1[0], outerextracurved * G1[1] + (1 - outerextracurved) * E1[1]) F2 = (outerextracurved * G2[0] + (1 - outerextracurved) * E2[0], outerextracurved * G2[1] + (1 - outerextracurved) * E2[1]) # the tip of the outer stroke, endpoints of the bezier curve H1 = (I1[0] - outer_cap_param * othick_pt * sin_oangle, I1[1] + outer_cap_param * othick_pt * cos_oangle) H2 = (I2[0] - outer_cap_param * othick_pt * sin_oangle, I2[1] + outer_cap_param * othick_pt * cos_oangle) #for qq in [A1,B1,C1,D1,E1,F1,G1,H1,I1, # A2,B2,C2,D2,E2,F2,G2,H2,I2, # O,P # ]: # cc.fill(path.circle(qq[0], qq[1], 0.5), [color.rgb.green]) # now build the right halfbrace bracepath = path.path(path.moveto_pt(*A1)) bracepath.append(path.curveto_pt(B1[0], B1[1], C1[0], C1[1], D1[0], D1[1])) bracepath.append(path.lineto_pt(E1[0], E1[1])) bracepath.append(path.curveto_pt(F1[0], F1[1], G1[0], G1[1], H1[0], H1[1])) # the tip of the right halfbrace bracepath.append(path.curveto_pt(I1[0], I1[1], I2[0], I2[1], H2[0], H2[1])) # the rest of the right halfbrace bracepath.append(path.curveto_pt(G2[0], G2[1], F2[0], F2[1], E2[0], E2[1])) bracepath.append(path.lineto_pt(D2[0], D2[1])) bracepath.append(path.curveto_pt(C2[0], C2[1], B2[0], B2[1], A2[0], A2[1])) # the tip in the middle of the brace bracepath.append(path.curveto_pt(O[0], O[1], O[0], O[1], P[0], P[1])) return bracepath
def _halfbracepath_pt( self, length_pt, height_pt, ilength_pt, olength_pt, # <<< ithick_pt, othick_pt, bthick_pt, cos_iangle, sin_iangle, cos_oangle, sin_oangle, cos_slangle, sin_slangle): ismooth = self.innerstrokessmoothness osmooth = self.outerstrokessmoothness # these two parameters are not important enough to be seen outside inner_cap_param = 1.5 outer_cap_param = 2.5 outerextracurved = 0.6 # in (0, 1] # 1.0 will lead to F=G, the outer strokes will not be curved at their ends. # The smaller, the more curvature # build an orientation path (three straight lines) # # \q1 # / \ # / \ # _/ \______________________________________q5 # q2 q3 q4 \ # \ # \ # \q6 # # get the points for that: q1 = (0, height_pt - inner_cap_param * ithick_pt + 0.5 * ithick_pt / sin_iangle) q2 = (q1[0] + ilength_pt * sin_iangle, q1[1] - ilength_pt * cos_iangle) q6 = (length_pt, 0) q5 = (q6[0] - olength_pt * sin_oangle, q6[1] + olength_pt * cos_oangle) bardir = (q5[0] - q2[0], q5[1] - q2[1]) bardirnorm = math.hypot(*bardir) bardir = (bardir[0] / bardirnorm, bardir[1] / bardirnorm) ismoothlength_pt = ilength_pt * ismooth osmoothlength_pt = olength_pt * osmooth if bardirnorm < ismoothlength_pt + osmoothlength_pt: ismoothlength_pt = bardirnorm * ismoothlength_pt / ( ismoothlength_pt + osmoothlength_pt) osmoothlength_pt = bardirnorm * osmoothlength_pt / ( ismoothlength_pt + osmoothlength_pt) q3 = (q2[0] + ismoothlength_pt * bardir[0], q2[1] + ismoothlength_pt * bardir[1]) q4 = (q5[0] - osmoothlength_pt * bardir[0], q5[1] - osmoothlength_pt * bardir[1]) # # P _O # / | \A2 # / A1\ \ # / \ B2C2________D2___________E2_______F2___G2 # \______________________________________ \ # B1,C1 D1 E1 F1 G1 \ # \ \ # \ \H2 # H1\_/I2 # I1 # # the halfbraces meet in P and A1: P = (0, height_pt) A1 = (0, height_pt - inner_cap_param * ithick_pt) # A2 is A1, shifted by the inner thickness A2 = (A1[0] + ithick_pt * cos_iangle, A1[1] + ithick_pt * sin_iangle) s, t = deformer.intersection(P, A2, (cos_slangle, sin_slangle), (sin_iangle, -cos_iangle)) O = (P[0] + s * cos_slangle, P[1] + s * sin_slangle) # from D1 to E1 is the straight part of the brace # also back from E2 to D1 D1 = (q3[0] + bthick_pt * bardir[1], q3[1] - bthick_pt * bardir[0]) D2 = (q3[0] - bthick_pt * bardir[1], q3[1] + bthick_pt * bardir[0]) E1 = (q4[0] + bthick_pt * bardir[1], q4[1] - bthick_pt * bardir[0]) E2 = (q4[0] - bthick_pt * bardir[1], q4[1] + bthick_pt * bardir[0]) # I1, I2 are the control points at the outer stroke I1 = (q6[0] - 0.5 * othick_pt * cos_oangle, q6[1] - 0.5 * othick_pt * sin_oangle) I2 = (q6[0] + 0.5 * othick_pt * cos_oangle, q6[1] + 0.5 * othick_pt * sin_oangle) # get the control points for the curved parts of the brace s, t = deformer.intersection(A1, D1, (sin_iangle, -cos_iangle), bardir) B1 = (D1[0] + t * bardir[0], D1[1] + t * bardir[1]) s, t = deformer.intersection(A2, D2, (sin_iangle, -cos_iangle), bardir) B2 = (D2[0] + t * bardir[0], D2[1] + t * bardir[1]) s, t = deformer.intersection(E1, I1, bardir, (-sin_oangle, cos_oangle)) G1 = (E1[0] + s * bardir[0], E1[1] + s * bardir[1]) s, t = deformer.intersection(E2, I2, bardir, (-sin_oangle, cos_oangle)) G2 = (E2[0] + s * bardir[0], E2[1] + s * bardir[1]) # at the inner strokes: use curvature zero at both ends C1 = B1 C2 = B2 # at the outer strokes: use curvature zero only at the connection to # the straight part F1 = (outerextracurved * G1[0] + (1 - outerextracurved) * E1[0], outerextracurved * G1[1] + (1 - outerextracurved) * E1[1]) F2 = (outerextracurved * G2[0] + (1 - outerextracurved) * E2[0], outerextracurved * G2[1] + (1 - outerextracurved) * E2[1]) # the tip of the outer stroke, endpoints of the bezier curve H1 = (I1[0] - outer_cap_param * othick_pt * sin_oangle, I1[1] + outer_cap_param * othick_pt * cos_oangle) H2 = (I2[0] - outer_cap_param * othick_pt * sin_oangle, I2[1] + outer_cap_param * othick_pt * cos_oangle) #for qq in [A1,B1,C1,D1,E1,F1,G1,H1,I1, # A2,B2,C2,D2,E2,F2,G2,H2,I2, # O,P # ]: # cc.fill(path.circle(qq[0], qq[1], 0.5), [color.rgb.green]) # now build the right halfbrace bracepath = path.path(path.moveto_pt(*A1)) bracepath.append( path.curveto_pt(B1[0], B1[1], C1[0], C1[1], D1[0], D1[1])) bracepath.append(path.lineto_pt(E1[0], E1[1])) bracepath.append( path.curveto_pt(F1[0], F1[1], G1[0], G1[1], H1[0], H1[1])) # the tip of the right halfbrace bracepath.append( path.curveto_pt(I1[0], I1[1], I2[0], I2[1], H2[0], H2[1])) # the rest of the right halfbrace bracepath.append( path.curveto_pt(G2[0], G2[1], F2[0], F2[1], E2[0], E2[1])) bracepath.append(path.lineto_pt(D2[0], D2[1])) bracepath.append( path.curveto_pt(C2[0], C2[1], B2[0], B2[1], A2[0], A2[1])) # the tip in the middle of the brace bracepath.append(path.curveto_pt(O[0], O[1], O[0], O[1], P[0], P[1])) return bracepath