gcodetools.py revision 7765ee8964c8ffd7faee9baa0412abeb1ef5b0a4
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshComments starting "#LT" or "#CLT" are by Chris Lusby Taylor who rewrote the engraving function in 2011.
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshHistory of CLT changes to engraving and other functions it uses:
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh9 May 2011 Changed test of tool diameter to square it
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh10 May Note that there are many unused functions, including:
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh bound_to_bound_distance, csp_curvature_radius_at_t,
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh csp_special_points, csplength, rebuild_csp, csp_slope,
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh csp_simple_bound_to_point_distance, csp_bound_to_point_distance,
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh bez_at_t, bez_to_point_distance, bez_normalized_slope, matrix_mul, transpose
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh Fixed csp_point_inside_bound() to work if x outside bounds
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh20 May Now encoding the bisectors of angles.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh23 May Using r/cos(a) instead of normalised normals for bisectors of angles.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh23 May Note that Z values generated for engraving are in pixels, not mm.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh Removed the biarc curves - straight lines are better.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh24 May Changed Bezier slope calculation to be less sensitive to tiny differences in points.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh Added use of self.options.engraving_newton_iterations to control accuracy
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh25 May Big restructure and new recursive function.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh Changed the way I treat corners - I now find if the centre of a proposed circle is
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh within the area bounded by the line being tested and the two angle bisectors at
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh its ends. See get_radius_to_line().
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh29 May Eliminating redundant points. If A,B,C colinear, drop B
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh30 May Eliminating redundant lines in divided Beziers. Changed subdivision of lines
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 7Jun Try to show engraving in 3D
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 8 Jun Displaying in stereo 3D.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh Fixed a bug in bisect - it could go wrong due to rounding errors if
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 1+x1.x2+y1.y2<0 which should never happen. BTW, I spotted a non-normalised normal
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh returned by csp_normalized_normal. Need to check for that.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 9 Jun Corrected spelling of 'definition' but still match previous 'defention' and 'defenition' if found in file
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh Changed get_tool to find 1.6.04 tools or new tools with corrected spelling
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh10 Jun Put 3D into a separate layer called 3D, created unless it already exists
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh Changed csp_normalized_slope to reject lines shorter than 1e-9.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh10 Jun Changed all dimensions seen by user to be mm/inch, not pixels. This includes
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh tool diameter, maximum engraving distance, tool shape and all Z values.
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh12 Jun ver 208 Now scales correctly if orientation points moved or stretched.
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh12 Jun ver 209. Now detect if engraving toolshape not a function of radius
fba63a357654d8b3e84c60007e40aa698cd45d19miklosh Graphics now indicate Gcode toolpath, limited by min(tool diameter/2,max-dist)
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshTODO Change line division to be recursive, depending on what line is touched. See line_divide
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshengraving() functions (c) 2011 Chris Lusby Taylor, clusbytaylor@enterprise.net
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshCopyright (C) 2009 Nick Drobchenko, nick@cnc-club.ru
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshbased on gcode.py (C) 2007 hugomatic...
dc4f69a188c203f2fdc65f22d0d57904a8c52dd7mikloshbased on addnodes.py (C) 2005,2007 Aaron Spike, aaron@ekips.org
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshbased on dots.py (C) 2005 Aaron Spike, aaron@ekips.org
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshbased on interp.py (C) 2005 Aaron Spike, aaron@ekips.org
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshbased on bezmisc.py (C) 2005 Aaron Spike, aaron@ekips.org
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshbased on cubicsuperpath.py (C) 2005 Aaron Spike, aaron@ekips.org
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshThis program is free software; you can redistribute it and/or modify
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshit under the terms of the GNU General Public License as published by
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshthe Free Software Foundation; either version 2 of the License, or
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh(at your option) any later version.
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshThis program is distributed in the hope that it will be useful,
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshbut WITHOUT ANY WARRANTY; without even the implied warranty of
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshGNU General Public License for more details.
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshYou should have received a copy of the GNU General Public License
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshalong with this program; if not, write to the Free Software
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh### Gcodetools v 1.7
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh### Check if inkex has errormsg (0.46 version does not have one.) Could be removed later.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh inkex.errormsg = lambda msg: sys.stderr.write((unicode(msg) + "\n").encode("UTF-8"))
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshdef bezierslopeatt(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)),t):
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh ax,ay,bx,by,cx,cy,x0,y0=bezmisc.bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)))
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh print_("Slope error x = %s*t^3+%s*t^2+%s*t+%s, y = %s*t^3+%s*t^2+%s*t+%s, t = %s, dx==dy==0" % (ax,bx,cx,dx,ay,by,cy,dy,t))
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh # VARIABLE NAME SHOULD BE A STRING! Like isset("foobar")
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh return variable in locals() or variable in globals()
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh################################################################################
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh### Styles and additional parameters
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh################################################################################
fba63a357654d8b3e84c60007e40aa698cd45d19miklosh(Generated by gcodetools from Inkscape.)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh(Using default header. To add your own header create file "header" in the output dir.)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh(Header end.)
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshG00 X0.0000 Y0.0000
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh(Using default footer. To add your own footer create file "footer" in the output dir.)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh "in_out_path_style" : simplestyle.formatStyle({ 'stroke': '#0072a7', 'fill': 'none', 'stroke-width':'1', 'marker-mid':'url(#InOutPathMarker)' }),
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh "loft_style" : {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'main curve': simplestyle.formatStyle({ 'stroke': '#88f', 'fill': 'none', 'stroke-width':'1', 'marker-end':'url(#Arrow2Mend)' }),
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh "biarc_style" : {
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh 'biarc0': simplestyle.formatStyle({ 'stroke': '#88f', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh 'biarc1': simplestyle.formatStyle({ 'stroke': '#8f8', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'line': simplestyle.formatStyle({ 'stroke': '#f88', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'area': simplestyle.formatStyle({ 'stroke': '#777', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.1' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh "biarc_style_dark" : {
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh 'biarc0': simplestyle.formatStyle({ 'stroke': '#33a', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'biarc1': simplestyle.formatStyle({ 'stroke': '#3a3', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'line': simplestyle.formatStyle({ 'stroke': '#a33', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'area': simplestyle.formatStyle({ 'stroke': '#222', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh "biarc_style_dark_area" : {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'biarc0': simplestyle.formatStyle({ 'stroke': '#33a', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.1' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'biarc1': simplestyle.formatStyle({ 'stroke': '#3a3', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.1' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'line': simplestyle.formatStyle({ 'stroke': '#a33', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.1' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'area': simplestyle.formatStyle({ 'stroke': '#222', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh "biarc_style_i" : {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'biarc0': simplestyle.formatStyle({ 'stroke': '#880', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'biarc1': simplestyle.formatStyle({ 'stroke': '#808', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'line': simplestyle.formatStyle({ 'stroke': '#088', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'area': simplestyle.formatStyle({ 'stroke': '#999', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh "biarc_style_dark_i" : {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'biarc0': simplestyle.formatStyle({ 'stroke': '#dd5', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'biarc1': simplestyle.formatStyle({ 'stroke': '#d5d', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'line': simplestyle.formatStyle({ 'stroke': '#5dd', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'area': simplestyle.formatStyle({ 'stroke': '#aaa', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh "biarc_style_lathe_feed" : {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'biarc0': simplestyle.formatStyle({ 'stroke': '#07f', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'biarc1': simplestyle.formatStyle({ 'stroke': '#0f7', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'line': simplestyle.formatStyle({ 'stroke': '#f44', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'area': simplestyle.formatStyle({ 'stroke': '#aaa', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh "biarc_style_lathe_passing feed" : {
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh 'biarc0': simplestyle.formatStyle({ 'stroke': '#07f', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'biarc1': simplestyle.formatStyle({ 'stroke': '#0f7', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'line': simplestyle.formatStyle({ 'stroke': '#f44', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh 'area': simplestyle.formatStyle({ 'stroke': '#aaa', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh "biarc_style_lathe_fine feed" : {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'biarc0': simplestyle.formatStyle({ 'stroke': '#7f0', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'biarc1': simplestyle.formatStyle({ 'stroke': '#f70', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'line': simplestyle.formatStyle({ 'stroke': '#744', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh 'area': simplestyle.formatStyle({ 'stroke': '#aaa', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
dc4f69a188c203f2fdc65f22d0d57904a8c52dd7miklosh "area artefact": simplestyle.formatStyle({ 'stroke': '#ff0000', 'fill': '#ffff00', 'stroke-width':'1' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh "area artefact arrow": simplestyle.formatStyle({ 'stroke': '#ff0000', 'fill': '#ffff00', 'stroke-width':'1' }),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh "dxf_points": simplestyle.formatStyle({ "stroke": "#ff0000", "fill": "#ff0000"}),
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh################################################################################
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh### Gcode additional functions
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh################################################################################
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if a != "" :
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh res += "(" + re.sub(r"[\(\)\\\n\r]", ".", a) + ")\n"
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh################################################################################
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh### Cubic Super Path additional functions
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh################################################################################
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh return [ [ [point[:] for k in range(3) ] for point in subline ] for subline in line ]
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshdef csp_remove_zerro_segments(csp, tolerance = 1e-7):
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if point_to_point_d2(sp1[1],sp2[1])<=tolerance and point_to_point_d2(sp1[2],sp2[1])<=tolerance and point_to_point_d2(sp1[1],sp2[0])<=tolerance :
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh # we'll do the raytracing and see how many intersections are there on the ray's way.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh # if number of intersections is even then point is outside.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh # ray will be x=p.x and y=>p.y
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh # you can assing any value to on_the_path, by dfault if point is on the path
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh # function will return thai it's inside the path.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh #we've got a special case here
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh # points is on the path
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh # we can skip this segment because it wont influence the answer.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh for t in csp_line_intersection([x,y],[x,y+5],sp1,sp2) :
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh #we've got another special case here
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh # the point is on the path
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh # if t == 0 we sould have considered this case previously.
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if t == 1 :
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh # we have to check the next segmant if it is on the same side of the ray
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if st_d == 0 : st_d = csp_normalized_slope(sp1,sp2,0.99)[0]
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if (i+j) % len(subpath) == 0 : continue # skip the closing segment
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh sp11,sp22 = subpath[(i-1+j) % len(subpath)], subpath[(i+j) % len(subpath)]
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh ax1,ay1,bx1,by1,cx1,cy1,dx1,dy1 = csp_parameterize(sp1,sp2)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if ax1==0 and bx1==0 and cx1==0 and dx1==x : continue # this segment parallel to the ray, so skip it
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if en_d == 0 : en_d = csp_normalized_slope(sp11,sp22,0.01)[0]
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh # the point is on the path
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if y1>y and 3*ax*t**2 + 2*bx*t + cx !=0 : # if it's 0 the path only touches the ray
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshdef csp_close_all_subpaths(csp, tolerance = 0.000001):
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if point_to_point_d2(csp[i][0][1] , csp[i][-1][1])> tolerance**2 :
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh min_, max_ = line_to_line_min_max_distance_2(points1[i-1], points1[i], points2[j-1], points2[j])
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshdef csp_to_point_distance(csp, p, dist_bounds = [0,1e100], tolerance=.01) :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh d = csp_seg_to_point_distance(csp[j][i-1],csp[j][i],p,sample_points = 5, tolerance = .01)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh# draw_pointer( list(csp_at_t(subpath[dist[2]-1],subpath[dist[2]],dist[3]))
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh# +list(csp_at_t(csp[dist[4]][dist[5]-1],csp[dist[4]][dist[5]],dist[6])),"red","line", comment = math.sqrt(dist[0]))
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshdef csp_seg_to_point_distance(sp1,sp2,p,sample_points = 5, tolerance = .01) :
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh d = min( [(p[0]-sp1[1][0])**2 + (p[1]-sp1[1][1])**2,0.], [(p[0]-sp2[1][0])**2 + (p[1]-sp2[1][1])**2,1.] )
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh f = (ax*t3+bx*t2+cx*t+dx)*(3*ax*t2+2*bx*t+cx) + (ay*t3+by*t2+cy*t+dy)*(3*ay*t2+2*by*t+cy)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh df = (6*ax*t+2*bx)*(ax*t3+bx*t2+cx*t+dx) + (3*ax*t2+2*bx*t+cx)**2 + (6*ay*t+2*by)*(ay*t3+by*t2+cy*t+dy) + (3*ay*t2+2*by*t+cy)**2
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshdef csp_seg_to_csp_seg_distance(sp1,sp2,sp3,sp4, dist_bounds = [0,1e100], sample_points = 5, tolerance=.01) :
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh # check the ending points first
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh dist = csp_seg_to_point_distance(sp1,sp2,sp3[1],sample_points, tolerance)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh d = csp_seg_to_point_distance(sp1,sp2,sp4[1],sample_points, tolerance)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh d = csp_seg_to_point_distance(sp3,sp4,sp1[1],sample_points, tolerance)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh d = csp_seg_to_point_distance(sp3,sp4,sp2[1],sample_points, tolerance)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh ax1,ay1,bx1,by1,cx1,cy1,dx1,dy1 = csp_parameterize(sp1,sp2)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh ax2,ay2,bx2,by2,cx2,cy2,dx2,dy2 = csp_parameterize(sp3,sp4)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh # try to find closes points using Newtons method
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh t1,t2 = float(k+1)/(sample_points+1), float(j)/(sample_points+1)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh t12, t13, t22, t23 = t1*t1, t1*t1*t1, t2*t2, t2*t2*t2
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh x,y = ax1*t13+bx1*t12+cx1*t1+dx1 - (ax2*t23+bx2*t22+cx2*t2+dx2), ay1*t13+by1*t12+cy1*t1+dy1 - (ay2*t23+by2*t22+cy2*t2+dy2)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh #draw_pointer(csp_at_t(sp1,sp2,t1))
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh F2[0][0] = 2*(6*ax1*t1+2*bx1)*x + 2*f1x*f1x + 2*(6*ay1*t1+2*by1)*y +2*f1y*f1y
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh F2[1][1] = -2*(6*ax2*t2+2*bx2)*x + 2*f2x*f2x - 2*(6*ay2*t2+2*by2)*y + 2*f2y*f2y
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh t12, t13, t22, t23 = t1*t1, t1*t1*t1, t2*t2, t2*t2*t2
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh x,y = ax1*t13+bx1*t12+cx1*t1+dx1 - (ax2*t23+bx2*t22+cx2*t2+dx2), ay1*t13+by1*t12+cy1*t1+dy1 - (ay2*t23+by2*t22+cy2*t2+dy2)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh F = x*x+y*y
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshdef csp_to_csp_distance(csp1,csp2, dist_bounds = [0,1e100], tolerance=.01) :
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh d = csp_seg_bound_to_csp_seg_bound_max_min_distance(csp1[i1][j1-1],csp1[i1][j1],csp2[i2][j2-1],csp2[i2][j2])
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if d[1] < dist_bounds[0] : return [d[1],i1,j1,1,i2,j2,1]
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh d = csp_seg_to_csp_seg_distance(csp1[i1][j1-1],csp1[i1][j1],csp2[i2][j2-1],csp2[i2][j2], dist_bounds, tolerance=tolerance)
dc4f69a188c203f2fdc65f22d0d57904a8c52dd7miklosh# draw_pointer( list(csp_at_t(csp1[dist[1]][dist[2]-1],csp1[dist[1]][dist[2]],dist[3]))
dc4f69a188c203f2fdc65f22d0d57904a8c52dd7miklosh# + list(csp_at_t(csp2[dist[4]][dist[5]-1],csp2[dist[4]][dist[5]],dist[6])), "#507","line")
dc4f69a188c203f2fdc65f22d0d57904a8c52dd7miklosh [x1,y1],[x2,y2],[x3,y3],[x4,y4] = sp1[1], sp1[2], sp2[0], sp2[1]
dc4f69a188c203f2fdc65f22d0d57904a8c52dd7miklosh return [sp1[0],sp1[1],[x12,y12]], [[x1223,y1223],[x,y],[x2334,y2334]], [[x34,y34],sp2[1],sp2[2]]
dc4f69a188c203f2fdc65f22d0d57904a8c52dd7miklosh # Finds minx,miny,maxx,maxy of the csp and return their (x,y,i,j,t)
dc4f69a188c203f2fdc65f22d0d57904a8c52dd7miklosh ax,ay,bx,by,cx,cy,x0,y0 = bezmisc.bezierparameterize((csp[i][j-1][1],csp[i][j-1][2],csp[i][j][0],csp[i][j][1]))
dc4f69a188c203f2fdc65f22d0d57904a8c52dd7miklosh############################################################################
dc4f69a188c203f2fdc65f22d0d57904a8c52dd7miklosh### csp_segments_intersection(sp1,sp2,sp3,sp4)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh### Returns array containig all intersections between two segmets of cubic
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh### super path. Results are [ta,tb], or [ta0, ta1, tb0, tb1, "Overlap"]
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh### where ta, tb are values of t for the intersection point.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh############################################################################
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh a, b = csp_segment_to_bez(sp1,sp2), csp_segment_to_bez(sp3,sp4)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh def polish_intersection(a,b,ta,tb, tolerance = intersection_tolerance) :
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh ax,ay,bx,by,cx,cy,dx,dy = bezmisc.bezierparameterize(a)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh ax1,ay1,bx1,by1,cx1,cy1,dx1,dy1 = bezmisc.bezierparameterize(b)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh while i==0 or (abs(F[0])**2+abs(F[1])**2 > tolerance and i<10):
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh F[0] = ax*ta3+bx*ta2+cx*ta+dx-ax1*tb3-bx1*tb2-cx1*tb-dx1
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh F[1] = ay*ta3+by*ta2+cy*ta+dy-ay1*tb3-by1*tb2-cy1*tb-dy1
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh F1 = [ [ F1[1][1]/det, -F1[0][1]/det], [-F1[1][0]/det, F1[0][0]/det] ]
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh else: break
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh def recursion(a,b, ta0,ta1,tb0,tb1, depth_a,depth_b) :
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh bezier_intersection_recursive_result += [[ta0,tb0,ta1,tb1,"Overlap"]]
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if bez_bounds_intersect(a1,b1) : recursion(a1,b1, ta0,tam,tb0,tbm, depth_a-1,depth_b-1)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if bez_bounds_intersect(a2,b1) : recursion(a2,b1, tam,ta1,tb0,tbm, depth_a-1,depth_b-1)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if bez_bounds_intersect(a1,b2) : recursion(a1,b2, ta0,tam,tbm,tb1, depth_a-1,depth_b-1)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if bez_bounds_intersect(a2,b2) : recursion(a2,b2, tam,ta1,tbm,tb1, depth_a-1,depth_b-1)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if bez_bounds_intersect(a1,b) : recursion(a1,b, ta0,tam,tb0,tb1, depth_a-1,depth_b)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if bez_bounds_intersect(a2,b) : recursion(a2,b, tam,ta1,tb0,tb1, depth_a-1,depth_b)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if bez_bounds_intersect(a,b1) : recursion(a,b1, ta0,ta1,tb0,tbm, depth_a,depth_b-1)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if bez_bounds_intersect(a,b2) : recursion(a,b2, ta0,ta1,tbm,tb1, depth_a,depth_b-1)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh else : # Both segments have been subdevided enougth. Let's get some intersections :).
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh intersection, t1, t2 = straight_segments_intersection([a[0]]+[a[3]],[b[0]]+[b[3]])
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh bezier_intersection_recursive_result += [[ta0+t1*(ta1-ta0),tb0+t2*(tb1-tb0)]]
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh recursion(a,b,0.,1.,0.,1.,intersection_recursion_depth,intersection_recursion_depth)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh intersections = bezier_intersection_recursive_result
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if len(intersections[i])<5 or intersections[i][4] != "Overlap" :
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh intersections[i] = polish_intersection(a,b,intersections[i][0],intersections[i][1])
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshdef csp_segments_true_intersection(sp1,sp2,sp3,sp4) :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh intersections = csp_segments_intersection(sp1,sp2,sp3,sp4)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh (len(intersection)==5 and intersection[4] == "Overlap" and (0<=intersection[0]<=1 or 0<=intersection[1]<=1) and (0<=intersection[2]<=1 or 0<=intersection[3]<=1) )
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh or ( 0<=intersection[0]<=1 and 0<=intersection[1]<=1 )
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshdef csp_get_t_at_curvature(sp1,sp2,c, sample_points = 16):
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh # returns a list containning [t1,t2,t3,...,tn], 0<=ti<=1...
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh try : # some numerical calculation could exceed the limits
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh ( (f1x*f3y-f3x*f1y)*d - (f1x*f2y-f2x*f1y)*3.*(f2x*f1x+f2y*f1y)*((f1x**2+f1y**2)**.5) ) /
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if d != 0 :
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh ( d*(f1x*f3y-f3x*f1y) - (f1x*f2y-f2x*f1y)*3.*(f2x*f1x+f2y*f1y)*pow(f1x**2+f1y**2,.5) ) /
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh else: break
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh ax,ay,bx,by,cx,cy,dx,dy = bezmisc.bezierparameterize(csp_segment_to_bez(sp1,sp2))
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh #curvature = (x'y''-y'x'') / (x'^2+y'^2)^1.5
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if d != 0 :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh # Use the Lapitals rule to solve 0/0 problem for 2 times...
c4723fe0caa2096d00cb31a7d1506351ba8102dbmiklosh # little hack ;^) hope it wont influence anything...
c4723fe0caa2096d00cb31a7d1506351ba8102dbmiklosh return 1e100
c4723fe0caa2096d00cb31a7d1506351ba8102dbmiklosh else: return 1/c
c4723fe0caa2096d00cb31a7d1506351ba8102dbmiklosh # special points = curvature == 0
c4723fe0caa2096d00cb31a7d1506351ba8102dbmiklosh ax,ay,bx,by,cx,cy,dx,dy = bezmisc.bezierparameterize((sp1[1],sp1[2],sp2[0],sp2[1]))
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh # Remove all zerro length segments
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh #subpath = subpath[:]
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if (P(subpath[-1][1])-P(subpath[0][1])).l2() > 1e-10 :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh subpath += [ [subpath[0][1],subpath[0][1],subpath[0][1]] ]
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh ax,bx,cx,dx = sp1[1][0], sp1[2][0], sp2[0][0], sp2[1][0]
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh ay,by,cy,dy = sp1[1][1], sp1[2][1], sp2[0][1], sp2[1][1]
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh return [x,y]
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshdef csp_splitatlength(sp1, sp2, l = 0.5, tolerance = 0.01):
c4723fe0caa2096d00cb31a7d1506351ba8102dbmiklosh # rebuild_csp() adds to csp control points making it's segments looks like segs
c4723fe0caa2096d00cb31a7d1506351ba8102dbmiklosh d = min( [abs(s[i]-segs[j]),j], d) if d!=None else [abs(s[i]-segs[j]),j]
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if segs[i]<s[j] : break
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh ax,ay,bx,by,cx,cy,x0,y0=bezmisc.bezierparameterize(bez)
77364929ced3ec0bc5c9f47440606615c559084emiklosh # points is float=t or list [t1, t2, ..., tn]
7ec85862d9730e449ed5c2a86201bc9ca1daa0aamiklosh sp3,sp4,sp5 = csp_split(res[-2],res[-1], (t-last_t)/(1-last_t))
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh # points are [[i,t]...] where i-segment's number
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if int1[0] == 0 and int2[0]==len(subpath)-1:# and small(int1[1]) and small(int2[1]-1) :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh sp = csp_split_by_two_points(subpath[int1[0]-1],subpath[int1[0]],int1[1], int2[1])
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh sp5,sp1,sp2 = csp_split(subpath[int1[0]-1],subpath[int1[0]],int1[1])
7ec85862d9730e449ed5c2a86201bc9ca1daa0aamiklosh sp3,sp4,sp5 = csp_split(subpath[int2[0]-1],subpath[int2[0]],int2[1])
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh parts += [ [sp1,sp2]+subpath[int1[0]+1:int2[0]-1]+[sp3,sp4] ]
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if abs(n[0]**2+n[1]**2 - 1) > 1e-10 : n = normalize(n)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh return arc_from_c_s_l([s[0]+n[0]*r, s[1]+n[1]*r],s,l)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if r == 0 : return []
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh e = [ c[0] + (s[0]-c[0])*cos_ - (s[1]-c[1])*sin_, c[1] + (s[0]-c[0])*sin_ + (s[1]-c[1])*cos_]
7ec85862d9730e449ed5c2a86201bc9ca1daa0aamiklosh # Creates csp that approximise specified arc
7ec85862d9730e449ed5c2a86201bc9ca1daa0aamiklosh alpha = (atan2(end[0]-center[0],end[1]-center[1]) - atan2(start[0]-center[0],start[1]-center[1])) % math.pi2
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh alpha_start = atan2(start[0]-center[0],start[1]-center[1])
7ec85862d9730e449ed5c2a86201bc9ca1daa0aamiklosh cos_,sin_ = math.cos(alpha_start), math.sin(alpha_start)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh cos_,sin_ = math.cos(alpha_start + alpha*i/sectors), math.sin(alpha_start + alpha*i/sectors)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh sp = [ [], [center[0] + cos_*r, center[1] + sin_*r], [] ]
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh ### Distance calculattion from point to arc
7ec85862d9730e449ed5c2a86201bc9ca1daa0aamiklosh i = c + (p-c).unit()*r
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if between(alpha,0,a) or min(abs(alpha),abs(alpha-a))<straight_tolerance :
7ec85862d9730e449ed5c2a86201bc9ca1daa0aamiklosh return (p-i).mag(), [i.x, i.y]
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshdef csp_to_arc_distance(sp1,sp2, arc1, arc2, tolerance = 0.01 ): # arc = [start,end,center,alpha]
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh d = min(point_to_arc_distance(p,arc1), point_to_arc_distance(p,arc2))
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh return math.sqrt(max(minx-p[0],p[0]-maxx,0)**2+max(miny-p[1],p[1]-maxy,0)**2)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh #CLT added test of x in range
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if x0-x1!=0 and (y-y0)*(x1-x0)>=(x-x0)*(y1-y0) and x>min(x0,x1) and x<=max(x0,x1) :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh d = point_to_line_segment_distance_2(p, bez[i-1],bez[i])
7ec85862d9730e449ed5c2a86201bc9ca1daa0aamikloshdef line_line_intersect(p1,p2,p3,p4) : # Return only true intersection.
7ec85862d9730e449ed5c2a86201bc9ca1daa0aamiklosh if (p1[0]==p2[0] and p1[1]==p2[1]) or (p3[0]==p4[0] and p3[1]==p4[1]) : return False
7ec85862d9730e449ed5c2a86201bc9ca1daa0aamiklosh x = (p2[0]-p1[0])*(p4[1]-p3[1]) - (p2[1]-p1[1])*(p4[0]-p3[0])
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if (p3[0]-p1[0])*(p2[1]-p1[1]) == (p3[1]-p1[1])*(p2[0]-p1[0]) :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh return ("Overlap" if (0<=t11<=1 or 0<=t12<=1) and (0<=t21<=1 or 0<=t22<=1) else False)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh else: return False
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh 0<=((p4[0]-p3[0])*(p1[1]-p3[1]) - (p4[1]-p3[1])*(p1[0]-p3[0]))/x<=1 and
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh 0<=((p2[0]-p1[0])*(p1[1]-p3[1]) - (p2[1]-p1[1])*(p1[0]-p3[0]))/x<=1 )
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshdef line_line_intersection_points(p1,p2,p3,p4) : # Return only points [ (x,y) ]
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if (p1[0]==p2[0] and p1[1]==p2[1]) or (p3[0]==p4[0] and p3[1]==p4[1]) : return []
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh x = (p2[0]-p1[0])*(p4[1]-p3[1]) - (p2[1]-p1[1])*(p4[0]-p3[0])
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if (p3[0]-p1[0])*(p2[1]-p1[1]) == (p3[1]-p1[1])*(p2[0]-p1[0]) :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if (0<=t11<=1 or 0<=t12<=1) and (0<=t21<=1 or 0<=t22<=1) :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh else: return []
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh t1 = ((p4[0]-p3[0])*(p1[1]-p3[1]) - (p4[1]-p3[1])*(p1[0]-p3[0]))/x
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh t2 = ((p2[0]-p1[0])*(p1[1]-p3[1]) - (p2[1]-p1[1])*(p1[0]-p3[0]))/x
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if 0<=t1<=1 and 0<=t2<=1 : return [ [p1[0]*(1-t1)+p2[0]*t1, p1[1]*(1-t1)+p2[1]*t1] ]
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh else : return []
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh # p1 - point, p2,p3 - line segment
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh #draw_pointer(p1)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh return (p1[0]- p2[0]-v[0]*c1/c2)**2 + (p1[1]- p2[1]-v[1]*c1/c2)
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshdef csp_seg_bound_to_csp_seg_bound_max_min_distance(sp1,sp2,sp3,sp4) :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if csp_point_inside_bound(sp1, sp2, bez2[i]) or csp_point_inside_bound(sp3, sp4, bez1[i]) :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh d = line_to_line_distance_2(bez1[i-1],bez1[i],bez2[j-1],bez2[j])
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh d = (bez2[j][0]-bez1[i][0])**2 + (bez2[j][1]-bez1[i][1])**2
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh for j in csp[i] :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh ax,ay,bx,by,cx,cy,dx,dy=bezmisc.bezierparameterize((sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:]))
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if abs(f1x*f1x+f1y*f1y) > 1e-9 : #LT changed this from 1e-20, which caused problems
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if t == 0 :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if abs(f1x*f1x+f1y*f1y) > 1e-9 : #LT changed this from 1e-20, which caused problems
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh elif t == 1 :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh return bezmisc.bezierparameterize(csp_segment_to_bez(sp1,sp2))
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if (s1[-1][1][0]-s2[0][1][0])**2 + (s1[-1][1][1]-s2[0][1][1])**2 > 0.00001 :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh return s1[:-1]+[ [s1[-1][0],s1[-1][1],s1[-1][1]], [s2[0][1],s2[0][1],s2[0][2]] ] + s2[1:]
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh return s1[:-1]+[ [s1[-1][0],s2[0][1],s2[0][2]] ] + s2[1:]
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh return (s1[-1][1][0]-s2[0][1][0])**2 + (s1[-1][1][1]-s2[0][1][1])**2
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh intersections += [ [j,int_] for int_ in csp_line_intersection(l1,l2,s[j-1],s[j])]
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh splitted_s = csp_subpath_split_by_points(s, intersections)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh for s in splitted_s[:] :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh for p in csp_true_bounds([s]) :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if (l1[1]-l2[1])*p[0] + (l2[0]-l1[0])*p[1] + (l1[0]*l2[1]-l2[0]*l1[1])<-0.01 :
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshdef csp_subpath_line_to(subpath, points, prepend = False) :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh # Appends subpath with line or polyline.
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh subpath += [ [p[:],p[:],p[:]] ]
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if csp_subpaths_end_to_start_distance2(joined_result[j],s1) <0.000001 :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh joined_result[j] = csp_concat_subpaths(joined_result[j],s1)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if csp_subpaths_end_to_start_distance2(s1,joined_result[j]) <0.000001 :
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh joined_result[j] = csp_concat_subpaths(s1,joined_result[j])
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh return (a[0]-b[0])*(c[1]-b[1]) - (c[0]-b[0])*(a[1]-b[1])
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh a,b,c,d = sp1[1][:], sp1[2][:], sp2[0][:], sp2[1][:]
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh if abc == 0 and abd == 0 : return [min(a,b,c,d), max(a,b,c,d)]
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh raise ValueError, "csp_segment_convex_hull happend something that shouldnot happen!"
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh################################################################################
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh### Bezier additional functions
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh################################################################################
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh return bounds_intersect(bez_bound(bez2), bez_bound(bez1))
def bounds_intersect(a, b) :
def normalize((x,y)) :
def cross(a,b) :
def dot(a,b) :
def rotate_ccw(d) :
def rotate_cw(d) :
def vectors_ccw(a,b):
def vector_add(a,b) :
def vector_mul(a,b) :
def vector_from_to_length(a,b):
def matrix_mul(a,b) :
return [ [ sum([a[i][k]*b[k][j] for k in range(len(a[0])) ]) for j in range(len(b[0]))] for i in range(len(a))]
return [ [ sum([a[i][k]*b[k][j] for k in range(len(a[0])) ]) for j in range(len(b[0]))] for i in range(len(a))]
def transpose(a) :
def det_3x3(a):
return float(
[ (a[1][1]*a[2][2] - a[2][1]*a[1][2])/det, -(a[0][1]*a[2][2] - a[2][1]*a[0][2])/det, (a[0][1]*a[1][2] - a[1][1]*a[0][2])/det ],
[ -(a[1][0]*a[2][2] - a[2][0]*a[1][2])/det, (a[0][0]*a[2][2] - a[2][0]*a[0][2])/det, -(a[0][0]*a[1][2] - a[1][0]*a[0][2])/det ],
[ (a[1][0]*a[2][1] - a[2][0]*a[1][1])/det, -(a[0][0]*a[2][1] - a[2][0]*a[0][1])/det, (a[0][0]*a[1][1] - a[1][0]*a[0][1])/det ]
def small(a) :
global small_tolerance
value = None
for k in node :
return value
if style == None :
style = "font-family:DejaVu Sans;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:DejaVu Sans;fill:#000000;fill-opacity:1;stroke:none;"
if gcodetools_tag!=None :
if group == None:
for s in text :
y += font_size
def draw_csp(csp, stroke = "#f00", fill = "none", comment = "", width = 0.354, group = None, style = None, gcodetools_tag = None) :
if style == None :
if group == None :
def draw_pointer(x,color = "#f00", figure = "cross", group = None, comment = "", fill=None, width = .1, size = 10., text = None, font_size=None, pointer_type=None, attrib = None) :
if pointer_type == None:
if group == None:
if text != None :
group = inkex.etree.SubElement( group, inkex.addNS('g','svg'), {"gcodetools": pointer_type+" group"} )
attrib.update({"d": "M %s,%s L %s"%(x[0],x[1],s), "style":"fill:none;stroke:%s;stroke-width:%f;"%(color,width),"comment":str(comment)})
d = "m %s,%s " % (x[0],x[1]) + re.sub("([0-9\-.e]+)",(lambda match: str(float(match.group(1))*size*2.)), "0.88464,-0.40404 c -0.0987,-0.0162 -0.186549,-0.0589 -0.26147,-0.1173 l 0.357342,-0.35625 c 0.04631,-0.039 0.0031,-0.13174 -0.05665,-0.12164 -0.0029,-1.4e-4 -0.0058,-1.4e-4 -0.0087,0 l -2.2e-5,2e-5 c -0.01189,0.004 -0.02257,0.0119 -0.0305,0.0217 l -0.357342,0.35625 c -0.05818,-0.0743 -0.102813,-0.16338 -0.117662,-0.26067 l -0.409636,0.88193 z")
attrib.update({"d": d, "style":"fill:%s;stroke:none;fill-opacity:%s;"%(fill,fill_opacity),"comment":str(comment)})
attrib.update({"d": "m %s,%s l %f,%f %f,%f %f,%f %f,%f , %f,%f"%(x[0],x[1], size,size, -2*size,-2*size, size,size, size,-size, -2*size,2*size ), "style":"fill:none;stroke:%s;stroke-width:%f;"%(color,width),"comment":str(comment)})
def straight_segments_intersection(a,b, true_intersection = True) : # (True intersection means check ta and tb are in [0,1])
return ("Overlap" if 0<=ta<=1 or 0<=tb<=1 or 0<=tc<=1 or 0<=td<=1 or not true_intersection else False), (ta,tb), (tc,td)
def between(c,x,y):
return x-straight_tolerance<=c<=y+straight_tolerance or y-straight_tolerance<=c<=x+straight_tolerance
def cubic_solver_real(a,b,c,d):
res = []
return res
def cubic_solver(a,b,c,d):
# Monics formula see http://en.wikipedia.org/wiki/Cubic_function#Monic_formula_of_roots
for s in arg :
f.write( s )
f.close()
if h: return self / h
class Arc():
self.c = P(c)
r += self.r
r = self.r - r
self.r = r
r = (st-c)
r = r.mag()
attr = {
if transform != [] :
class Line():
if transform != [] :
res = []
return res
class Biarc:
if items == None :
def l(self) :
i = a.intersect(b)
global gcodetools
if group==None:
gcodetools.preview_groups = { layer: inkex.etree.SubElement( gcodetools.layers[min(1,len(gcodetools.layers)-1)], inkex.addNS('g','svg'), {"gcodetools": "Preview group"} ) }
gcodetools.preview_groups[layer] = inkex.etree.SubElement( gcodetools.layers[min(1,len(gcodetools.layers)-1)], inkex.addNS('g','svg'), {"gcodetools": "Preview group"} )
if transform != [] :
a,b,c = gcodetools.transform(a, layer, True), gcodetools.transform(b, layer, True), gcodetools.transform(c, layer, True)
#Crve defenitnion [start point, type = {'arc','line','move','end'}, arc center, arc angle, end point, [zstart, zend]]
### It's based on src/livarot/PathOutline.cpp from Inkscape's source code.
result = []
t.sort()
if result==[] :
if intersection != [] :
return result
if intersection != [] :
if _break:break
if _break :
if intersection != [] :
if arc == [] :
if intersection != [] :
if next == [] :
if intersection != [] :
csp_seg_to_point_distance(sp1_r,sp2_r, (P(csp_at_t(sp1,sp2,.25)) + P(csp_normalized_normal(sp1,sp2,.25))*r).to_list())[0],
csp_seg_to_point_distance(sp1_r,sp2_r, (P(csp_at_t(sp1,sp2,.50)) + P(csp_normalized_normal(sp1,sp2,.50))*r).to_list())[0],
csp_seg_to_point_distance(sp1_r,sp2_r, (P(csp_at_t(sp1,sp2,.75)) + P(csp_normalized_normal(sp1,sp2,.75))*r).to_list())[0],
#print_(csp_seg_to_point_distance(sp1_r,sp2_r, (P(csp_at_t(sp1,sp2,.25)) + P(csp_normalized_normal(sp1,sp2,.25))*r).to_list())[0], tolerance)
# Clip segments which has curvature>1/r. Because their offset will be selfintersecting and very nasty.
subpath_offset = []
if subpath_offset == [] :
prev, arc, next = csp_join_offsets(subpath_offset[-prev_l:], subpath_offset[:2], subpath[0], subpath[1], sp1_l,sp2_l, r)
#inkex.etree.SubElement( options.doc_root, inkex.addNS('path','svg'), {"d": cubicsuperpath.formatPath(unclipped_offset), "style":"fill:none;stroke:#0f0;"} )
# First of all find all intersection's between all segments of all offseted subpaths, including self intersections.
global small_tolerance
for t in intersections :
for t in intersections :
splitted_offset = []
result = []
if (P(s1[0][1])-P(s2[-1][1])).l2()<0.0001 and ( (subpath_i+1) % len(splitted_offset) != subpath_j ):
if (P(s2[0][1])-P(s1[-1][1])).l2()<0.0001 and ( (subpath_j+1) % len(splitted_offset) != subpath_i ):
if not clip :
(P(csp_at_t(s2[-2],s2[-1],1.))+ P(csp_normalized_normal(s2[-2],s2[-1],1.))*10).to_list(),"Green", "line" )
for s in joined_result[:] :
for s in joined_result[:]:
dist = csp_to_point_distance(original_csp, s[int(len(s)/2)][1], dist_bounds = [r1,r2], tolerance = .000001)
draw_pointer(csp_at_t(csp[dist[1]][dist[2]-1],csp[dist[1]][dist[2]],dist[3])+s[int(len(s)/2)][1],"blue", "line", comment = [math.sqrt(dist[0]),i,j,sp] )
print_()
return joined_result
tang_are_parallel = ((tsa-tea)%math.pi<straight_tolerance or math.pi-(tsa-tea)%math.pi<straight_tolerance )
if ( tang_are_parallel and
((v.mag()<straight_distance_tolerance or TE.mag()<straight_distance_tolerance or TS.mag()<straight_distance_tolerance) or
elif not asmall:
return R, alpha
if R1==None or R2==None or (R1-P0).mag()<straight_tolerance or (R2-P2).mag()<straight_tolerance : return [ [sp1[1],'line', 0, 0, sp2[1], [z1,z2]] ]
if d > options.biarc_tolerance and depth<options.biarc_max_split_depth : return biarc_split(sp1, sp2, z1, z2, depth)
if (subcurve[-1][4][0]-subcurve[0][0][0])**2 + (subcurve[-1][4][1]-subcurve[0][0][1])**2 < 10**-7 : subcurve_closed = True
while lc<l :
if reverse :
seg = [seg[4], "line", 0 , 0, seg[0], seg[5]] # Hmmm... Do we have to swap seg[5][0] and seg[5][1] (zstart and zend) or not?
seg = [seg[4], "arc", seg[2] , -seg[3], seg[0], seg[5]] # Hmmm... Do we have to swap seg[5][0] and seg[5][1] (zstart and zend) or not?
res += [[ seg[0], "line", 0, 0, [(seg[4][0]-seg[0][0])/ls*(l-lc),(seg[4][1]-seg[0][1])/ls*(l-lc)], [seg[5][0],seg[5][1]/ls*(l-lc)] ]]
return res
class Postprocessor():
for s in command:
s = s.strip()
self.error("Unrecognized function '%s' while postprocessing.\n(Command: '%s')"%(function,command), "error")
self.error("Bad parameters for regexp. They should be as re.sub pattern and replacement parameters! For example: r\"G0(\d)\", r\"G\\1\" \n(Parameters: '%s')\n %s"%(parameters, ex), "error")
for s in parameters:
if case_sensitive :
warned = []
if plane == "g17" and scale[0]!=scale[1]: self.error("Post-processor: Scale factors for X and Y axis are not the same. G02 and G03 codes will be corrupted.","warning")
if plane == "g18" and scale[0]!=scale[2]: self.error("Post-processor: Scale factors for X and Z axis are not the same. G02 and G03 codes will be corrupted.","warning")
if plane == "g19" and scale[1]!=scale[2]: self.error("Post-processor: Scale factors for Y and Z axis are not the same. G02 and G03 codes will be corrupted.","warning")
for a in axis[i] :
s = re.sub(r"(?i)("+a+r")\s*(-?)\s*(\d*\.?\d*)", r"\1 %f"%(float(r.group(2)+r.group(3))*scale[i]+(move[i] if a not in ["i","j","k"] else 0) ), s)
if flip :
planes = []
feeds = {}
coords = []
if c not in coords :
coords += [c]
for c in coords:
for f in feeds :
self.error("Bad parameters for round. Round should be an integer! \n(Parameters: '%s')"%(parameters), "error")
self.error("Bad parameters for scale. Scale should not be 0 at any axis! \n(Parameters: '%s')"%(parameters), "error")
for p in parameters:
self.error("Bad parameters for flip_axis. Parameter should be string consists of 'xyza' \n(Parameters: '%s')"%(parameters), "error")
class Polygon:
for p in poly :
centroids = []
cx /= a
cy /= a
for c in centroids :
if st[0]>end[0] : st, end = end, st # This will be needed to check that edge if open only at rigth end
return True
return inside
hull = []
poly_ = []
poly_ += [s]
for p in int_ :
poly_ += [p]
for p in int_ :
poly_ += [p]
edges = {}
for p in edges :
l = point_to_point_d(s,e)
edges[s] = [ [s,e,l] ]
edges[e] = [ [e,s,l] ]
if e in edges :
edges[e] += [ [e,s,l] ]
edges[e] = [ [e,s,l] ]
if s in edges :
edges[s] += [ [s,e, l] ]
edges[s] = [ [s,e,l] ]
return False
return True
for p in edges:
#draw_pointer(list(p[0])+[p[0][0]+cur[0]*40,p[0][1]+cur[1]*40], "Orange", "line", width=1, comment = [sin,cos])
next = p
return next
poly = []
class Arangement_Genetic:
specimen = []
for j in order:
s += ((sp1[j][0]-sp2[j][0])/self.genes_count)**2 + (( sp1[j][1]-sp2[j][1]))**2 + ((sp1[j][2]-sp2[j][2]))**2
t.sort()
genes_order = []
end_gene = (max(1,random.randint(0,self.genes_count),int(self.genes_count/4))+start_gene) % self.genes_count
specimen[i] = [parent1[i][0], parent1[i][1]*tr+parent2[i][1]*(1-tr),parent1[i][2]*tp+parent2[i][2]*(1-tp)]
specimen[i] = [parent2[j][0], parent1[i][1]*tr+parent2[i][1]*(1-tr),parent1[i][2]*tp+parent2[i][2]*(1-tp)]
for i in range(random.randint(self.mutation_genes_count[0],self.mutation_genes_count[0]*self.incest_mutation_count_multiplyer )) :
for p in spiece :
return surface
return surface
converters is None
options.self.error("For this function Scipy is needed. See http://www.cnc-club.ru/gcodetools for details.","error")
for subpoly in p :
test_ = []
population_ = []
f.close()
f.close()
code,
if not no_headers :
f.close()
if not end :
if not end :
if not end :
if not self.options.in_out_path and not self.options.plasma_prepare_corners and self.options.in_out_path_do_not_add_reference_point:
self.error("Warning! Extenstion is not said to do anything! Enable one of Create in-out paths or Prepare corners checkboxes or disable Do not add in-out referense point!")
add_func = {"Round":add_arc, "Perpendicular": add_normal, "Tangent": add_tangent}[self.options.in_out_path_type]
if self.options.in_out_path_type == "Round" and self.options.in_out_path_len > self.options.in_out_path_radius*3/2*math.pi :
res = []
d = d1[:]
p_ = p
res_ += [
polygons = []
original_paths = []
print_("Got %s polygons having average %s edges each."% ( len(polygons), float(sum([ sum([len(poly) for poly in polygon.polygon]) for polygon in polygons ])) / len(polygons) ) )
population.mutation_genes_count = [1,max(2,int(population.genes_count/4))] #[1,max(2,int(population.genes_count/2))] if 40<=i%100<60 else [1,max(2,int(population.genes_count/10))]
print_()
print_()
draw_text("Step = %s\nSquare = %f\nSquare improvement = %f\nTime from start = %f"%(i,(b[2]-b[0])*(b[3]-b[1]),improve,time.time()-start_time),x,y-50)
self.OptionParser.add_option("-d", "--directory", action="store", type="string", dest="directory", default="/home/", help="Directory for gcode file")
self.OptionParser.add_option("-f", "--filename", action="store", type="string", dest="file", default="-1.0", help="File name")
self.OptionParser.add_option("", "--add-numeric-suffix-to-filename", action="store", type="inkbool", dest="add_numeric_suffix_to_filename", default=True,help="Add numeric suffix to filename")
self.OptionParser.add_option("", "--Zscale", action="store", type="float", dest="Zscale", default="1.0", help="Scale factor Z")
self.OptionParser.add_option("", "--Zoffset", action="store", type="float", dest="Zoffset", default="0.0", help="Offset along Z")
self.OptionParser.add_option("-s", "--Zsafe", action="store", type="float", dest="Zsafe", default="0.5", help="Z above all obstacles")
self.OptionParser.add_option("-z", "--Zsurface", action="store", type="float", dest="Zsurface", default="0.0", help="Z of the surface")
self.OptionParser.add_option("-c", "--Zdepth", action="store", type="float", dest="Zdepth", default="-0.125", help="Z depth of cut")
self.OptionParser.add_option("", "--Zstep", action="store", type="float", dest="Zstep", default="-0.125", help="Z step of cutting")
self.OptionParser.add_option("-p", "--feed", action="store", type="float", dest="feed", default="4.0", help="Feed rate in unit/min")
self.OptionParser.add_option("", "--biarc-tolerance", action="store", type="float", dest="biarc_tolerance", default="1", help="Tolerance used when calculating biarc interpolation.")
self.OptionParser.add_option("", "--biarc-max-split-depth", action="store", type="int", dest="biarc_max_split_depth", default="4", help="Defines maximum depth of splitting while approximating using biarcs.")
self.OptionParser.add_option("", "--path-to-gcode-order", action="store", type="string", dest="path_to_gcode_order", default="path by path", help="Defines cutting order path by path or layer by layer.")
self.OptionParser.add_option("", "--path-to-gcode-depth-function",action="store", type="string", dest="path_to_gcode_depth_function", default="zd", help="Path to gcode depth function.")
self.OptionParser.add_option("", "--path-to-gcode-sort-paths", action="store", type="inkbool", dest="path_to_gcode_sort_paths", default=True, help="Sort paths to reduse rapid distance.")
self.OptionParser.add_option("", "--comment-gcode", action="store", type="string", dest="comment_gcode", default="", help="Comment Gcode")
self.OptionParser.add_option("", "--comment-gcode-from-properties",action="store", type="inkbool", dest="comment_gcode_from_properties", default=False,help="Get additional comments from Object Properties")
self.OptionParser.add_option("", "--tool-diameter", action="store", type="float", dest="tool_diameter", default="3", help="Tool diameter used for area cutting")
self.OptionParser.add_option("", "--max-area-curves", action="store", type="int", dest="max_area_curves", default="100", help="Maximum area curves for each area")
self.OptionParser.add_option("", "--area-inkscape-radius", action="store", type="float", dest="area_inkscape_radius", default="0", help="Area curves overlaping (depends on tool diameter [0,0.9])")
self.OptionParser.add_option("", "--area-tool-overlap", action="store", type="float", dest="area_tool_overlap", default="-10", help="Radius for preparing curves using inkscape")
self.OptionParser.add_option("", "--unit", action="store", type="string", dest="unit", default="G21 (All units in mm)", help="Units")
self.OptionParser.add_option("", "--active-tab", action="store", type="string", dest="active_tab", default="", help="Defines which tab is active")
self.OptionParser.add_option("", "--area-fill-angle", action="store", type="float", dest="area_fill_angle", default="0", help="Fill area with lines heading this angle")
self.OptionParser.add_option("", "--area-fill-shift", action="store", type="float", dest="area_fill_shift", default="0", help="Shift the lines by tool d * shift")
self.OptionParser.add_option("", "--area-fill-method", action="store", type="string", dest="area_fill_method", default="zig-zag", help="Filling method either zig-zag or spiral")
self.OptionParser.add_option("", "--area-find-artefacts-diameter",action="store", type="float", dest="area_find_artefacts_diameter", default="1", help="Artefacts seeking radius")
self.OptionParser.add_option("", "--area-find-artefacts-action", action="store", type="string", dest="area_find_artefacts_action", default="mark with an arrow", help="Artefacts action type")
self.OptionParser.add_option("", "--auto_select_paths", action="store", type="inkbool", dest="auto_select_paths", default=True, help="Select all paths if nothing is selected.")
self.OptionParser.add_option("", "--loft-distances", action="store", type="string", dest="loft_distances", default="10", help="Distances between paths.")
self.OptionParser.add_option("", "--loft-direction", action="store", type="string", dest="loft_direction", default="crosswise", help="Direction of loft's interpolation.")
self.OptionParser.add_option("", "--loft-interpolation-degree", action="store", type="float", dest="loft_interpolation_degree", default="2", help="Which interpolation use to loft the paths smooth interpolation or staright.")
self.OptionParser.add_option("", "--min-arc-radius", action="store", type="float", dest="min_arc_radius", default=".1", help="All arc having radius less than minimum will be considered as straight line")
self.OptionParser.add_option("", "--engraving-sharp-angle-tollerance",action="store", type="float", dest="engraving_sharp_angle_tollerance", default="150", help="All angles thar are less than engraving-sharp-angle-tollerance will be thought sharp")
self.OptionParser.add_option("", "--engraving-max-dist", action="store", type="float", dest="engraving_max_dist", default="10", help="Distanse from original path where engraving is not needed (usualy it's cutting tool diameter)")
self.OptionParser.add_option("", "--engraving-newton-iterations", action="store", type="int", dest="engraving_newton_iterations", default="4", help="Number of sample points used to calculate distance")
self.OptionParser.add_option("", "--engraving-draw-calculation-paths",action="store", type="inkbool", dest="engraving_draw_calculation_paths", default=False, help="Draw additional graphics to debug engraving path")
self.OptionParser.add_option("", "--engraving-cutter-shape-function",action="store", type="string", dest="engraving_cutter_shape_function", default="w", help="Cutter shape function z(w). Ex. cone: w. ")
self.OptionParser.add_option("", "--lathe-width", action="store", type="float", dest="lathe_width", default=10., help="Lathe width")
self.OptionParser.add_option("", "--lathe-fine-cut-width", action="store", type="float", dest="lathe_fine_cut_width", default=1., help="Fine cut width")
self.OptionParser.add_option("", "--lathe-fine-cut-count", action="store", type="int", dest="lathe_fine_cut_count", default=1., help="Fine cut count")
self.OptionParser.add_option("", "--lathe-create-fine-cut-using", action="store", type="string", dest="lathe_create_fine_cut_using", default="Move path", help="Create fine cut using")
self.OptionParser.add_option("", "--lathe-x-axis-remap", action="store", type="string", dest="lathe_x_axis_remap", default="X", help="Lathe X axis remap")
self.OptionParser.add_option("", "--lathe-z-axis-remap", action="store", type="string", dest="lathe_z_axis_remap", default="Z", help="Lathe Z axis remap")
self.OptionParser.add_option("", "--lathe-rectangular-cutter-width",action="store", type="float", dest="lathe_rectangular_cutter_width", default="4", help="Rectangular cutter width")
self.OptionParser.add_option("", "--create-log", action="store", type="inkbool", dest="log_create_log", default=False, help="Create log files")
self.OptionParser.add_option("", "--log-filename", action="store", type="string", dest="log_filename", default='', help="Create log files")
self.OptionParser.add_option("", "--orientation-points-count", action="store", type="string", dest="orientation_points_count", default="2", help="Orientation points count")
self.OptionParser.add_option("", "--tools-library-type", action="store", type="string", dest="tools_library_type", default='cylinder cutter', help="Create tools definition")
self.OptionParser.add_option("", "--dxfpoints-action", action="store", type="string", dest="dxfpoints_action", default='replace', help="dxfpoint sign toggle")
self.OptionParser.add_option("", "--help-language", action="store", type="string", dest="help_language", default='http://www.cnc-club.ru/forum/viewtopic.php?f=33&t=35', help="Open help page in webbrowser.")
self.OptionParser.add_option("", "--offset-radius", action="store", type="float", dest="offset_radius", default=10., help="Offset radius")
self.OptionParser.add_option("", "--offset-step", action="store", type="float", dest="offset_step", default=10., help="Offset step")
self.OptionParser.add_option("", "--offset-draw-clippend-path", action="store", type="inkbool", dest="offset_draw_clippend_path", default=False, help="Draw clipped path")
self.OptionParser.add_option("", "--offset-just-get-distance", action="store", type="inkbool", dest="offset_just_get_distance", default=False, help="Don't do offset just get distance")
self.OptionParser.add_option("", "--arrangement-material-width", action="store", type="float", dest="arrangement_material_width", default=500, help="Materials width for arrangement")
self.OptionParser.add_option("", "--arrangement-population-count",action="store", type="int", dest="arrangement_population_count", default=100, help="Genetic algorithm populations count")
self.OptionParser.add_option("", "--arrangement-inline-test", action="store", type="inkbool", dest="arrangement_inline_test", default=False, help="Use C-inline test (some additional packets will be needed)")
self.OptionParser.add_option("", "--postprocessor", action="store", type="string", dest="postprocessor", default='', help="Postprocessor command.")
self.OptionParser.add_option("", "--postprocessor-custom", action="store", type="string", dest="postprocessor_custom", default='', help="Postprocessor custom command.")
self.OptionParser.add_option("", "--graffiti-max-seg-length", action="store", type="float", dest="graffiti_max_seg_length", default=1., help="Graffiti maximum segment length.")
self.OptionParser.add_option("", "--graffiti-min-radius", action="store", type="float", dest="graffiti_min_radius", default=10., help="Graffiti minimal connector's radius.")
self.OptionParser.add_option("", "--graffiti-start-pos", action="store", type="string", dest="graffiti_start_pos", default="(0;0)", help="Graffiti Start position (x;y).")
self.OptionParser.add_option("", "--graffiti-create-linearization-preview", action="store", type="inkbool", dest="graffiti_create_linearization_preview", default=True, help="Graffiti create linearization preview.")
self.OptionParser.add_option("", "--graffiti-create-preview", action="store", type="inkbool", dest="graffiti_create_preview", default=True, help="Graffiti create preview.")
self.OptionParser.add_option("", "--graffiti-preview-size", action="store", type="int", dest="graffiti_preview_size", default=800, help="Graffiti preview's size.")
self.OptionParser.add_option("", "--graffiti-preview-emmit", action="store", type="int", dest="graffiti_preview_emmit", default=800, help="Preview's paint emmit (pts/s).")
self.OptionParser.add_option("", "--in-out-path", action="store", type="inkbool", dest="in_out_path", default=True, help="Create in-out paths")
self.OptionParser.add_option("", "--in-out-path-do-not-add-reference-point", action="store", type="inkbool", dest="in_out_path_do_not_add_reference_point", default=False, help="Just add reference in-out point")
self.OptionParser.add_option("", "--in-out-path-point-max-dist", action="store", type="float", dest="in_out_path_point_max_dist", default=10., help="In-out path max distance to reference point")
self.OptionParser.add_option("", "--in-out-path-type", action="store", type="string", dest="in_out_path_type", default="Round", help="In-out path type")
self.OptionParser.add_option("", "--in-out-path-len", action="store", type="float", dest="in_out_path_len", default=10., help="In-out path length")
self.OptionParser.add_option("", "--in-out-path-replace-original-path",action="store", type="inkbool", dest="in_out_path_replace_original_path", default=False, help="Replace original path")
self.OptionParser.add_option("", "--in-out-path-radius", action="store", type="float", dest="in_out_path_radius", default=10., help="In-out path radius for round path")
self.OptionParser.add_option("", "--plasma-prepare-corners", action="store", type="inkbool", dest="plasma_prepare_corners", default=True, help="Prepare corners")
self.OptionParser.add_option("", "--plasma-prepare-corners-distance", action="store", type="float", dest="plasma_prepare_corners_distance", default=10.,help="Stepout distance for corners")
self.OptionParser.add_option("", "--plasma-prepare-corners-tolerance", action="store", type="float", dest="plasma_prepare_corners_tolerance", default=10.,help="Maximum angle for corner (0-180 deg)")
dist = None
for k in keys:
subpath = p[k]
def draw_csp(self, csp, layer=None, group=None, fill='none', stroke='#178ade', width=0.354, style=None):
if layer!=None :
if style!=None :
if group==None:
self.preview_groups = { layer: inkex.etree.SubElement( self.layers[min(1,len(self.layers)-1)], inkex.addNS('g','svg'), {"gcodetools": "Preview group"} ) }
self.preview_groups[layer] = inkex.etree.SubElement( self.layers[min(1,len(self.layers)-1)], inkex.addNS('g','svg'), {"gcodetools": "Preview group"} )
if transform != [] :
a,b,c = self.transform(a, layer, True), self.transform(b, layer, True), self.transform(c, layer, True)
si[0], si[2] = self.transform(si[0], layer, True), (self.transform(si[2], layer, True) if type(si[2])==type([]) and len(si[2])==2 else si[2])
if transform != [] :
attr = {
if transform != [] :
s = si
f.close()
f.close()
self.error(_("Directory does not exist! Please specify existing directory at Preferences tab!"),"error")
return False
for s in dir_list :
f.close()
self.error(_("Can not write to specified file!\n%s"%(self.options.directory+self.options.file)),"error")
return False
return True
### Curve definition [start point, type = {'arc','line','move','end'}, arc center, arc angle, end point, [zstart, zend]]
m,a = [1,1,self.options.Zscale*Zauto_scale,1,1,self.options.Zscale*Zauto_scale], [0,0,self.options.Zoffset,0,0,0]
return min(
g += ( "(Change tool to %s)\n" % re.sub("\"'\(\)\\\\"," ",tool["name"]) ) + tool["tool change gcode"] + "\n"
current_a = a
current_a = a
g += ("G02" if s[3]<0 else "G03") + c(si[0]+[ s[5][1]+depth, (s[2][0]-s[0][0]),(s[2][1]-s[0][1]) ]) + feed + axis4 + "\n"
current_a = a
trans = []
while (g!=root):
g=g.getparent()
return trans
return trans
return transform
if trans != []:
if not reverse :
return csp
self.error(_("Orientation points for '%s' layer have not been found! Please add orientation points using Orientation tab!") % layer.get(inkex.addNS('label','inkscape')),"no_orientation_points")
self.error(_("There are more than one orientation point groups in '%s' layer") % orientation_layer.get(inkex.addNS('label','inkscape')),"more_than_one_orientation_point_groups")
points += [ [ [(points[1][0][1]-points[0][0][1])+points[0][0][0], -(points[1][0][0]-points[0][0][0])+points[0][0][1]], [-(points[1][1][1]-points[0][1][1])+points[0][1][0], points[1][1][0]-points[0][1][0]+points[0][1][1]] ] ]
self.Zcoordinates[layer] = [max(points[0][1][2],points[1][1][2]), min(points[0][1][2],points[1][1][2])]
[[points[0][1][0]], [points[0][1][1]], [1], [points[1][1][0]], [points[1][1][1]], [1], [points[2][1][0]], [points[2][1][1]], [1]]
).tolist()
self.error(_("Orientation points are wrong! (if there are two orientation points they should not be the same. If there are three orientation points they should not be in a straight line.)"),"wrong_orientation_points")
self.error(_("Orientation points are wrong! (if there are two orientation points they should not be the same. If there are three orientation points they should not be in a straight line.)"),"wrong_orientation_points")
###self.Zauto_scale[layer] = math.sqrt( (self.transform_matrix[layer][0][0]**2 + self.transform_matrix[layer][1][1]**2)/2 )
if not reverse :
csp = [ [ [csp_[i][j][0][:],csp_[i][j][1][:],csp_[i][j][2][:]] for j in range(len(csp_[i])) ] for i in range(len(csp_)) ]
return csp
s = str(s)
print_(s)
print_(s)
print_(s)
print_(s)
marker = inkex.etree.SubElement( defs, inkex.addNS("marker","svg"), {"id":"CheckToolsAndOPMarker","orient":"auto","refX":"-4","refY":"-1.687441","style":"overflow:visible"})
{ "d":" m -4.588864,-1.687441 0.0,0.0 L -9.177728,0.0 c 0.73311,-0.996261 0.728882,-2.359329 0.0,-3.374882",
marker = inkex.etree.SubElement( defs, inkex.addNS("marker","svg"), {"id":"DrawCurveMarker","orient":"auto","refX":"-4","refY":"-1.687441","style":"overflow:visible"})
{ "d":"m -4.588864,-1.687441 0.0,0.0 L -9.177728,0.0 c 0.73311,-0.996261 0.728882,-2.359329 0.0,-3.374882",
marker = inkex.etree.SubElement( defs, inkex.addNS("marker","svg"), {"id":"DrawCurveMarker_r","orient":"auto","refX":"4","refY":"-1.687441","style":"overflow:visible"})
{ "d":"m 4.588864,-1.687441 0.0,0.0 L 9.177728,0.0 c -0.73311,-0.996261 -0.728882,-2.359329 0.0,-3.374882",
marker = inkex.etree.SubElement( defs, inkex.addNS("marker","svg"), {"id":"InOutPathMarker","orient":"auto","refX":"-4","refY":"-1.687441","style":"overflow:visible"})
{ "d":"m -4.588864,-1.687441 0.0,0.0 L -9.177728,0.0 c 0.73311,-0.996261 0.728882,-2.359329 0.0,-3.374882",
def recursive(g) :
recursive(i)
for i in items:
if selected:
recursive_search(i,i)
if points != None :
self.orientation_points[layer] = self.orientation_points[layer]+[points[:]] if layer in self.orientation_points else [points[:]]
print_("Found orientation points in '%s' layer: %s" % (layer.get(inkex.addNS('label','inkscape')), points))
self.error(_("Warning! Found bad orientation points in '%s' layer. Resulting Gcode could be corrupt!") % layer.get(inkex.addNS('label','inkscape')), "bad_orientation_points_in_some_layers")
elif i.get("gcodetools") == "Gcodetools tool definition" or i.get("gcodetools") == "Gcodetools tool defenition" :
if point != [] :
self.graffiti_reference_points[layer] = self.graffiti_reference_points[layer]+[point[:]] if layer in self.graffiti_reference_points else [point]
self.error(_("Warning! Found bad graffiti reference point in '%s' layer. Resulting Gcode could be corrupt!") % layer.get(inkex.addNS('label','inkscape')), "bad_orientation_points_in_some_layers")
self.selected_paths[layer] = self.selected_paths[layer] + [i] if layer in self.selected_paths else [i]
for j in items_ :
self.in_out_reference_points.append( self.apply_transforms(j,cubicsuperpath.parsePath(j.get("d")))[0][0][1] )
self.error(_("This extension works with Paths and Dynamic Offsets and groups of them only! All other objects will be ignored!\nSolution 1: press Path->Object to path or Shift+Ctrl+C.\nSolution 2: Path->Dynamic offset or Ctrl+J.\nSolution 3: export all contours to PostScript level 2 (File->Save As->.ps) and File->Import this file."),"selection_contains_objects_that_are_not_paths")
self.error(_("Document has no layers! Add at least one layer using layers panel (Ctrl+Shift+L)"),"Error")
self.error(_("Warning! There are some paths in the root of the document, but not in any layer! Using bottom-most layer for them."), "tools_warning" )
for i in items:
if i.tag == inkex.addNS("g",'svg') and i.get("gcodetools") == "Gcodetools orientation point (2 points)":
p2 += [i]
if i.tag == inkex.addNS("g",'svg') and i.get("gcodetools") == "Gcodetools orientation point (3 points)":
p3 += [i]
points = []
point = [[],[]]
for node in i :
r = re.match(r'(?i)\s*\(\s*(-?\s*\d*(?:,|\.)*\d*)\s*;\s*(-?\s*\d*(?:,|\.)*\d*)\s*;\s*(-?\s*\d*(?:,|\.)*\d*)\s*\)\s*',get_text(node))
for node in g :
key = None
value = None
if j.get("gcodetools") == "Gcodetools tool definition field name" or j.get("gcodetools") == "Gcodetools tool defention field name":
if j.get("gcodetools") == "Gcodetools tool definition field value" or j.get("gcodetools") == "Gcodetools tool defention field value":
self.error(_("Warning! Tool's and default tool's parameter's (%s) types are not the same ( type('%s') != type('%s') ).") % (key, value, self.default_tool[key]), "tools_warning")
self.error(_("Warning! Tool has parameter that default tool has not ( '%s': '%s' ).") % (key, value), "tools_warning" )
return tool
# print_(("index(layer)=",self.layers.index(layer),"set_tool():layer=",layer,"self.tools=",self.tools))
if len(self.tools[layer])>1 : self.error(_("Layer '%s' contains more than one tool!") % self.layers[i].get(inkex.addNS('label','inkscape')), "more_than_one_tool")
self.error(_("Can not find tool for '%s' layer! Please add one with Tools library tab!") % layer.get(inkex.addNS('label','inkscape')), "no_tool_error")
out=[[],[],[],[]]
for p in points:
return out
out=[]
for p in points:
if p!=[None,None]: out+=[p]
return(out)
ways=[
minimal_way=[]
minimal_len=None
minimal_way_type=None
for w in ways:
cw=[]
cw+=p
return minimal_way
del lines[i]
return keys
lines = []
gcode +="(drilling dxfpoint)\nG00 Z%f\nG00 X%f Y%f\nG01 Z%f F%f\nG04 P%f\nG00 Z%f\n" % (self.options.Zsafe,point[0],point[1],self.Zcoordinates[layer][1],self.tools[layer][0]["penetration feed"],0.2,self.options.Zsafe)
return gcode
def get_path_properties(node, recursive=True, tags={inkex.addNS('desc','svg'):"Description",inkex.addNS('title','svg'):"Title"} ) :
res = {}
return res
biarc_group = inkex.etree.SubElement( self.selected_paths.keys()[0] if len(self.selected_paths.keys())>0 else self.layers[0], inkex.addNS('g','svg') )
colors = {}
curves = []
dxfpoints = []
self.error(_("Warning: One or more paths do not have 'd' parameter, try to Ungroup (Ctrl+Shift+G) and Object to Path (Ctrl+Shift+C)!"),"selection_contains_objects_that_are_not_paths")
comment = re.sub("\[([A-Za-z_\-\:]+)\]", partial(set_comment, path=path), self.options.comment_gcode)
colors[id_] = simplestyle.parseColor(style['stroke'] if "stroke" in style and style['stroke']!='none' else "#000")
dxfpoints += [[x,y]]
curves += [
curves_ = []
curves_ = []
self.error(_("Noting is selected. Please select something to convert to drill point (dxfpoint) or clear point sign."),"warning")
path.set("d","m %s 2.9375,-6.343750000001 0.8125,1.90625 6.843748640396,-6.84374864039 0,0 0.6875,0.6875 -6.84375,6.84375 1.90625,0.812500000001 z" % r.group(1))
self.error(_("Warning: One or more paths do not have 'd' parameter, try to Ungroup (Ctrl+Shift+G) and Object to Path (Ctrl+Shift+C)!"),"selection_contains_objects_that_are_not_paths")
remove = []
if (bounds[2]-bounds[0])**2+(bounds[3]-bounds[1])**2 < self.options.area_find_artefacts_diameter**2:
arrow = cubicsuperpath.parsePath( 'm %s,%s 2.9375,-6.343750000001 0.8125,1.90625 6.843748640396,-6.84374864039 0,0 0.6875,0.6875 -6.84375,6.84375 1.90625,0.812500000001 z' % (subpath[0][1][0],subpath[0][1][1]) )
inkex.etree.SubElement(parent, inkex.addNS('path','svg'), {'d': cubicsuperpath.formatPath(csp[i]), 'style': styles["area artefact"]})
for i in remove :
del csp[i]
self.error(_("Tool diameter must be > 0 but tool's diameter on '%s' layer is not!") % layer.get(inkex.addNS('label','inkscape')),"area_tools_diameter_error")
print_(d)
j = min_j
subp = [ [subp[j][1], subp[j][1], subp[j][2]] ] + subp[j+1:] + subp[:j] + [ [subp[j][0], subp[j][1], subp[j][1]] ]
subp = [ [ sp2[1], sp2[1],sp2[2] ] ] + [sp3] + subp[j+1:] + subp[:j-1] + [sp1] + [[ sp2[0], sp2[1],sp2[1] ]]
for j in csp[i]:
csp[i] = n[:]
radius = -r
if radius == -r : break
tang_are_parallel = ((tsa-tea)%math.pi<straight_tolerance or math.pi-(tsa-tea)%math.pi<straight_tolerance )
if ( tang_are_parallel and
((v.mag()<straight_distance_tolerance or TE.mag()<straight_distance_tolerance or TS.mag()<straight_distance_tolerance) or
elif not asmall:
return R, alpha
if R1==None or R2==None or (R1-P0).mag()<straight_tolerance or (R2-P2).mag()<straight_tolerance : return [ [sp1[1],'line', 0, 0, sp2[1], [z1,z2]] ]
if d > options.biarc_tolerance and depth<options.biarc_max_split_depth : return biarc_split(sp1, sp2, z1, z2, depth)
self.error(_("Tool diameter must be > 0 but tool's diameter on '%s' layer is not!") % layer.get(inkex.addNS('label','inkscape')),"area_tools_diameter_error")
lines = []
rotated_path = [ [ [ [point[0]*math.cos(a) - point[1]*math.sin(a), point[0]*math.sin(a)+point[1]*math.cos(a)] for point in sp] for sp in subpath] for subpath in csp ]
lines += [ [] ]
if top :
if not start:
lines = [ [ [point[0]*math.cos(a) - point[1]*math.sin(a), point[0]*math.sin(a)+point[1]*math.cos(a)] for point in subpath] for subpath in lines ]
intersections = {}
ints = []
for t in roots :
if p in intersections :
intersections[p] += [ [i,j,t] ]
intersections[p] = [ [i,j,t] ]
for i in ints:
del splitted_line[i]
#LT Notes to self: See wiki.inkscape.org/wiki/index.php/PythonEffectTutorial
global nlLT, i, j
global eye_dist
global max_dist
return max_dist
return max_dist
global max_dist
def bez_divide(a,b,c,d):
r = max_dist
r = t1
return [ line_divide((x0,y0),j0,i0,(x2,y2),j2,i2,(nx,ny),length/2), line_divide((x2,y2),j2,i2,(x1,y1),j1,i1,(nx,ny),length/2)]
wl+=[w]
{"gcodetools": "Engraving calculation toolpath", 'style': "fill:#ff00ff; fill-opacity:0.46; stroke:#000000; stroke-width:0.1;", inkex.addNS('cx','sodipodi'): str(x), inkex.addNS('cy','sodipodi'): str(y), inkex.addNS('rx','sodipodi'): str(1), inkex.addNS('ry','sodipodi'): str(1), inkex.addNS('type','sodipodi'): 'arc'})
{"gcodetools": "Engraving calculation paths", 'style': "fill:none; fill-opacity:0.46; stroke:#000000; stroke-width:0.1;", inkex.addNS('cx','sodipodi'): str(x), inkex.addNS('cy','sodipodi'): str(y),inkex.addNS('rx','sodipodi'): str(w), inkex.addNS('ry','sodipodi'): str(w), inkex.addNS('type','sodipodi'): 'arc'})
cspe =[]
we = []
self.error(_("Tool '%s' has no shape. 45 degree cone assumed!") % self.tools[layer][0]['name'],"Continue")
toolshape = lambda w: w
engraving_group = inkex.etree.SubElement( self.selected_paths[layer][0].getparent(), inkex.addNS('g','svg') )
self.my3Dlayer=inkex.etree.SubElement(self.document.getroot(), 'g') #Create a generic element at root level
gcode_3Dleft = inkex.etree.SubElement(self.my3Dlayer, inkex.addNS('g','svg'), {"gcodetools":"Gcode 3D L"})
gcode_3Dright = inkex.etree.SubElement(self.my3Dlayer, inkex.addNS('g','svg'), {"gcodetools":"Gcode 3D R"})
nlLT = []
if abs(cspi[j][i-1][1][0]-cspi[j][i][1][0])<engraving_tolerance and abs(cspi[j][i-1][1][1]-cspi[j][i][1][1])<engraving_tolerance:
del cspi[j][i]
cspl=[]
cspr=[]
spl=[]
spr=[]
w = max_dist
if w>lastw :
elif b>0 and n2[3]>0 and not self.options.engraving_draw_calculation_paths : #acute corner coming up
{"gcodetools": "Engraving calculation paths", 'style': "fill:none; fill-opacity:0.46; stroke:#000000; stroke-width:0.1;", inkex.addNS('cx','sodipodi'): str(cspm[i][1][0]), inkex.addNS('cy','sodipodi'): str(cspm[i][1][1]),inkex.addNS('rx','sodipodi'): str(wl[i]), inkex.addNS('ry','sodipodi'): str(wl[i]), inkex.addNS('type','sodipodi'): 'arc'})
for w in wl :
if cspe!=[]:
if layer == None :
if transform != [] :
if layer in self.graffiti_reference_points: graffiti_reference_points_count = len(self.graffiti_reference_points[layer])
if transform != [] :
'd':'m %s,%s 2.9375,-6.343750000001 0.8125,1.90625 6.843748640396,-6.84374864039 0,0 0.6875,0.6875 -6.84375,6.84375 1.90625,0.812500000001 z z' % (graffiti_reference_points_count*100, 0),
draw_text(axis,graffiti_reference_points_count*100+10,-10, group = g, gcodetools_tag = "Gcodetools graffiti reference point text")
draw_pointer(group = self.current_layer, x = self.view_center, figure="arrow", pointer_type = "In-out reference point", text = "In-out point")
self.error(_("Active layer already has orientation points! Remove them or select another layer!"),"active_layer_already_has_orientation_points")
if transform != [] :
for i in points :
g = inkex.etree.SubElement(orientation_group, inkex.addNS('g','svg'), {'gcodetools': "Gcodetools orientation point (%s points)" % self.options.orientation_points_count})
'd':'m %s,%s 2.9375,-6.343750000001 0.8125,1.90625 6.843748640396,-6.84374864039 0,0 0.6875,0.6875 -6.84375,6.84375 1.90625,0.812500000001 z z' % (si[0], -si[1]+doc_height),
draw_text("(%s; %s; %s)" % (i[0],i[1],i[2]), (si[0]+10), (-si[1]-10+doc_height), group = g, gcodetools_tag = "Gcodetools orientation point text")
if layer == None :
self.error(_("Active layer already has a tool! Remove it or select another layer!"),"active_layer_already_has_tool")
tool = {
tool = {
tool = {
tool = {
tool = {
tool = {
colors = ["00ff00","0000ff","ff0000","fefe00","00fefe", "fe00fe", "fe7e00", "7efe00", "00fe7e", "007efe", "7e00fe", "fe007e"]
tools_group = inkex.etree.SubElement(layer, inkex.addNS('g','svg'), {'gcodetools': "Gcodetools tool definition"})
{'style': "fill:#%s;fill-opacity:0.5;stroke:#444444; stroke-width:1px;"%colors[tool_num%len(colors)], "gcodetools":"Gcodetools tool background"})
keys = []
g = inkex.etree.SubElement(tools_group, inkex.addNS('g','svg'), {'gcodetools': "Gcodetools tool parameter"})
draw_text(key, 0, y, group = g, gcodetools_tag = "Gcodetools tool definition field name", font_size = 10 if key!='name' else 20)
draw_text(param, 150, y, group = g, gcodetools_tag = "Gcodetools tool definition field value", font_size = 10 if key!='name' else 20)
tool = []
tools_group.set("transform", simpletransform.formatTransform([ [1,0,self.view_center[0]-150 ], [0,1,self.view_center[1]] ] ))
self.error(_("Selection is empty! Will compute whole drawing."),"selection_is_empty_will_comupe_drawing")
group = inkex.etree.SubElement( self.selected_paths.keys()[0] if len(self.selected_paths.keys())>0 else self.layers[0], inkex.addNS('g','svg') )
tools_bounds = {}
tools_bounds[layer] = tools_bounds[layer] if layer in tools_bounds else [float("inf"),float("-inf")]
style = "fill:%s; fill-opacity:%s; stroke:#000044; stroke-width:1; marker-mid:url(#CheckToolsAndOPMarker);" % (
trans = simpletransform.composeTransform( trans_, trans if trans != [] else [[1.,0.,0.],[0.,1.,0.]])
bounds = [min(bounds[0],path_bounds[0]), min(bounds[1],path_bounds[1]), max(bounds[2],path_bounds[2]), max(bounds[3],path_bounds[3])]
tools_bounds[layer] = [min(tools_bounds[layer][0], path_bounds[1]), max(tools_bounds[layer][1], path_bounds[3])]
self.error(_("""Tutorials, manuals and support can be found at\nEnglish support forum:\n http://www.cnc-club.ru/gcodetools\nand Russian support forum:\n http://www.cnc-club.ru/gcodetoolsru"""),"warning")
gcode = ("G01 %s %f %s %f" % (x, c[0][4][0], z, c[0][4][1]) ) + feed + "\n" # Just in case move to the start...
gcode += ("G02" if s[3]*flip_angle<0 else "G03") + (" %s %f %s %f %s %f %s %f" % (x,s[4][0],z,s[4][1],i_,(s[2][0]-s[0][0]), k_, (s[2][1]-s[0][1]) ) ) + feed + "\n"
gcode += ("G02" if s[3]*flip_angle<0 else "G03") + (" %s %f %s %f" % (x,s[4][0],z,y[4][1]) ) + " R%f"%r + feed + "\n"
return gcode
self.tool["passing feed"] = float(self.tool["passing feed"] if "passing feed" in self.tool else self.tool["feed"])
self.tool["fine feed"] = float(self.tool["fine feed"] if "fine feed" in self.tool else self.tool["feed"])
gcode += ( "(Change tool to %s)\n" % re.sub("\"'\(\)\\\\"," ",self.tool["name"]) ) + self.tool["tool change gcode"] + "\n"
offsetted_subpath = csp_subpath_line_to(subpath[:], [ [subpath[-1][1][0], miny[1]-r*10 ], [subpath[0][1][0], miny[1]-r*10 ], [subpath[0][1][0], subpath[0][1][1] ] ])
offsetted_subpath = csp_offset([offsetted_subpath], r if not csp_subpath_ccw(offsetted_subpath) else -r )
top_start, top_end = [subpath[0][1][0], self.options.lathe_width+self.options.Zsafe+self.options.lathe_fine_cut_width], [subpath[-1][1][0], self.options.lathe_width+self.options.Zsafe+self.options.lathe_fine_cut_width]
gcode += ("G01 %s %f %s %f F %f \n" % (x, top_start[0], z, top_start[1], self.tool["passing feed"]) )
intersections = []
intersections += [[j,k] for k in csp_line_intersection([bound[0]-10,current_width], [bound[2]+10,current_width], sp1, sp2)]
intersections += [[j,k] for k in csp_line_intersection([bound[0]-10,current_width+step], [bound[2]+10,current_width+step], sp1, sp2)]
top_start, top_end = [fine_cut[0][1][0], self.options.lathe_width+self.options.Zsafe+self.options.lathe_fine_cut_width], [fine_cut[-1][1][0], self.options.lathe_width+self.options.Zsafe+self.options.lathe_fine_cut_width]
gcode += "\n(Fine cutting start)\n(Calculating fine cut using %s)\n"%self.options.lathe_create_fine_cut_using
offsetted_subpath = csp_subpath_line_to(fine_cut[:], [ [fine_cut[-1][1][0], miny[1]-r*10 ], [fine_cut[0][1][0], miny[1]-r*10 ], [fine_cut[0][1][0], fine_cut[0][1][1] ] ])
offsetted_subpath = csp_offset([offsetted_subpath], width if not csp_subpath_ccw(offsetted_subpath) else -width )
gcode += ("G01 %s %f %s %f F %f \n" % (x, top_start[0], z, top_start[1], self.tool["passing feed"]) )
gcode += ("G01 %s %f %s %f F %f \n" % (x, current_pass[0][1][0], z, current_pass[0][1][1]+self.options.lathe_fine_cut_width, self.tool["passing feed"]) )
gcode += ("G01 %s %f %s %f F %f \n" % (x, current_pass[0][1][0], z, current_pass[0][1][1], self.tool["fine feed"]) )
gcode += ("G01 %s %f %s %f F %f \n" % (x, top_start[0], z, top_start[1], self.tool["passing feed"]) )
new_csp = []
last_n = None
new_subpath = []
new_subpath = []
if not first_seg and new_subpath==[] : new_subpath = [ [[subpath[0][i][0] - width*o ,subpath[0][i][1]] for i in range(3)] ]
import urllib
f = urllib.urlopen("http://www.cnc-club.ru/gcodetools_latest_version", proxies = urllib.getproxies())
a = f.read()
self.error("There is a newer version of Gcodetools you can get it at: \nhttp://www.cnc-club.ru/gcodetools (English version). \nhttp://www.cnc-club.ru/gcodetools_ru (Russian version). ","Warning")
self.error("Can not check the latest version. You can check it manualy at \nhttp://www.cnc-club.ru/gcodetools (English version). \nhttp://www.cnc-club.ru/gcodetools_ru (Russian version). \nCurrent version is Gcodetools %s"%gcodetools_current_version,"Warning")
self.error("Can not check the latest version. You can check it manualy at \nhttp://www.cnc-club.ru/gcodetools (English version). \nhttp://www.cnc-club.ru/gcodetools_ru (Russian version). \nCurrent version is Gcodetools %s"%gcodetools_current_version,"Warning")
pos = []
pos += [c]
def graffiti_preview_transform(x,y):
return [(x-tr[0]+1)*self.options.graffiti_preview_size/d, self.options.graffiti_preview_size - (y-tr[1]+1)*self.options.graffiti_preview_size/d]
x,y = graffiti_preview_transform(x,y)
#draw_csp(self.transform_csp([[ [[C1.x-r*sin,C1.y+r*cos]]*3,[[C2.x-r*sin,C2.y+r*cos]]*3 ]],layer,reverse=True), color = "#00ff00;" )
reference_points = None
if reference_points == None :
self.graffiti_reference_points[layer][i][0] = self.transform(self.graffiti_reference_points[layer][i][0], layer)
minx,miny,maxx,maxy = min(minx,point[0][0]), min(miny,point[0][1]), max(maxx,point[0][0]), max(maxy,point[0][1])
minx,miny,maxx,maxy = min(minx,bounds[0]), min(miny,bounds[1]), max(maxx,bounds[2]), max(maxy,bounds[3])
self.graffiti_preview = list([ [255]*(4*self.options.graffiti_preview_size) for i in range(self.options.graffiti_preview_size)])
gcode += ( "(Change tool to %s)\n" % re.sub("\"'\(\)\\\\"," ",self.tool["name"]) ) + self.tool["tool change gcode"] + "\n"
subpaths = []
polylines = []
del subpaths[i]
polylines += [
polyline = []
spl = None
if spl != None and abs(cross( csp_normalized_slope(spl,sp1,1.),csp_normalized_slope(sp1,sp2,0.) )) > 0.1 : # TODO add coefficient into inx
polylines += [
polyline = []
if polylines == [] : continue
polylines += [ ["connect1", [ [polylines[-1][1][-1][1] for i in range(3)],[start_point for i in range(3)] ] ] ]
polyline = []
print_(i)
last_state = None
draw_csp(self.transform_csp([csp],layer,reverse=True), color = "#00cc00;" if polyline_[0]=='draw' else "#ff5555;")
draw_graffiti_segment(layer,real_pos,last_real_pos,feed,color=(0,0,255,200) if polyline_[0] == "draw" else (255,0,0,200),emmit=self.options.graffiti_preview_emmit)
import png
writer = png.Writer(width=self.options.graffiti_preview_size, height=self.options.graffiti_preview_size, size=None, greyscale=False, alpha=True, bitdepth=8, palette=None, transparent=None, background=None, gamma=None, compression=None, interlace=False, bytes_per_sample=None, planes=None, colormap=None, maxval=None, chunk_limit=1048576)
f.close()
global options
global print_
f.write("Gcodetools log file.\nStarted at %s.\n%s\n" % (time.strftime("%d.%m.%Y %H:%M:%S"),options.log_filename))
f.close()
print_ = lambda *x : None
else : print_ = lambda *x : None
elif self.options.active_tab not in ['"dxfpoints"','"path-to-gcode"', '"area_fill"', '"area"', '"area_artefacts"', '"engraving"', '"orientation"', '"tools_library"', '"lathe"', '"offset"', '"arrangement"', '"update"', '"graffiti"', '"lathe_modify_path"', '"plasma-prepare-path"']:
self.error(_("Select one of the action tabs - Path to Gcode, Area, Engraving, DXF points, Orientation, Offset, Lathe or Tools library.\n Current active tab id is %s" % self.options.active_tab),"error")
if self.options.active_tab in ['"dxfpoints"','"path-to-gcode"', '"area_fill"', '"area"', '"area_artefacts"', '"engraving"', '"lathe"', '"graffiti"', '"plasma-prepare-path"']:
self.error(_("Orientation points have not been defined! A default set of orientation points has been automatically added."),"warning")
self.error(_("Cutting tool has not been defined! A default tool has been automatically added."),"warning")
csp1, csp2 = cubicsuperpath.parsePath(self.selected_paths[layer][0].get("d")), cubicsuperpath.parsePath(self.selected_paths[layer][1].get("d"))
+list(csp_at_t(csp2[dist[4]][dist[5]-1],csp2[dist[4]][dist[5]],dist[6])),"red","line", comment = math.sqrt(dist[0]))
if offset_ != [] :
print_()
print_()