def enlarged(anormpath, enlargeby_pt, round): newnormsubpaths = [] for normsubpath in anormpath.normsubpaths: splitnormsubpathitems = normsubpath.normsubpathitems[:] # do splitting on a copy i = 0 while i < len(splitnormsubpathitems): if isinstance(splitnormsubpathitems[i], normpath.normcurve_pt) and splitnormsubpathitems[i].arclen_pt(normsubpath.epsilon) > 100: splitnormsubpathitems[i:i+1] = splitnormsubpathitems[i]._midpointsplit(normsubpath.epsilon) else: i += 1 newnormsubpathitems = [] for normsubpathitem in splitnormsubpathitems: # get old and new start and end points ts, te = normsubpathitem.trafo([0, 1]) xs, ys = ts.apply_pt(0, 0) nxs, nys = ts.apply_pt(0, -enlargeby_pt) xe, ye = te.apply_pt(0, 0) nxe, nye = te.apply_pt(0, -enlargeby_pt) if isinstance(normsubpathitem, normpath.normcurve_pt): # We should do not alter the sign. Could we do any better here? try: cs = 1/(normsubpathitem.curveradius_pt([0])[0] + enlargeby_pt) except ArithmeticError: cs = 0 try: ce = 1/(normsubpathitem.curveradius_pt([1])[0] + enlargeby_pt) except ArithmeticError: ce = 0 # this should be a function (in path?), not a method in a class # the parameter convention is quite different from other places ... bezierparams = deformer.normcurve_from_endgeometry_pt((nxs, nys), (nxe, nye), (ts.matrix[0][0], ts.matrix[1][0]), (te.matrix[0][0], te.matrix[1][0]), cs, ce) c.fill(path.circle_pt(bezierparams.x0_pt, bezierparams.y0_pt, 1), [color.rgb.blue]) c.fill(path.circle_pt(bezierparams.x3_pt, bezierparams.y3_pt, 1), [color.rgb.blue]) newnormpathitems = normpath.normcurve_pt(bezierparams.x0_pt, bezierparams.y0_pt, bezierparams.x1_pt, bezierparams.y1_pt, bezierparams.x2_pt, bezierparams.y2_pt, bezierparams.x3_pt, bezierparams.y3_pt) showtangent(newnormpathitems) # line alignment of bezier curves showcircle(newnormpathitems) # circle alignment of bezier curves else: # line newnormpathitems = path.normline_pt(nxs, nys, nxe, nye) if len(newnormsubpathitems): newnormsubpathitems.extend(connect(newnormsubpathitems[-1], newnormpathitems, round=round)) newnormsubpathitems.append(newnormpathitems) if normsubpath.closed: newnormsubpathitems.extend(connect(newnormsubpathitems[-1], newnormsubpathitems[0], round=round)) newnormsubpaths.append(path.normsubpath(newnormsubpathitems, normsubpath.closed)) return normpath.normpath(newnormsubpaths)
def testparallel_2(c): # a case with several dangers: # - double intersection pairs # - intersections with angle 0 # - inner intersections that have to be cut away by _between_paths move = (10, 2) nsp = normpath.normsubpath( [ # <<< #ormpath.normline_pt(-87.5005, 184.037, -86.2747, 184.198), #ormpath.normline_pt(-86.2747, 184.198, -85.0394, 184.252), #ormpath.normline_pt(-85.0394, 184.252, -83.8041, 184.198), #ormpath.normline_pt(-83.8041, 184.198, -82.5782, 184.037), #ormpath.normline_pt(-82.5782, 184.037, -81.3711, 183.769), #ormpath.normline_pt(-81.3711, 183.769, -80.1918, 183.397), #ormpath.normline_pt(-80.1918, 183.397, -79.0495, 182.924), #ormpath.normline_pt(-79.0495, 182.924, -77.9528, 182.353), #ormpath.normline_pt(-77.9528, 182.353, -76.9099, 181.689), #ormpath.normline_pt(-76.9099, 181.689, -75.929, 180.936), #ormpath.normline_pt(-75.929, 180.936, -75.0174, 180.101), #ormpath.normline_pt(-75.0174, 180.101, -74.1821, 179.189), #ormpath.normline_pt(-74.1821, 179.189, -73.4293, 178.208), #ormpath.normline_pt(-73.4293, 178.208, -72.765, 177.165), #ormpath.normline_pt(-72.765, 177.165, -72.1941, 176.069), #ormpath.normline_pt(-72.1941, 176.069, -71.7209, 174.926), #ormpath.normline_pt(-71.7209, 174.926, -71.3491, 173.747), #ormpath.normline_pt(-71.3491, 173.747, -71.0815, 172.54), #ormpath.normline_pt(-71.0815, 172.54, -70.9201, 171.314), #ormpath.normline_pt(-70.9201, 171.314, -70.8661, 170.079), #ormpath.normline_pt(-70.8661, 170.079, -70.9201, 168.843), #ormpath.normline_pt(-70.9201, 168.843, -71.0815, 167.618), #ormpath.normline_pt(-71.0815, 167.618, -71.3491, 166.41), #ormpath.normline_pt(-71.3491, 166.41, -71.7209, 165.231), #ormpath.normline_pt(-71.7209, 165.231, -72.1941, 164.089), #ormpath.normline_pt(-72.1941, 164.089, -72.765, 162.992), #ormpath.normline_pt(-72.765, 162.992, -73.4293, 161.949), #ormpath.normline_pt(-73.4293, 161.949, -74.1821, 160.968), #ormpath.normline_pt(-74.1821, 160.968, -75.0174, 160.057), #ormpath.normline_pt(-75.0174, 160.057, -75.929, 159.221), #ormpath.normline_pt(-75.929, 159.221, -76.9099, 158.469), #ormpath.normline_pt(-76.9099, 158.469, -77.9528, 157.804), #ormpath.normline_pt(-77.9528, 157.804, -77.9528, -28.3465), #ormpath.normline_pt(-77.9528, -28.3465, -77.9797, -28.9641), #ormpath.normline_pt(-77.9797, -28.9641, -78.0604, -29.577), #ormpath.normline_pt(-78.0604, -29.577, -78.1942, -30.1806), #ormpath.normline_pt(-78.1942, -30.1806, -78.3801, -30.7702), #ormpath.normline_pt(-78.3801, -30.7702, -78.6167, -31.3414), #ormpath.normline_pt(-78.6167, -31.3414, -78.9022, -31.8897), #ormpath.normline_pt(-78.9022, -31.8897, -79.2344, -32.4111), #ormpath.normline_pt(-79.2344, -32.4111, -79.6107, -32.9016), #ormpath.normline_pt(-79.6107, -32.9016, -80.0284, -33.3574), #ormpath.normline_pt(-80.0284, -33.3574, -80.4842, -33.7751), #ormpath.normline_pt(-80.4842, -33.7751, -80.9747, -34.1514), #ormpath.normline_pt(-80.9747, -34.1514, -81.4961, -34.4836), #ormpath.normline_pt(-81.4961, -34.4836, -82.0444, -34.7691), #ormpath.normline_pt(-82.0444, -34.7691, -82.6156, -35.0057), #ormpath.normline_pt(-82.6156, -35.0057, -83.2052, -35.1916), #ormpath.normline_pt(-83.2052, -35.1916, -83.8088, -35.3254), #ormpath.normline_pt(-83.8088, -35.3254, -84.3307, -35.3941), #ormpath.normline_pt(-84.3307, -35.3941, -84.3307, -169.37), #ormpath.normline_pt(-84.3307, -169.37, -28.423, -169.37), #ormpath.normline_pt(-28.423, -169.37, 0, -156.252), #ormpath.normline_pt(0, -156.252, 0, -157.813), #ormpath.normline_pt(0, -157.813, -28.1117, -170.787), #ormpath.normline_pt(-28.1117, -170.787, -150, -170.787), normpath.normline_pt(-150, -170.787, -361.417, -170.787), # start normpath.normline_pt(-361.417, -170.787, -361.417, -169.37), normpath.normline_pt(-361.417, -169.37, -299.055, -169.37), normpath.normline_pt(-299.055, -169.37, -299.055, -141.732), normpath.normline_pt(-299.055, -141.732, -297.638, -141.732), normpath.normline_pt(-297.638, -141.732, -297.638, -143.15), normpath.normline_pt(-297.638, -143.15, -297.638, -169.37), normpath.normline_pt(-297.638, -169.37, -270.709, -169.37), normpath.normline_pt(-270.709, -169.37, -270.709, -143.15), normpath.normline_pt(-270.709, -143.15, -297.638, -143.15), normpath.normline_pt(-297.638, -143.15, -297.638, -141.732), normpath.normline_pt(-297.638, -141.732, -284.882, -141.732), normpath.normline_pt(-284.882, -141.732, -284.882, -113.386), normpath.normline_pt(-284.882, -113.386, -283.465, -113.386), normpath.normline_pt(-283.465, -113.386, -283.465, -114.803), normpath.normline_pt(-283.465, -114.803, -283.465, -141.732), normpath.normline_pt(-283.465, -141.732, -269.291, -141.732), normpath.normline_pt(-269.291, -141.732, -269.291, -169.37), normpath.normline_pt(-269.291, -169.37, -242.362, -169.37), normpath.normline_pt(-242.362, -169.37, -242.362, -141.732), normpath.normline_pt(-242.362, -141.732, -240.945, -141.732), normpath.normline_pt(-240.945, -141.732, -240.945, -143.15), normpath.normline_pt(-240.945, -143.15, -240.945, -169.37), normpath.normline_pt(-240.945, -169.37, -214.016, -169.37), normpath.normline_pt(-214.016, -169.37, -214.016, -143.15), normpath.normline_pt(-214.016, -143.15, -240.945, -143.15), normpath.normline_pt(-240.945, -143.15, -240.945, -141.732), normpath.normline_pt(-240.945, -141.732, -228.189, -141.732), normpath.normline_pt(-228.189, -141.732, -228.189, -114.803), normpath.normline_pt(-228.189, -114.803, -283.465, -114.803), normpath.normline_pt(-283.465, -114.803, -283.465, -113.386), normpath.normline_pt(-283.465, -113.386, -226.772, -113.386), normpath.normline_pt(-226.772, -113.386, -226.772, -141.732), normpath.normline_pt(-226.772, -141.732, -212.598, -141.732), normpath.normline_pt(-212.598, -141.732, -212.598, -169.37), normpath.normline_pt(-212.598, -169.37, -150, -169.37), # end #ormpath.normline_pt(-150, -169.37, -85.748, -169.37), #ormpath.normline_pt(-85.748, -169.37, -85.748, -35.3941), #ormpath.normline_pt(-85.748, -35.3941, -86.2699, -35.3254), #ormpath.normline_pt(-86.2699, -35.3254, -86.8735, -35.1916), #ormpath.normline_pt(-86.8735, -35.1916, -87.4631, -35.0057), #ormpath.normline_pt(-87.4631, -35.0057, -88.0343, -34.7691), #ormpath.normline_pt(-88.0343, -34.7691, -88.5827, -34.4836), #ormpath.normline_pt(-88.5827, -34.4836, -89.1041, -34.1514), #ormpath.normline_pt(-89.1041, -34.1514, -89.5946, -33.7751), #ormpath.normline_pt(-89.5946, -33.7751, -90.0504, -33.3574), #ormpath.normline_pt(-90.0504, -33.3574, -90.468, -32.9016), #ormpath.normline_pt(-90.468, -32.9016, -90.8444, -32.4111), #ormpath.normline_pt(-90.8444, -32.4111, -91.1765, -31.8897), #ormpath.normline_pt(-91.1765, -31.8897, -91.462, -31.3414), #ormpath.normline_pt(-91.462, -31.3414, -91.6986, -30.7702), #ormpath.normline_pt(-91.6986, -30.7702, -91.8845, -30.1806), #ormpath.normline_pt(-91.8845, -30.1806, -92.0183, -29.577), #ormpath.normline_pt(-92.0183, -29.577, -92.099, -28.9641), #ormpath.normline_pt(-92.099, -28.9641, -92.126, -28.3465), #ormpath.normline_pt(-92.126, -28.3465, -92.126, 157.804), #ormpath.normline_pt(-92.126, 157.804, -93.1688, 158.469), #ormpath.normline_pt(-93.1688, 158.469, -94.1498, 159.221), #ormpath.normline_pt(-94.1498, 159.221, -95.0613, 160.057), #ormpath.normline_pt(-95.0613, 160.057, -95.8967, 160.968), #ormpath.normline_pt(-95.8967, 160.968, -96.6494, 161.949), #ormpath.normline_pt(-96.6494, 161.949, -97.3138, 162.992), #ormpath.normline_pt(-97.3138, 162.992, -97.8847, 164.089), #ormpath.normline_pt(-97.8847, 164.089, -98.3578, 165.231), #ormpath.normline_pt(-98.3578, 165.231, -98.7297, 166.41), #ormpath.normline_pt(-98.7297, 166.41, -98.9973, 167.618), #ormpath.normline_pt(-98.9973, 167.618, -99.1587, 168.843), #ormpath.normline_pt(-99.1587, 168.843, -99.2126, 170.079), #ormpath.normline_pt(-99.2126, 170.079, -99.1587, 171.314), #ormpath.normline_pt(-99.1587, 171.314, -98.9973, 172.54), #ormpath.normline_pt(-98.9973, 172.54, -98.7297, 173.747), #ormpath.normline_pt(-98.7297, 173.747, -98.3578, 174.926), #ormpath.normline_pt(-98.3578, 174.926, -97.8847, 176.069), #ormpath.normline_pt(-97.8847, 176.069, -97.3138, 177.165), #ormpath.normline_pt(-97.3138, 177.165, -96.6494, 178.208), #ormpath.normline_pt(-96.6494, 178.208, -95.8967, 179.189), #ormpath.normline_pt(-95.8967, 179.189, -95.0613, 180.101), #ormpath.normline_pt(-95.0613, 180.101, -94.1498, 180.936), #ormpath.normline_pt(-94.1498, 180.936, -93.1688, 181.689), #ormpath.normline_pt(-93.1688, 181.689, -92.126, 182.353), #ormpath.normline_pt(-92.126, 182.353, -91.0292, 182.924), #ormpath.normline_pt(-91.0292, 182.924, -89.8869, 183.397), #ormpath.normline_pt(-89.8869, 183.397, -88.7077, 183.769), #ormpath.normline_pt(-88.7077, 183.769, -87.5005, 184.037), ], closed=1) # >>> p = normpath.normpath([nsp]) c.stroke(p, [trafo.translate(*move)]) hard_test(c, p, 0.47504345 - 5 * normpath._epsilon, parallel(0.0), move, "Y", checklens=[[37, 14], [37, 14], [7, 7], [7, 7]]) hard_test(c, p, 0.47504345 + 5 * normpath._epsilon, parallel(0.0), move, "Y", checklens=[[37, 7], [37, 7], [7, 7, 7], [7, 7, 7]]) hard_test(c, p, 0.5, parallel(0.0), move, "Y", checklens=[[36, 7], [36, 7], [6, 5, 6, 3, 7, 3], [6, 3, 7, 3, 5, 6]]) hard_test(c, p, 0.6125, parallel(0.0), move, "Y", checklens=[[35], [35], [3], [3]]) hard_test(c, p, 0.6130, parallel(0.0), move, "Y", checklens=[[35], [35], [], []]) # a path of two subpaths: # and with inner intersections to be cut away by _between_paths move = (0, 0) p = path.circle(-6, 0, 2) p += path.path(path.moveto(0, 0), path.curveto(0, 16, -11, 5, 5, 5)) p += path.path(path.lineto(5, 4), path.lineto(7, 4), path.lineto(7, 6), path.lineto(4, 6), path.lineto(4, 7), path.lineto(5, 7), path.lineto(3, 1), path.closepath()) p = p.transformed(trafo.scale(0.5)).normpath() hard_test(c, p, 0.05, parallel(0.0), move, "Z", checklens=[[10, 2, 8], [9, 2, 10], [13, 4, 4], [13, 4, 4]]) hard_test(c, p, 0.3, parallel(0.0), move, "Z", checklens=[[10, 4, 5], [4, 6, 10], [13, 4], [13, 4]]) hard_test(c, p, 0.6, parallel(0.0), move, "Z", checklens=[[], [], [13, 4], [13, 4]])
def testparallel_1(c): # HARD TESTS of elementary geometry: # # test for correct skipping of short ugly pieces: move = (-2, 0) p = path.path(path.moveto(0, 1), path.lineto(10, 0.3), path.lineto(12, 0), path.lineto(0, 0)) p.append(path.closepath()) hard_test(c, p, 0.1, parallel(0.0), move, "A", checklens=[[15], [15], [4], [4]]) hard_test(c, p, 0.25, parallel(0.0, sharpoutercorners=True), move, "A", checklens=[[12], [12], [3], [3]]) hard_test(c, p, 0.55, parallel(0.0), move, "A", checklens=[[15], [15], [], []]) # test non-intersecting/too short neighbouring pathels move = (0, 4) p = path.curve(0, 0, 0, 1, 1, 2, 2, 0) p.append(path.lineto(2.1, 0.1)) p.append(path.lineto(1.6, -2)) p.append(path.lineto(2.1, -2)) p.append(path.lineto(-0.15, 0)) p.append(path.closepath()) hard_test(c, p, 0.02, parallel(0.0, sharpoutercorners=1), move, "B", checklens=[[3], [3], [11], [11]]) hard_test(c, p, 0.06, parallel(0.0), move, "B", checklens=[[3], [3], [10], [ 9 ]]) # difference is due to rounding in path._arctobeziers hard_test(c, p, 0.3, parallel(0.0), move, "B", checklens=[[25], [25], [5], [5]]) hard_test(c, p, 0.3, parallel(0.0, sharpoutercorners=1), move, "B", checklens=[[22], [22], [5], [5]]) # test extreme precision: move = (3.5, 2) p = path.curve(0, 0, 0, 1, 1, 1, 1, 0) p.append(path.closepath()) hard_test(c, p, 0.1, parallel(0.0), move, "C", checklens=[[8], [8], [2], [2]]) hard_test(c, p, 0.1, parallel(0.0, relerr=1e-15, checkdistanceparams=[0.5]), move, "C", checklens=[[23], [23], [15], [15]]) # test for numeric instabilities: move = (6, 2) p = path.curve(0, 0, 1, 1, 1, 1, 2, 0) p.append(path.closepath()) hard_test(c, p, 0.1, parallel(0.0, relerr=0.15, checkdistanceparams=[0.5]), move, "D", checklens=[[11], [11], [3], [3]]) hard_test(c, p, 0.3, parallel(0.0), move, "D", checklens=[[11], [11], [3], [3]]) # test for an empty parallel path: move = (5, 5) p = path.circle(0, 0, 0.5).normpath() nspitems = [ nspitem for nspitem in p[0] if isinstance(nspitem, normpath.normcurve_pt) ] nspitems[-1] = nspitems[-1].modifiedend_pt(*nspitems[0].atbegin_pt()) p = normpath.normpath([normpath.normsubpath(nspitems, closed=True)]) hard_test(c, p, 0.55, parallel(0.0), move, "E", checklens=[[], [], [9], [9]]) hard_test(c, p, 0.4999, parallel(0.0, relerr=1.0e-15), move, "E", checklens=[[1, 14, 8], [1, 14], [17], [17]]) # a degenerate path: move = (13, 3) p = path.curve(0, 0, 0, -5, 0, 1, 0, 0.5) hard_test(c, p, 0.10, parallel(0.0, dointersection=False), move, "F", dotests=[True, True, False, False], checklens=[[13], [12], [13], [12]]) hard_test(c, p, 0.13, parallel(0.0, dointersection=False), move, "F", dotests=[False, False, True, True], checklens=[[13], [12], [13], [12]]) # test for too big curvatures in the middle: move = (9, 2.5) p = path.curve(0, 0, 1, 1, 1, 1, 2, 0) hard_test(c, p, 0.4, parallel(0.0, relerr=1.0e-2), move, "G", checklens=[[2], [2], [4], [4]]) hard_test(c, p, 0.6, parallel(0.0, relerr=1.0e-2), move, "G", checklens=[[2], [2], [4], [4]]) hard_test(c, p, 0.8, parallel(0.0, relerr=1.0e-2), move, "G", checklens=[[2], [2], [4], [4]]) hard_test(c, p, 1.7, parallel(0.0, relerr=1.0e-2), move, "G", checklens=[[2], [2], [1, 1], [1, 1]]) # deformation of the deformation: move = (11, 6) p = path.curve(-1, 0, 0, 1, 0, 1, 1, 0).normpath() c.stroke(p, [trafo.translate(*move), color.gray(0.8)]) dist = unit.u_pt / p.curvature_pt([normpath.normpathparam(p, 0, 0.5)])[0] p = parallel(dist, relerr=1.0e-2, dointersection=0).deform(p) assert len(p) == 2 assert len(p[0]) == len(p[1]) == 2 c.stroke(p, [trafo.translate(*move), color.gray(0.8)]) hard_test(c, p, -dist, parallel(0.0), move, "H", checklens=[[4], [4], [2], [2]]) # test for infinite curvature in the middle: move = (11, 8.5) p = path.curve(0, 0, 1, 1, 0, 1, 1, 0).normpath() hard_test(c, p, 0.2, parallel(0.0), move, "I", checklens=[[1, 1], [1, 1], [2], [2]]) hard_test(c, p, 1.5, parallel(0.0), move, "I", checklens=[[1, 1], [1, 1], [7], [7]]) #ard_test(c, p, 5.0, parallel(0.0), move, "I", checklens=[[],[],[7],[7]]) # test for infinite curvature at the end: move = (-2, 13) p = path.curve(0, 0, 0.5, 0.5, 0.75, 0.5, 0.75, 0.5) hard_test(c, p, 0.1, parallel(0.0, relerr=1.0e-4), move, "J", checklens=[[5], [5], [5], [5]]) # test for infinite curvature when the path goes on # XXX this is not correctly detected if rlineto(1,0). Expect two nsp p.append(path.rlineto(0, 1)) hard_test(c, p, 0.22, parallel(0.0, relerr=1.0e-4), move, "J", checklens=[[4], [4], [3, 1], [1, 3]]) # test for too big curvature in the middle, the non-intersecting case move = (0, 8) p = path.curve(-1, -1, 4, 4, -4, 4, 1, -1).normpath() dist = unit.u_pt * (1.0 / p.curvature_pt([normpath.normpathparam(p, 0, 0.5)])[0]) hard_test(c, p, 1.5 * dist, parallel(0.0, dointersection=False), move, "K", checklens=[[1, 1], [1, 1], [2], [2]]) hard_test(c, p, dist + normpath._epsilon, parallel(0.0, dointersection=False, relerr=1.0e-5), move, "K", checklens=[[11, 11], [11, 11], [16], [16]]) hard_test(c, p, dist + 0 * normpath._epsilon, parallel(0.0, dointersection=False, relerr=1.0e-5), move, "K", checklens=[[22], [22], [16], [16]]) # what is to be done with the arcs running around corners? # for dist=1.1 they do not even intersect with the original path: # TODO move = (8, 14) p = path.rect(0, 0, 1, 1).normpath() hard_test(c, p, 1.1, parallel(0.0), move, "L", dotests=[True, True, False, False], checklens=[[20], [20], None, None]) hard_test(c, p, 0.55, parallel(0.0), move, "L", dotests=[True, True, False, False], checklens=[[28], [28], None, None]) # very small lines approximating a curve # make sure that there is no "dust" remaining from the many intersections move = (3, 9) N = 12 angle = 0.5 * math.pi / (N - 1.0) p = path.path(path.moveto(0, 0)) for n in range(N): p.append(path.lineto(2 + math.sin(n * angle), 1 - math.cos(n * angle))) p.append(path.rlineto(0, 1)) p.append(path.rlineto(2, 0)) p.append(path.rlineto(0, -2)) p = p.transformed(trafo.translate(0, 0.05)) p = p << p.transformed(trafo.scale(1, -1)).reversed() hard_test(c, p, 0.6, parallel(0.0), move, "M", checklens=[[43], [43], [29], [29]]) # intersections where paths are parallel (in the middle of a nsp-item) move = (4, 15) c.text(move[0], move[1] + 0.2, "N") tr = trafo.translate(*move) par = parallel(0.1) par.dist_pt = unit.topt(par.distance) c1 = path.curve(-2, -1, -2, 1, 2, -1, 2, 1).transformed(tr).normpath() c2 = path.curve(-2, -1, -2, 1 / 3.0, 2, 1 / 3.0, 2, -1).transformed(tr).normpath() l = path.line(-2, 0, 2, 0).transformed(tr).normpath() for p in [c1, c2, l]: c.stroke(p) p = (c1 + l).normpath() try: par._can_continue(mynormpathparam(p, 0, 0, 0.5), mynormpathparam(p, 1, 0, 0.5)) except IntersectionError as e: assert str( e ) == "Cannot determine whether curves intersect (parallel and equally curved)" p = c2 + l assert par._can_continue(mynormpathparam(p, 0, 0, 0.5), mynormpathparam(p, 1, 0, 0.5)) p = c2 + l.reversed() assert par._can_continue(mynormpathparam(p, 0, 0, 0.5), mynormpathparam(p, 1, 0, 0.5)) p = c2.reversed() + l assert not par._can_continue(mynormpathparam(p, 0, 0, 0.5), mynormpathparam(p, 1, 0, 0.5)) p = c2.reversed() + l.reversed() assert not par._can_continue(mynormpathparam(p, 0, 0, 0.5), mynormpathparam(p, 1, 0, 0.5)) p = c1 + c2 assert not par._can_continue(mynormpathparam(p, 0, 0, 0.5), mynormpathparam(p, 1, 0, 0.5)) p = c2 + c1 assert par._can_continue(mynormpathparam(p, 0, 0, 0.5), mynormpathparam(p, 1, 0, 0.5)) # intersections where paths are parallel (between nsp-items) c11, c12 = c1.split([normpath.normpathparam(c1, 0, 0.5)]) c21, c22 = c2.split([normpath.normpathparam(c2, 0, 0.5)]) l1, l2 = l.split([normpath.normpathparam(l, 0, 0.5)]) p = (c21 << l2 + l1 << c22).normpath() # curve-line + line-curve assert par._can_continue(mynormpathparam(p, 1, 0, 1), mynormpathparam(p, 0, 1, 0)) # line -> line assert not par._can_continue(mynormpathparam(p, 0, 0, 1), mynormpathparam(p, 1, 1, 0)) # curve -> curve # intersections where paths are parallel (in the middle of a nsp-item) move = (12, 13) p1 = path.path(path.moveto(0, 0), path.curveto(0, 3, 1, 5, 1, 0)).normpath() params1, params2 = p1.intersect(path.line(0.5, -1, 0.5, 5)) p11, p12 = p1.split(params1) p11.append(path.rlineto(0, -2)) p = p11 << p12 p.append(path.closepath()) hard_test(c, p, 0.55, parallel(0.0), move, "O", dotests=[True, True, False, False], checklens=[[10], [10], None, None]) # jump to too large curvature between nspitems move = (-2, 17) p = path.path(path.moveto(0, 0), path.arc(2, 0.5, 0.5, -90, 90), path.lineto(0, 1)).normpath() hard_test(c, p, 0.55, parallel(0.0), move, "P", dotests=[True, True, True, True], checklens=[[1, 1], [1, 1], [7], [7]])
def testparallel_2(c): # a case with several dangers: # - double intersection pairs # - intersections with angle 0 # - inner intersections that have to be cut away by _between_paths move = (10, 2) nsp = normpath.normsubpath( [ # <<< #ormpath.normline_pt(-87.5005, 184.037, -86.2747, 184.198), #ormpath.normline_pt(-86.2747, 184.198, -85.0394, 184.252), #ormpath.normline_pt(-85.0394, 184.252, -83.8041, 184.198), #ormpath.normline_pt(-83.8041, 184.198, -82.5782, 184.037), #ormpath.normline_pt(-82.5782, 184.037, -81.3711, 183.769), #ormpath.normline_pt(-81.3711, 183.769, -80.1918, 183.397), #ormpath.normline_pt(-80.1918, 183.397, -79.0495, 182.924), #ormpath.normline_pt(-79.0495, 182.924, -77.9528, 182.353), #ormpath.normline_pt(-77.9528, 182.353, -76.9099, 181.689), #ormpath.normline_pt(-76.9099, 181.689, -75.929, 180.936), #ormpath.normline_pt(-75.929, 180.936, -75.0174, 180.101), #ormpath.normline_pt(-75.0174, 180.101, -74.1821, 179.189), #ormpath.normline_pt(-74.1821, 179.189, -73.4293, 178.208), #ormpath.normline_pt(-73.4293, 178.208, -72.765, 177.165), #ormpath.normline_pt(-72.765, 177.165, -72.1941, 176.069), #ormpath.normline_pt(-72.1941, 176.069, -71.7209, 174.926), #ormpath.normline_pt(-71.7209, 174.926, -71.3491, 173.747), #ormpath.normline_pt(-71.3491, 173.747, -71.0815, 172.54), #ormpath.normline_pt(-71.0815, 172.54, -70.9201, 171.314), #ormpath.normline_pt(-70.9201, 171.314, -70.8661, 170.079), #ormpath.normline_pt(-70.8661, 170.079, -70.9201, 168.843), #ormpath.normline_pt(-70.9201, 168.843, -71.0815, 167.618), #ormpath.normline_pt(-71.0815, 167.618, -71.3491, 166.41), #ormpath.normline_pt(-71.3491, 166.41, -71.7209, 165.231), #ormpath.normline_pt(-71.7209, 165.231, -72.1941, 164.089), #ormpath.normline_pt(-72.1941, 164.089, -72.765, 162.992), #ormpath.normline_pt(-72.765, 162.992, -73.4293, 161.949), #ormpath.normline_pt(-73.4293, 161.949, -74.1821, 160.968), #ormpath.normline_pt(-74.1821, 160.968, -75.0174, 160.057), #ormpath.normline_pt(-75.0174, 160.057, -75.929, 159.221), #ormpath.normline_pt(-75.929, 159.221, -76.9099, 158.469), #ormpath.normline_pt(-76.9099, 158.469, -77.9528, 157.804), #ormpath.normline_pt(-77.9528, 157.804, -77.9528, -28.3465), #ormpath.normline_pt(-77.9528, -28.3465, -77.9797, -28.9641), #ormpath.normline_pt(-77.9797, -28.9641, -78.0604, -29.577), #ormpath.normline_pt(-78.0604, -29.577, -78.1942, -30.1806), #ormpath.normline_pt(-78.1942, -30.1806, -78.3801, -30.7702), #ormpath.normline_pt(-78.3801, -30.7702, -78.6167, -31.3414), #ormpath.normline_pt(-78.6167, -31.3414, -78.9022, -31.8897), #ormpath.normline_pt(-78.9022, -31.8897, -79.2344, -32.4111), #ormpath.normline_pt(-79.2344, -32.4111, -79.6107, -32.9016), #ormpath.normline_pt(-79.6107, -32.9016, -80.0284, -33.3574), #ormpath.normline_pt(-80.0284, -33.3574, -80.4842, -33.7751), #ormpath.normline_pt(-80.4842, -33.7751, -80.9747, -34.1514), #ormpath.normline_pt(-80.9747, -34.1514, -81.4961, -34.4836), #ormpath.normline_pt(-81.4961, -34.4836, -82.0444, -34.7691), #ormpath.normline_pt(-82.0444, -34.7691, -82.6156, -35.0057), #ormpath.normline_pt(-82.6156, -35.0057, -83.2052, -35.1916), #ormpath.normline_pt(-83.2052, -35.1916, -83.8088, -35.3254), #ormpath.normline_pt(-83.8088, -35.3254, -84.3307, -35.3941), #ormpath.normline_pt(-84.3307, -35.3941, -84.3307, -169.37), #ormpath.normline_pt(-84.3307, -169.37, -28.423, -169.37), #ormpath.normline_pt(-28.423, -169.37, 0, -156.252), #ormpath.normline_pt(0, -156.252, 0, -157.813), #ormpath.normline_pt(0, -157.813, -28.1117, -170.787), #ormpath.normline_pt(-28.1117, -170.787, -150, -170.787), normpath.normline_pt(-150, -170.787, -361.417, -170.787), # start normpath.normline_pt(-361.417, -170.787, -361.417, -169.37), normpath.normline_pt(-361.417, -169.37, -299.055, -169.37), normpath.normline_pt(-299.055, -169.37, -299.055, -141.732), normpath.normline_pt(-299.055, -141.732, -297.638, -141.732), normpath.normline_pt(-297.638, -141.732, -297.638, -143.15), normpath.normline_pt(-297.638, -143.15, -297.638, -169.37), normpath.normline_pt(-297.638, -169.37, -270.709, -169.37), normpath.normline_pt(-270.709, -169.37, -270.709, -143.15), normpath.normline_pt(-270.709, -143.15, -297.638, -143.15), normpath.normline_pt(-297.638, -143.15, -297.638, -141.732), normpath.normline_pt(-297.638, -141.732, -284.882, -141.732), normpath.normline_pt(-284.882, -141.732, -284.882, -113.386), normpath.normline_pt(-284.882, -113.386, -283.465, -113.386), normpath.normline_pt(-283.465, -113.386, -283.465, -114.803), normpath.normline_pt(-283.465, -114.803, -283.465, -141.732), normpath.normline_pt(-283.465, -141.732, -269.291, -141.732), normpath.normline_pt(-269.291, -141.732, -269.291, -169.37), normpath.normline_pt(-269.291, -169.37, -242.362, -169.37), normpath.normline_pt(-242.362, -169.37, -242.362, -141.732), normpath.normline_pt(-242.362, -141.732, -240.945, -141.732), normpath.normline_pt(-240.945, -141.732, -240.945, -143.15), normpath.normline_pt(-240.945, -143.15, -240.945, -169.37), normpath.normline_pt(-240.945, -169.37, -214.016, -169.37), normpath.normline_pt(-214.016, -169.37, -214.016, -143.15), normpath.normline_pt(-214.016, -143.15, -240.945, -143.15), normpath.normline_pt(-240.945, -143.15, -240.945, -141.732), normpath.normline_pt(-240.945, -141.732, -228.189, -141.732), normpath.normline_pt(-228.189, -141.732, -228.189, -114.803), normpath.normline_pt(-228.189, -114.803, -283.465, -114.803), normpath.normline_pt(-283.465, -114.803, -283.465, -113.386), normpath.normline_pt(-283.465, -113.386, -226.772, -113.386), normpath.normline_pt(-226.772, -113.386, -226.772, -141.732), normpath.normline_pt(-226.772, -141.732, -212.598, -141.732), normpath.normline_pt(-212.598, -141.732, -212.598, -169.37), normpath.normline_pt(-212.598, -169.37, -150, -169.37), # end #ormpath.normline_pt(-150, -169.37, -85.748, -169.37), #ormpath.normline_pt(-85.748, -169.37, -85.748, -35.3941), #ormpath.normline_pt(-85.748, -35.3941, -86.2699, -35.3254), #ormpath.normline_pt(-86.2699, -35.3254, -86.8735, -35.1916), #ormpath.normline_pt(-86.8735, -35.1916, -87.4631, -35.0057), #ormpath.normline_pt(-87.4631, -35.0057, -88.0343, -34.7691), #ormpath.normline_pt(-88.0343, -34.7691, -88.5827, -34.4836), #ormpath.normline_pt(-88.5827, -34.4836, -89.1041, -34.1514), #ormpath.normline_pt(-89.1041, -34.1514, -89.5946, -33.7751), #ormpath.normline_pt(-89.5946, -33.7751, -90.0504, -33.3574), #ormpath.normline_pt(-90.0504, -33.3574, -90.468, -32.9016), #ormpath.normline_pt(-90.468, -32.9016, -90.8444, -32.4111), #ormpath.normline_pt(-90.8444, -32.4111, -91.1765, -31.8897), #ormpath.normline_pt(-91.1765, -31.8897, -91.462, -31.3414), #ormpath.normline_pt(-91.462, -31.3414, -91.6986, -30.7702), #ormpath.normline_pt(-91.6986, -30.7702, -91.8845, -30.1806), #ormpath.normline_pt(-91.8845, -30.1806, -92.0183, -29.577), #ormpath.normline_pt(-92.0183, -29.577, -92.099, -28.9641), #ormpath.normline_pt(-92.099, -28.9641, -92.126, -28.3465), #ormpath.normline_pt(-92.126, -28.3465, -92.126, 157.804), #ormpath.normline_pt(-92.126, 157.804, -93.1688, 158.469), #ormpath.normline_pt(-93.1688, 158.469, -94.1498, 159.221), #ormpath.normline_pt(-94.1498, 159.221, -95.0613, 160.057), #ormpath.normline_pt(-95.0613, 160.057, -95.8967, 160.968), #ormpath.normline_pt(-95.8967, 160.968, -96.6494, 161.949), #ormpath.normline_pt(-96.6494, 161.949, -97.3138, 162.992), #ormpath.normline_pt(-97.3138, 162.992, -97.8847, 164.089), #ormpath.normline_pt(-97.8847, 164.089, -98.3578, 165.231), #ormpath.normline_pt(-98.3578, 165.231, -98.7297, 166.41), #ormpath.normline_pt(-98.7297, 166.41, -98.9973, 167.618), #ormpath.normline_pt(-98.9973, 167.618, -99.1587, 168.843), #ormpath.normline_pt(-99.1587, 168.843, -99.2126, 170.079), #ormpath.normline_pt(-99.2126, 170.079, -99.1587, 171.314), #ormpath.normline_pt(-99.1587, 171.314, -98.9973, 172.54), #ormpath.normline_pt(-98.9973, 172.54, -98.7297, 173.747), #ormpath.normline_pt(-98.7297, 173.747, -98.3578, 174.926), #ormpath.normline_pt(-98.3578, 174.926, -97.8847, 176.069), #ormpath.normline_pt(-97.8847, 176.069, -97.3138, 177.165), #ormpath.normline_pt(-97.3138, 177.165, -96.6494, 178.208), #ormpath.normline_pt(-96.6494, 178.208, -95.8967, 179.189), #ormpath.normline_pt(-95.8967, 179.189, -95.0613, 180.101), #ormpath.normline_pt(-95.0613, 180.101, -94.1498, 180.936), #ormpath.normline_pt(-94.1498, 180.936, -93.1688, 181.689), #ormpath.normline_pt(-93.1688, 181.689, -92.126, 182.353), #ormpath.normline_pt(-92.126, 182.353, -91.0292, 182.924), #ormpath.normline_pt(-91.0292, 182.924, -89.8869, 183.397), #ormpath.normline_pt(-89.8869, 183.397, -88.7077, 183.769), #ormpath.normline_pt(-88.7077, 183.769, -87.5005, 184.037), ], closed=1) # >>> p = normpath.normpath([nsp]) c.stroke(p, [trafo.translate(*move)]) hard_test( c, p, 0.47504345 - 5 * normpath._epsilon, parallel(0.0), move, "Y", checklens=[[37, 14], [37, 14], [7, 7], [7, 7]]) hard_test( c, p, 0.47504345 + 5 * normpath._epsilon, parallel(0.0), move, "Y", checklens=[[37, 7], [37, 7], [7, 7, 7], [7, 7, 7]]) hard_test( c, p, 0.5, parallel(0.0), move, "Y", checklens=[[36, 7], [36, 7], [6, 5, 6, 3, 7, 3], [6, 3, 7, 3, 5, 6]]) hard_test( c, p, 0.6125, parallel(0.0), move, "Y", checklens=[[35], [35], [3], [3]]) hard_test( c, p, 0.6130, parallel(0.0), move, "Y", checklens=[[35], [35], [], []]) # a path of two subpaths: # and with inner intersections to be cut away by _between_paths move = (0, 0) p = path.circle(-6, 0, 2) p += path.path(path.moveto(0, 0), path.curveto(0, 16, -11, 5, 5, 5)) p += path.path( path.lineto(5, 4), path.lineto(7, 4), path.lineto(7, 6), path.lineto(4, 6), path.lineto(4, 7), path.lineto(5, 7), path.lineto(3, 1), path.closepath()) p = p.transformed(trafo.scale(0.5)).normpath() hard_test( c, p, 0.05, parallel(0.0), move, "Z", checklens=[[10, 2, 8], [9, 2, 10], [13, 4, 4], [13, 4, 4]]) hard_test( c, p, 0.3, parallel(0.0), move, "Z", checklens=[[10, 4, 5], [4, 6, 10], [13, 4], [13, 4]]) hard_test( c, p, 0.6, parallel(0.0), move, "Z", checklens=[[], [], [13, 4], [13, 4]])
def testparallel_1(c): # HARD TESTS of elementary geometry: # # test for correct skipping of short ugly pieces: move = (-2, 0) p = path.path( path.moveto(0, 1), path.lineto(10, 0.3), path.lineto(12, 0), path.lineto(0, 0)) p.append(path.closepath()) hard_test( c, p, 0.1, parallel(0.0), move, "A", checklens=[[15], [15], [4], [4]]) hard_test( c, p, 0.25, parallel(0.0, sharpoutercorners=True), move, "A", checklens=[[12], [12], [3], [3]]) hard_test( c, p, 0.55, parallel(0.0), move, "A", checklens=[[15], [15], [], []]) # test non-intersecting/too short neighbouring pathels move = (0, 4) p = path.curve(0, 0, 0, 1, 1, 2, 2, 0) p.append(path.lineto(2.1, 0.1)) p.append(path.lineto(1.6, -2)) p.append(path.lineto(2.1, -2)) p.append(path.lineto(-0.15, 0)) p.append(path.closepath()) hard_test( c, p, 0.02, parallel(0.0, sharpoutercorners=1), move, "B", checklens=[[3], [3], [11], [11]]) hard_test( c, p, 0.06, parallel(0.0), move, "B", checklens=[[3], [3], [10], [9]]) # difference is due to rounding in path._arctobeziers hard_test( c, p, 0.3, parallel(0.0), move, "B", checklens=[[25], [25], [5], [5]]) hard_test( c, p, 0.3, parallel(0.0, sharpoutercorners=1), move, "B", checklens=[[22], [22], [5], [5]]) # test extreme precision: move = (3.5, 2) p = path.curve(0, 0, 0, 1, 1, 1, 1, 0) p.append(path.closepath()) hard_test( c, p, 0.1, parallel(0.0), move, "C", checklens=[[8], [8], [2], [2]]) hard_test( c, p, 0.1, parallel(0.0, relerr=1e-15, checkdistanceparams=[0.5]), move, "C", checklens=[[23], [23], [15], [15]]) # test for numeric instabilities: move = (6, 2) p = path.curve(0, 0, 1, 1, 1, 1, 2, 0) p.append(path.closepath()) hard_test( c, p, 0.1, parallel(0.0, relerr=0.15, checkdistanceparams=[0.5]), move, "D", checklens=[[11], [11], [3], [3]]) hard_test( c, p, 0.3, parallel(0.0), move, "D", checklens=[[11], [11], [3], [3]]) # test for an empty parallel path: move = (5, 5) p = path.circle(0, 0, 0.5).normpath() nspitems = [ nspitem for nspitem in p[0] if isinstance(nspitem, normpath.normcurve_pt) ] nspitems[-1] = nspitems[-1].modifiedend_pt(*nspitems[0].atbegin_pt()) p = normpath.normpath([normpath.normsubpath(nspitems, closed=True)]) hard_test( c, p, 0.55, parallel(0.0), move, "E", checklens=[[], [], [9], [9]]) hard_test( c, p, 0.4999, parallel(0.0, relerr=1.0e-15), move, "E", checklens=[[1, 14, 8], [1, 14], [17], [17]]) # a degenerate path: move = (13, 3) p = path.curve(0, 0, 0, -5, 0, 1, 0, 0.5) hard_test( c, p, 0.10, parallel(0.0, dointersection=False), move, "F", dotests=[True, True, False, False], checklens=[[13], [12], [13], [12]]) hard_test( c, p, 0.13, parallel(0.0, dointersection=False), move, "F", dotests=[False, False, True, True], checklens=[[13], [12], [13], [12]]) # test for too big curvatures in the middle: move = (9, 2.5) p = path.curve(0, 0, 1, 1, 1, 1, 2, 0) hard_test( c, p, 0.4, parallel(0.0, relerr=1.0e-2), move, "G", checklens=[[2], [2], [4], [4]]) hard_test( c, p, 0.6, parallel(0.0, relerr=1.0e-2), move, "G", checklens=[[2], [2], [4], [4]]) hard_test( c, p, 0.8, parallel(0.0, relerr=1.0e-2), move, "G", checklens=[[2], [2], [4], [4]]) hard_test( c, p, 1.7, parallel(0.0, relerr=1.0e-2), move, "G", checklens=[[2], [2], [1, 1], [1, 1]]) # deformation of the deformation: move = (11, 6) p = path.curve(-1, 0, 0, 1, 0, 1, 1, 0).normpath() c.stroke(p, [trafo.translate(*move), color.gray(0.8)]) dist = unit.u_pt / p.curvature_pt([normpath.normpathparam(p, 0, 0.5)])[0] p = parallel(dist, relerr=1.0e-2, dointersection=0).deform(p) assert len(p) == 2 assert len(p[0]) == len(p[1]) == 2 c.stroke(p, [trafo.translate(*move), color.gray(0.8)]) hard_test( c, p, -dist, parallel(0.0), move, "H", checklens=[[4], [4], [2], [2]]) # test for infinite curvature in the middle: move = (11, 8.5) p = path.curve(0, 0, 1, 1, 0, 1, 1, 0).normpath() hard_test( c, p, 0.2, parallel(0.0), move, "I", checklens=[[1, 1], [1, 1], [2], [2]]) hard_test( c, p, 1.5, parallel(0.0), move, "I", checklens=[[1, 1], [1, 1], [7], [7]]) #ard_test(c, p, 5.0, parallel(0.0), move, "I", checklens=[[],[],[7],[7]]) # test for infinite curvature at the end: move = (-2, 13) p = path.curve(0, 0, 0.5, 0.5, 0.75, 0.5, 0.75, 0.5) hard_test( c, p, 0.1, parallel(0.0, relerr=1.0e-4), move, "J", checklens=[[5], [5], [5], [5]]) # test for infinite curvature when the path goes on # XXX this is not correctly detected if rlineto(1,0). Expect two nsp p.append(path.rlineto(0, 1)) hard_test( c, p, 0.22, parallel(0.0, relerr=1.0e-4), move, "J", checklens=[[4], [4], [3, 1], [1, 3]]) # test for too big curvature in the middle, the non-intersecting case move = (0, 8) p = path.curve(-1, -1, 4, 4, -4, 4, 1, -1).normpath() dist = unit.u_pt * ( 1.0 / p.curvature_pt([normpath.normpathparam(p, 0, 0.5)])[0]) hard_test( c, p, 1.5 * dist, parallel(0.0, dointersection=False), move, "K", checklens=[[1, 1], [1, 1], [2], [2]]) hard_test( c, p, dist + normpath._epsilon, parallel(0.0, dointersection=False, relerr=1.0e-5), move, "K", checklens=[[11, 11], [11, 11], [16], [16]]) hard_test( c, p, dist + 0 * normpath._epsilon, parallel(0.0, dointersection=False, relerr=1.0e-5), move, "K", checklens=[[22], [22], [16], [16]]) # what is to be done with the arcs running around corners? # for dist=1.1 they do not even intersect with the original path: # TODO move = (8, 14) p = path.rect(0, 0, 1, 1).normpath() hard_test( c, p, 1.1, parallel(0.0), move, "L", dotests=[True, True, False, False], checklens=[[20], [20], None, None]) hard_test( c, p, 0.55, parallel(0.0), move, "L", dotests=[True, True, False, False], checklens=[[28], [28], None, None]) # very small lines approximating a curve # make sure that there is no "dust" remaining from the many intersections move = (3, 9) N = 12 angle = 0.5 * math.pi / (N - 1.0) p = path.path(path.moveto(0, 0)) for n in range(N): p.append(path.lineto(2 + math.sin(n * angle), 1 - math.cos(n * angle))) p.append(path.rlineto(0, 1)) p.append(path.rlineto(2, 0)) p.append(path.rlineto(0, -2)) p = p.transformed(trafo.translate(0, 0.05)) p = p << p.transformed(trafo.scale(1, -1)).reversed() hard_test( c, p, 0.6, parallel(0.0), move, "M", checklens=[[43], [43], [29], [29]]) # intersections where paths are parallel (in the middle of a nsp-item) move = (4, 15) c.text(move[0], move[1] + 0.2, "N") tr = trafo.translate(*move) par = parallel(0.1) par.dist_pt = unit.topt(par.distance) c1 = path.curve(-2, -1, -2, 1, 2, -1, 2, 1).transformed(tr).normpath() c2 = path.curve(-2, -1, -2, 1 / 3.0, 2, 1 / 3.0, 2, -1).transformed(tr).normpath() l = path.line(-2, 0, 2, 0).transformed(tr).normpath() for p in [c1, c2, l]: c.stroke(p) p = (c1 + l).normpath() try: par._can_continue( mynormpathparam(p, 0, 0, 0.5), mynormpathparam(p, 1, 0, 0.5)) except IntersectionError as e: assert str( e ) == "Cannot determine whether curves intersect (parallel and equally curved)" p = c2 + l assert par._can_continue( mynormpathparam(p, 0, 0, 0.5), mynormpathparam(p, 1, 0, 0.5)) p = c2 + l.reversed() assert par._can_continue( mynormpathparam(p, 0, 0, 0.5), mynormpathparam(p, 1, 0, 0.5)) p = c2.reversed() + l assert not par._can_continue( mynormpathparam(p, 0, 0, 0.5), mynormpathparam(p, 1, 0, 0.5)) p = c2.reversed() + l.reversed() assert not par._can_continue( mynormpathparam(p, 0, 0, 0.5), mynormpathparam(p, 1, 0, 0.5)) p = c1 + c2 assert not par._can_continue( mynormpathparam(p, 0, 0, 0.5), mynormpathparam(p, 1, 0, 0.5)) p = c2 + c1 assert par._can_continue( mynormpathparam(p, 0, 0, 0.5), mynormpathparam(p, 1, 0, 0.5)) # intersections where paths are parallel (between nsp-items) c11, c12 = c1.split([normpath.normpathparam(c1, 0, 0.5)]) c21, c22 = c2.split([normpath.normpathparam(c2, 0, 0.5)]) l1, l2 = l.split([normpath.normpathparam(l, 0, 0.5)]) p = (c21 << l2 + l1 << c22).normpath() # curve-line + line-curve assert par._can_continue( mynormpathparam(p, 1, 0, 1), mynormpathparam(p, 0, 1, 0)) # line -> line assert not par._can_continue( mynormpathparam(p, 0, 0, 1), mynormpathparam(p, 1, 1, 0)) # curve -> curve # intersections where paths are parallel (in the middle of a nsp-item) move = (12, 13) p1 = path.path(path.moveto(0, 0), path.curveto(0, 3, 1, 5, 1, 0)).normpath() params1, params2 = p1.intersect(path.line(0.5, -1, 0.5, 5)) p11, p12 = p1.split(params1) p11.append(path.rlineto(0, -2)) p = p11 << p12 p.append(path.closepath()) hard_test( c, p, 0.55, parallel(0.0), move, "O", dotests=[True, True, False, False], checklens=[[10], [10], None, None]) # jump to too large curvature between nspitems move = (-2, 17) p = path.path( path.moveto(0, 0), path.arc(2, 0.5, 0.5, -90, 90), path.lineto(0, 1)).normpath() hard_test( c, p, 0.55, parallel(0.0), move, "P", dotests=[True, True, True, True], checklens=[[1, 1], [1, 1], [7], [7]])
def test_reproductions(seed, n_tests, xmax, ymax, accuracy): # <<< # insert xmax, ymax, accuracy in pt! r = Random(seed) n_testpoints = 20 testparams = [i / (n_testpoints - 1.0) for i in range(n_testpoints)] # a canvas for drawing can = canvas.canvas() xpos = 0 ypos = 0 # loop over many different cases n_failures = 0 n_successes = 0 for cnt in range(n_tests): # the original curve a = r.uniform(0, xmax), r.uniform(0, ymax) b = r.uniform(0, xmax), r.uniform(0, ymax) c = r.uniform(0, xmax), r.uniform(0, ymax) d = r.uniform(0, xmax), r.uniform(0, ymax) origcurve = normpath.normcurve_pt(a[0], a[1], b[0], b[1], c[0], c[1], d[0], d[1]) tbeg, tend = origcurve.rotation([0, 1]) cbeg, cend = origcurve.curvature_pt([0, 1]) # raise an error if one of the params is invalid: tbeg, tend, cbeg, cend tbeg, tend = tbeg.apply_pt(1, 0), tend.apply_pt(1, 0) # the reproduced curve controldistpairs = controldists_from_endgeometry_pt(a, d, tbeg, tend, cbeg, cend, _epsilon) reprocurves = [] for controldistpair in controldistpairs: alpha, beta = controldistpair reprocurves.append( normpath.normcurve_pt( a[0], a[1], a[0] + alpha * tbeg[0], a[1] + alpha * tbeg[1], d[0] - beta * tend[0], d[1] - beta * tend[1], d[0], d[1], ) ) # analyse the quality of the reproduction minmaxdist = float("inf") minindex = -1 maxdists = [] for i, reprocurve in enumerate(reprocurves): maxdist = max( [ math.hypot(p[0] - q[0], p[1] - q[1]) for p, q in zip(origcurve.at_pt(testparams), reprocurve.at_pt(testparams)) ] ) if maxdist < minmaxdist: minmaxdist = maxdist minindex = i maxdists.append(maxdist) # print complaints for too bad reproductions if minindex != 0 or minmaxdist > accuracy: n_failures += 1 if minmaxdist > accuracy: print("%4d Smallest distance is %f" % (cnt, minmaxdist)) if minindex == -1: print("%4d Failure: no solution found" % (cnt)) if minindex > 0: print("%4d Wrong sorting: entry %d is the smallest" % (cnt, minindex)) if minindex >= 0 and not (controldistpairs[minindex][0] >= 0 and controldistpairs[minindex][1] >= 0): print("%4d Failure: signs are wrong" % (cnt)) # selectively draw the curves: # if minindex == -1: # if minindex > 0: if minmaxdist > accuracy: # draw the failure curves can.stroke(path.rect_pt(0, 0, xmax, ymax), [trafo.translate_pt(xpos, ypos)]) can.draw( normpath.normpath([normpath.normsubpath([origcurve])]), [trafo.translate_pt(xpos, ypos), deco.stroked([style.linewidth.THIck]), deco.shownormpath()], ) if minindex != -1: can.stroke( normpath.normpath([normpath.normsubpath([reprocurves[minindex]])]), [trafo.translate_pt(xpos, ypos), color.rgb.red], ) can.text( 0, 0, r"(%d)" % (cnt), [trafo.translate_pt(xpos + 0.5 * xmax, ypos), text.halign.center, text.vshift(2.0)], ) xpos += 1.1 * xmax if xpos > 11 * xmax: xpos = 0 ypos -= 1.1 * ymax ypos -= 15 else: n_successes += 1 print("failures, successes = ", n_failures, ", ", n_successes) can.writeEPSfile("test_bezier")