Extensive Path Workbench improvements.

Implement libarea improvements for profile
Implement libarea pocketing.
consolidate occ and libarea pocketing operation into one with algorithm
switch
consolidate occ aand libarea profile op into one with algorithm switch
add basic engraving operation.
Add rough UI for profile holding tags
implement holding tags for libarea profile.
implement basic defaults for depth settings.
First move in Drilling is rapid to clearance height.

UI needs lots of work but is usable.
This commit is contained in:
sliptonic
2016-02-24 09:02:25 -06:00
committed by Yorik van Havre
parent a55f676134
commit b67f6f1886
71 changed files with 11954 additions and 727 deletions

View File

@@ -48,7 +48,7 @@ SET(PathScripts_SRCS
PathScripts/PathFromShape.py
PathScripts/DlgSettingsPath.ui
PathScripts/PathKurveUtils.py
PathScripts/PathKurve.py
PathScripts/PathAreaUtils.py
PathScripts/slic3r_pre.py
PathScripts/PathFaceProfile.py
PathScripts/PathFacePocket.py
@@ -56,6 +56,13 @@ SET(PathScripts_SRCS
PathScripts/PathCustom.py
PathScripts/PathInspect.py
PathScripts/PathSimpleCopy.py
PathScripts/PathEngrave.py
PathScripts/nc/nc.py
PathScripts/nc/iso.py
PathScripts/nc/__init__.py
PathScripts/nc/format.py
PathScripts/nc/iso_codes.py
)
ADD_CUSTOM_TARGET(PathScripts ALL

View File

@@ -30,7 +30,7 @@
<file>icons/Path-Inspect.svg</file>
<file>icons/Path-ToolChange.svg</file>
<file>icons/Path-SimpleCopy.svg</file>
<file>icons/PathWorkbench.svg</file>
<file>icons/Path-Engrave.svg</file>
<file>translations/Path_de.qm</file>
<file>translations/Path_af.qm</file>
<file>translations/Path_zh-CN.qm</file>

View File

@@ -0,0 +1,564 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2816"
version="1.1"
inkscape:version="0.91 r"
sodipodi:docname="Path-Engrave.svg">
<defs
id="defs2818">
<linearGradient
id="linearGradient4513">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4515" />
<stop
style="stop-color:#999999;stop-opacity:1;"
offset="1"
id="stop4517" />
</linearGradient>
<linearGradient
id="linearGradient3681">
<stop
id="stop3697"
offset="0"
style="stop-color:#fff110;stop-opacity:1;" />
<stop
style="stop-color:#cf7008;stop-opacity:1;"
offset="1"
id="stop3685" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective2824" />
<inkscape:perspective
id="perspective3622"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3622-9"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3653"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3675"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3697"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3720"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3742"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3764"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3785"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3806"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3806-3"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3835"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3614"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3614-8"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3643"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3643-3"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3672"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3672-5"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3701"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3701-8"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3746"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<pattern
patternTransform="matrix(0.67643728,-0.81829155,2.4578314,1.8844554,-26.450606,18.294947)"
id="pattern5231"
xlink:href="#Strips1_1-4"
inkscape:collect="always" />
<inkscape:perspective
id="perspective5224"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<pattern
inkscape:stockid="Stripes 1:1"
id="Strips1_1-4"
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
height="1"
width="2"
patternUnits="userSpaceOnUse"
inkscape:collect="always">
<rect
id="rect4483-4"
height="2"
width="1"
y="-0.5"
x="0"
style="fill:black;stroke:none" />
</pattern>
<inkscape:perspective
id="perspective5224-9"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<pattern
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,39.618381,8.9692804)"
id="pattern5231-4"
xlink:href="#Strips1_1-6"
inkscape:collect="always" />
<inkscape:perspective
id="perspective5224-3"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<pattern
inkscape:stockid="Stripes 1:1"
id="Strips1_1-6"
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
height="1"
width="2"
patternUnits="userSpaceOnUse"
inkscape:collect="always">
<rect
id="rect4483-0"
height="2"
width="1"
y="-0.5"
x="0"
style="fill:black;stroke:none" />
</pattern>
<pattern
patternTransform="matrix(0.66513382,-1.0631299,2.4167603,2.4482973,-49.762569,2.9546807)"
id="pattern5296"
xlink:href="#pattern5231-3"
inkscape:collect="always" />
<inkscape:perspective
id="perspective5288"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<pattern
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,-26.336284,10.887197)"
id="pattern5231-3"
xlink:href="#Strips1_1-4-3"
inkscape:collect="always" />
<pattern
inkscape:stockid="Stripes 1:1"
id="Strips1_1-4-3"
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
height="1"
width="2"
patternUnits="userSpaceOnUse"
inkscape:collect="always">
<rect
id="rect4483-4-6"
height="2"
width="1"
y="-0.5"
x="0"
style="fill:black;stroke:none" />
</pattern>
<pattern
patternTransform="matrix(0.42844886,-0.62155849,1.5567667,1.431396,27.948414,13.306456)"
id="pattern5330"
xlink:href="#Strips1_1-9"
inkscape:collect="always" />
<inkscape:perspective
id="perspective5323"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<pattern
inkscape:stockid="Stripes 1:1"
id="Strips1_1-9"
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
height="1"
width="2"
patternUnits="userSpaceOnUse"
inkscape:collect="always">
<rect
id="rect4483-3"
height="2"
width="1"
y="-0.5"
x="0"
style="fill:black;stroke:none" />
</pattern>
<inkscape:perspective
id="perspective5361"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective5383"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective5411"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3681"
id="linearGradient3687"
x1="37.89756"
y1="41.087898"
x2="4.0605712"
y2="40.168594"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(127.27273,-51.272729)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3681"
id="linearGradient3695"
x1="37.894287"
y1="40.484772"
x2="59.811455"
y2="43.558987"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(127.27273,-51.272729)" />
<linearGradient
id="linearGradient3681-3">
<stop
id="stop3697-3"
offset="0"
style="stop-color:#fff110;stop-opacity:1;" />
<stop
style="stop-color:#cf7008;stop-opacity:1;"
offset="1"
id="stop3685-4" />
</linearGradient>
<linearGradient
y2="43.558987"
x2="59.811455"
y1="40.484772"
x1="37.894287"
gradientTransform="translate(-37.00068,-20.487365)"
gradientUnits="userSpaceOnUse"
id="linearGradient3608"
xlink:href="#linearGradient3681-3"
inkscape:collect="always" />
<linearGradient
id="linearGradient4513-2">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4515-2" />
<stop
style="stop-color:#999999;stop-opacity:1;"
offset="1"
id="stop4517-4" />
</linearGradient>
<radialGradient
r="23.634638"
fy="7.9319997"
fx="32.151962"
cy="7.9319997"
cx="32.151962"
gradientTransform="matrix(1,0,0,1.1841158,-8.5173246,-3.4097568)"
gradientUnits="userSpaceOnUse"
id="radialGradient4538"
xlink:href="#linearGradient4513-2"
inkscape:collect="always" />
<linearGradient
id="linearGradient4513-1">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4515-8" />
<stop
style="stop-color:#999999;stop-opacity:1;"
offset="1"
id="stop4517-6" />
</linearGradient>
<radialGradient
r="23.634638"
fy="7.9319997"
fx="32.151962"
cy="7.9319997"
cx="32.151962"
gradientTransform="matrix(1,0,0,1.1841158,-8.5173246,-3.4097568)"
gradientUnits="userSpaceOnUse"
id="radialGradient4538-6"
xlink:href="#linearGradient4513-1"
inkscape:collect="always" />
<linearGradient
id="linearGradient4513-1-3">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4515-8-7" />
<stop
style="stop-color:#999999;stop-opacity:1;"
offset="1"
id="stop4517-6-5" />
</linearGradient>
<radialGradient
r="23.634638"
fy="35.869175"
fx="32.151962"
cy="35.869175"
cx="32.151962"
gradientTransform="matrix(0.39497909,0,0,1.1841158,-2.716491,-26.067007)"
gradientUnits="userSpaceOnUse"
id="radialGradient3069"
xlink:href="#linearGradient4513-1-3"
inkscape:collect="always" />
<linearGradient
id="linearGradient4513-1-2">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4515-8-6" />
<stop
style="stop-color:#999999;stop-opacity:1;"
offset="1"
id="stop4517-6-6" />
</linearGradient>
<radialGradient
r="23.634638"
fy="35.869175"
fx="32.151962"
cy="35.869175"
cx="32.151962"
gradientTransform="matrix(0.39497909,0,0,1.1841158,-2.716491,-26.067007)"
gradientUnits="userSpaceOnUse"
id="radialGradient3102"
xlink:href="#linearGradient4513-1-2"
inkscape:collect="always" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4513-1"
id="radialGradient3132"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.39492727,-0.00639802,0.01748379,1.079213,34.386898,-11.189684)"
cx="32.151962"
cy="27.950663"
fx="32.151962"
fy="27.950663"
r="23.634638" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="7.26"
inkscape:cx="34.476174"
inkscape:cy="18.296628"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:object-paths="true"
inkscape:object-nodes="true"
inkscape:window-width="1135"
inkscape:window-height="1011"
inkscape:window-x="1565"
inkscape:window-y="18"
inkscape:window-maximized="0"
showguides="true"
inkscape:guide-bbox="true"
inkscape:snap-global="false">
<sodipodi:guide
position="59.366391,72.589532"
orientation="1,0"
id="guide3413" />
<sodipodi:guide
position="3.030303,65.977961"
orientation="1,0"
id="guide4224" />
</sodipodi:namedview>
<metadata
id="metadata2821">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g4219"
transform="translate(0,-0.68870523)">
<g
transform="matrix(1,0,0,-1,0,64.339618)"
id="g4215">
<path
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#008b00;stroke-width:7.83799982;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="M 60.870664,22.409685 58.093027,22.39655 34.425961,16.875046 4.1315809,34.023011 1.6689283,33.986452"
id="path3120"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#0047ff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.69342875;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="M 59.366391,5.835916 3.030303,5.2849518 l 0,24.8629482 30.719784,-17.771608 15.562973,4.856018 0.0585,8.594739 L 35.795455,21.173726 2.9137398,39.116391 2.7759987,58.503702 59.366391,58.779184 Z"
id="rect3105"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccc" />
</g>
</g>
<path
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient3132);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.97430003;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 38.577556,-2.8329968 0,17.4659098 0,8.59375 17.343749,-8.59375 0,-1.90625 0,-15.5596598 c -6.568186,-0.067747 -11.804952,0.099686 -17.343749,0 z m 17.343749,22.5596598 -17.343749,8.5625 0,7.03125 17.343749,-8.59375 z m 0,12.09375 -14.562499,7.21875 5.937499,3.90625 8.625,-5.71875 z"
id="rect4417"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,553 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2816"
version="1.1"
inkscape:version="0.91 r"
sodipodi:docname="Path-Tags.svg">
<defs
id="defs2818">
<linearGradient
id="linearGradient4513">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4515" />
<stop
style="stop-color:#999999;stop-opacity:1;"
offset="1"
id="stop4517" />
</linearGradient>
<linearGradient
id="linearGradient3681">
<stop
id="stop3697"
offset="0"
style="stop-color:#fff110;stop-opacity:1;" />
<stop
style="stop-color:#cf7008;stop-opacity:1;"
offset="1"
id="stop3685" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective2824" />
<inkscape:perspective
id="perspective3622"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3622-9"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3653"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3675"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3697"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3720"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3742"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3764"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3785"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3806"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3806-3"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3835"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3614"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3614-8"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3643"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3643-3"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3672"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3672-5"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3701"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3701-8"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3746"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<pattern
patternTransform="matrix(0.67643728,-0.81829155,2.4578314,1.8844554,-26.450606,18.294947)"
id="pattern5231"
xlink:href="#Strips1_1-4"
inkscape:collect="always" />
<inkscape:perspective
id="perspective5224"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<pattern
inkscape:stockid="Stripes 1:1"
id="Strips1_1-4"
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
height="1"
width="2"
patternUnits="userSpaceOnUse"
inkscape:collect="always">
<rect
id="rect4483-4"
height="2"
width="1"
y="-0.5"
x="0"
style="fill:black;stroke:none" />
</pattern>
<inkscape:perspective
id="perspective5224-9"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<pattern
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,39.618381,8.9692804)"
id="pattern5231-4"
xlink:href="#Strips1_1-6"
inkscape:collect="always" />
<inkscape:perspective
id="perspective5224-3"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<pattern
inkscape:stockid="Stripes 1:1"
id="Strips1_1-6"
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
height="1"
width="2"
patternUnits="userSpaceOnUse"
inkscape:collect="always">
<rect
id="rect4483-0"
height="2"
width="1"
y="-0.5"
x="0"
style="fill:black;stroke:none" />
</pattern>
<pattern
patternTransform="matrix(0.66513382,-1.0631299,2.4167603,2.4482973,-49.762569,2.9546807)"
id="pattern5296"
xlink:href="#pattern5231-3"
inkscape:collect="always" />
<inkscape:perspective
id="perspective5288"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<pattern
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,-26.336284,10.887197)"
id="pattern5231-3"
xlink:href="#Strips1_1-4-3"
inkscape:collect="always" />
<pattern
inkscape:stockid="Stripes 1:1"
id="Strips1_1-4-3"
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
height="1"
width="2"
patternUnits="userSpaceOnUse"
inkscape:collect="always">
<rect
id="rect4483-4-6"
height="2"
width="1"
y="-0.5"
x="0"
style="fill:black;stroke:none" />
</pattern>
<pattern
patternTransform="matrix(0.42844886,-0.62155849,1.5567667,1.431396,27.948414,13.306456)"
id="pattern5330"
xlink:href="#Strips1_1-9"
inkscape:collect="always" />
<inkscape:perspective
id="perspective5323"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<pattern
inkscape:stockid="Stripes 1:1"
id="Strips1_1-9"
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
height="1"
width="2"
patternUnits="userSpaceOnUse"
inkscape:collect="always">
<rect
id="rect4483-3"
height="2"
width="1"
y="-0.5"
x="0"
style="fill:black;stroke:none" />
</pattern>
<inkscape:perspective
id="perspective5361"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective5383"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective5411"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3681"
id="linearGradient3687"
x1="37.89756"
y1="41.087898"
x2="4.0605712"
y2="40.168594"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(127.27273,-51.272729)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3681"
id="linearGradient3695"
x1="37.894287"
y1="40.484772"
x2="59.811455"
y2="43.558987"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(127.27273,-51.272729)" />
<linearGradient
id="linearGradient3681-3">
<stop
id="stop3697-3"
offset="0"
style="stop-color:#fff110;stop-opacity:1;" />
<stop
style="stop-color:#cf7008;stop-opacity:1;"
offset="1"
id="stop3685-4" />
</linearGradient>
<linearGradient
y2="43.558987"
x2="59.811455"
y1="40.484772"
x1="37.894287"
gradientTransform="translate(-37.00068,-20.487365)"
gradientUnits="userSpaceOnUse"
id="linearGradient3608"
xlink:href="#linearGradient3681-3"
inkscape:collect="always" />
<linearGradient
id="linearGradient4513-2">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4515-2" />
<stop
style="stop-color:#999999;stop-opacity:1;"
offset="1"
id="stop4517-4" />
</linearGradient>
<radialGradient
r="23.634638"
fy="7.9319997"
fx="32.151962"
cy="7.9319997"
cx="32.151962"
gradientTransform="matrix(1,0,0,1.1841158,-8.5173246,-3.4097568)"
gradientUnits="userSpaceOnUse"
id="radialGradient4538"
xlink:href="#linearGradient4513-2"
inkscape:collect="always" />
<linearGradient
id="linearGradient4513-1">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4515-8" />
<stop
style="stop-color:#999999;stop-opacity:1;"
offset="1"
id="stop4517-6" />
</linearGradient>
<radialGradient
r="23.634638"
fy="7.9319997"
fx="32.151962"
cy="7.9319997"
cx="32.151962"
gradientTransform="matrix(1,0,0,1.1841158,-8.5173246,-3.4097568)"
gradientUnits="userSpaceOnUse"
id="radialGradient4538-6"
xlink:href="#linearGradient4513-1"
inkscape:collect="always" />
<linearGradient
id="linearGradient4513-1-3">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4515-8-7" />
<stop
style="stop-color:#999999;stop-opacity:1;"
offset="1"
id="stop4517-6-5" />
</linearGradient>
<radialGradient
r="23.634638"
fy="35.869175"
fx="32.151962"
cy="35.869175"
cx="32.151962"
gradientTransform="matrix(0.39497909,0,0,1.1841158,-2.716491,-26.067007)"
gradientUnits="userSpaceOnUse"
id="radialGradient3069"
xlink:href="#linearGradient4513-1-3"
inkscape:collect="always" />
<linearGradient
id="linearGradient4513-1-2">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4515-8-6" />
<stop
style="stop-color:#999999;stop-opacity:1;"
offset="1"
id="stop4517-6-6" />
</linearGradient>
<radialGradient
r="23.634638"
fy="35.869175"
fx="32.151962"
cy="35.869175"
cx="32.151962"
gradientTransform="matrix(0.39497909,0,0,1.1841158,-2.716491,-26.067007)"
gradientUnits="userSpaceOnUse"
id="radialGradient3102"
xlink:href="#linearGradient4513-1-2"
inkscape:collect="always" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4513-1"
id="radialGradient3132"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.39497909,0,0,1.1841158,38.034399,-9.2566343)"
cx="32.151962"
cy="27.950663"
fx="32.151962"
fy="27.950663"
r="23.634638" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.5"
inkscape:cx="9.584261"
inkscape:cy="24.706488"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:object-paths="true"
inkscape:object-nodes="true"
inkscape:window-width="1370"
inkscape:window-height="1011"
inkscape:window-x="1330"
inkscape:window-y="18"
inkscape:window-maximized="0"
inkscape:snap-global="false" />
<metadata
id="metadata2821">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g4209"
transform="matrix(-0.59592352,0.72506943,-0.6244145,-0.69198574,71.807132,55.52075)">
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path3083"
d="M 5.1362221,8.0043212 17.703439,20.925091 M 42.837872,46.76663 55.405088,59.6874"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#008b00;stroke-width:9;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
inkscape:connector-curvature="0"
id="path3085"
d="M 17.703439,20.925091 42.837872,46.76663"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#008b00;stroke-width:9;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4.5, 4.5;stroke-dashoffset:15.30000019;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
inkscape:connector-curvature="0"
id="path3878"
d="M 45.834047,49.847096 C 40.262009,44.1183 24.035259,54.287675 19.149794,48.759385 14.264328,43.231096 15.935672,45.545264 9.7645576,38.474196 3.5934436,31.403128 17.703439,20.925091 13.314693,16.412877 l -1.547279,-1.590808"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#89de00;stroke-width:9;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
</g>
<path
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient3132);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.97430003;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 41.738039,2.2378637 0,17.4659093 c 0,0 0,1.310757 0,8.59375 l 17.343751,-8.59375 0,-1.90625 0,-15.5596593 z m 17.343751,22.5596593 -17.343751,8.5625 0,7.03125 17.343751,-8.59375 z m 0,12.09375 -14.562501,7.21875 5.9375,3.90625 8.625001,-5.71875 z"
id="rect4417"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,553 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2816"
version="1.1"
inkscape:version="0.91 r"
sodipodi:docname="Path-Tags.svg">
<defs
id="defs2818">
<linearGradient
id="linearGradient4513">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4515" />
<stop
style="stop-color:#999999;stop-opacity:1;"
offset="1"
id="stop4517" />
</linearGradient>
<linearGradient
id="linearGradient3681">
<stop
id="stop3697"
offset="0"
style="stop-color:#fff110;stop-opacity:1;" />
<stop
style="stop-color:#cf7008;stop-opacity:1;"
offset="1"
id="stop3685" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective2824" />
<inkscape:perspective
id="perspective3622"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3622-9"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3653"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3675"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3697"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3720"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3742"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3764"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3785"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3806"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3806-3"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3835"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3614"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3614-8"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3643"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3643-3"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3672"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3672-5"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3701"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3701-8"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3746"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<pattern
patternTransform="matrix(0.67643728,-0.81829155,2.4578314,1.8844554,-26.450606,18.294947)"
id="pattern5231"
xlink:href="#Strips1_1-4"
inkscape:collect="always" />
<inkscape:perspective
id="perspective5224"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<pattern
inkscape:stockid="Stripes 1:1"
id="Strips1_1-4"
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
height="1"
width="2"
patternUnits="userSpaceOnUse"
inkscape:collect="always">
<rect
id="rect4483-4"
height="2"
width="1"
y="-0.5"
x="0"
style="fill:black;stroke:none" />
</pattern>
<inkscape:perspective
id="perspective5224-9"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<pattern
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,39.618381,8.9692804)"
id="pattern5231-4"
xlink:href="#Strips1_1-6"
inkscape:collect="always" />
<inkscape:perspective
id="perspective5224-3"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<pattern
inkscape:stockid="Stripes 1:1"
id="Strips1_1-6"
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
height="1"
width="2"
patternUnits="userSpaceOnUse"
inkscape:collect="always">
<rect
id="rect4483-0"
height="2"
width="1"
y="-0.5"
x="0"
style="fill:black;stroke:none" />
</pattern>
<pattern
patternTransform="matrix(0.66513382,-1.0631299,2.4167603,2.4482973,-49.762569,2.9546807)"
id="pattern5296"
xlink:href="#pattern5231-3"
inkscape:collect="always" />
<inkscape:perspective
id="perspective5288"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<pattern
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,-26.336284,10.887197)"
id="pattern5231-3"
xlink:href="#Strips1_1-4-3"
inkscape:collect="always" />
<pattern
inkscape:stockid="Stripes 1:1"
id="Strips1_1-4-3"
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
height="1"
width="2"
patternUnits="userSpaceOnUse"
inkscape:collect="always">
<rect
id="rect4483-4-6"
height="2"
width="1"
y="-0.5"
x="0"
style="fill:black;stroke:none" />
</pattern>
<pattern
patternTransform="matrix(0.42844886,-0.62155849,1.5567667,1.431396,27.948414,13.306456)"
id="pattern5330"
xlink:href="#Strips1_1-9"
inkscape:collect="always" />
<inkscape:perspective
id="perspective5323"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<pattern
inkscape:stockid="Stripes 1:1"
id="Strips1_1-9"
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
height="1"
width="2"
patternUnits="userSpaceOnUse"
inkscape:collect="always">
<rect
id="rect4483-3"
height="2"
width="1"
y="-0.5"
x="0"
style="fill:black;stroke:none" />
</pattern>
<inkscape:perspective
id="perspective5361"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective5383"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective5411"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3681"
id="linearGradient3687"
x1="37.89756"
y1="41.087898"
x2="4.0605712"
y2="40.168594"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(127.27273,-51.272729)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3681"
id="linearGradient3695"
x1="37.894287"
y1="40.484772"
x2="59.811455"
y2="43.558987"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(127.27273,-51.272729)" />
<linearGradient
id="linearGradient3681-3">
<stop
id="stop3697-3"
offset="0"
style="stop-color:#fff110;stop-opacity:1;" />
<stop
style="stop-color:#cf7008;stop-opacity:1;"
offset="1"
id="stop3685-4" />
</linearGradient>
<linearGradient
y2="43.558987"
x2="59.811455"
y1="40.484772"
x1="37.894287"
gradientTransform="translate(-37.00068,-20.487365)"
gradientUnits="userSpaceOnUse"
id="linearGradient3608"
xlink:href="#linearGradient3681-3"
inkscape:collect="always" />
<linearGradient
id="linearGradient4513-2">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4515-2" />
<stop
style="stop-color:#999999;stop-opacity:1;"
offset="1"
id="stop4517-4" />
</linearGradient>
<radialGradient
r="23.634638"
fy="7.9319997"
fx="32.151962"
cy="7.9319997"
cx="32.151962"
gradientTransform="matrix(1,0,0,1.1841158,-8.5173246,-3.4097568)"
gradientUnits="userSpaceOnUse"
id="radialGradient4538"
xlink:href="#linearGradient4513-2"
inkscape:collect="always" />
<linearGradient
id="linearGradient4513-1">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4515-8" />
<stop
style="stop-color:#999999;stop-opacity:1;"
offset="1"
id="stop4517-6" />
</linearGradient>
<radialGradient
r="23.634638"
fy="7.9319997"
fx="32.151962"
cy="7.9319997"
cx="32.151962"
gradientTransform="matrix(1,0,0,1.1841158,-8.5173246,-3.4097568)"
gradientUnits="userSpaceOnUse"
id="radialGradient4538-6"
xlink:href="#linearGradient4513-1"
inkscape:collect="always" />
<linearGradient
id="linearGradient4513-1-3">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4515-8-7" />
<stop
style="stop-color:#999999;stop-opacity:1;"
offset="1"
id="stop4517-6-5" />
</linearGradient>
<radialGradient
r="23.634638"
fy="35.869175"
fx="32.151962"
cy="35.869175"
cx="32.151962"
gradientTransform="matrix(0.39497909,0,0,1.1841158,-2.716491,-26.067007)"
gradientUnits="userSpaceOnUse"
id="radialGradient3069"
xlink:href="#linearGradient4513-1-3"
inkscape:collect="always" />
<linearGradient
id="linearGradient4513-1-2">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4515-8-6" />
<stop
style="stop-color:#999999;stop-opacity:1;"
offset="1"
id="stop4517-6-6" />
</linearGradient>
<radialGradient
r="23.634638"
fy="35.869175"
fx="32.151962"
cy="35.869175"
cx="32.151962"
gradientTransform="matrix(0.39497909,0,0,1.1841158,-2.716491,-26.067007)"
gradientUnits="userSpaceOnUse"
id="radialGradient3102"
xlink:href="#linearGradient4513-1-2"
inkscape:collect="always" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4513-1"
id="radialGradient3132"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.39497909,0,0,1.1841158,38.034399,-9.2566343)"
cx="32.151962"
cy="27.950663"
fx="32.151962"
fy="27.950663"
r="23.634638" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.5"
inkscape:cx="9.584261"
inkscape:cy="24.706488"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:object-paths="true"
inkscape:object-nodes="true"
inkscape:window-width="1370"
inkscape:window-height="1011"
inkscape:window-x="1330"
inkscape:window-y="18"
inkscape:window-maximized="0"
inkscape:snap-global="false" />
<metadata
id="metadata2821">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g4209"
transform="matrix(-0.59592352,0.72506943,-0.6244145,-0.69198574,71.807132,55.52075)">
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path3083"
d="M 5.1362221,8.0043212 17.703439,20.925091 M 42.837872,46.76663 55.405088,59.6874"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#008b00;stroke-width:9;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
inkscape:connector-curvature="0"
id="path3085"
d="M 17.703439,20.925091 42.837872,46.76663"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#008b00;stroke-width:9;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4.5, 4.5;stroke-dashoffset:15.30000019;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
inkscape:connector-curvature="0"
id="path3878"
d="M 45.834047,49.847096 C 40.262009,44.1183 24.035259,54.287675 19.149794,48.759385 14.264328,43.231096 15.935672,45.545264 9.7645576,38.474196 3.5934436,31.403128 17.703439,20.925091 13.314693,16.412877 l -1.547279,-1.590808"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#89de00;stroke-width:9;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
</g>
<path
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient3132);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.97430003;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 41.738039,2.2378637 0,17.4659093 c 0,0 0,1.310757 0,8.59375 l 17.343751,-8.59375 0,-1.90625 0,-15.5596593 z m 17.343751,22.5596593 -17.343751,8.5625 0,7.03125 17.343751,-8.59375 z m 0,12.09375 -14.562501,7.21875 5.9375,3.90625 8.625001,-5.71875 z"
id="rect4417"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -56,19 +56,18 @@ class PathWorkbench ( Workbench ):
from PathScripts import PathStop
from PathScripts import PathMachine
from PathScripts import PathFromShape
from PathScripts import PathKurve
from PathScripts import PathArray
from PathScripts import PathFaceProfile
from PathScripts import PathFacePocket
from PathScripts import PathCustom
from PathScripts import PathInspect
from PathScripts import PathSimpleCopy
from PathScripts import PathEngrave
# build commands list
projcmdlist = ["Path_Project", "Path_ToolTableEdit","Path_Post","Path_Inspect"]
prepcmdlist = ["Path_Plane","Path_Fixture","Path_LoadTool","Path_ToolLenOffset","Path_Comment","Path_Stop",
"Path_FaceProfile","Path_FacePocket","Path_Custom","Path_FromShape"]
opcmdlist = ["Path_Profile","Path_Kurve","Path_Pocket","Path_Drilling"]
prepcmdlist = ["Path_Plane","Path_Fixture","Path_LoadTool","Path_ToolLenOffset","Path_Comment","Path_Stop","Path_FaceProfile","Path_FacePocket","Path_Custom","Path_FromShape"]
opcmdlist = ["Path_Profile","Path_Pocket","Path_Drilling","Path_Engrave"]
modcmdlist = ["Path_Copy","Path_CompoundExtended","Path_Dressup","Path_Hop","Path_Array","Path_SimpleCopy"]

View File

@@ -0,0 +1,435 @@
import area
from nc.nc import *
import PathScripts.nc.iso
import math
import PathKurveUtils
# some globals, to save passing variables as parameters too much
area_for_feed_possible = None
tool_radius_for_pocket = None
def cut_curve(curve, need_rapid, p, rapid_safety_space, current_start_depth, final_depth):
prev_p = p
first = True
for vertex in curve.getVertices():
if need_rapid and first:
# rapid across
rapid(vertex.p.x, vertex.p.y)
##rapid down
rapid(z = current_start_depth + rapid_safety_space)
#feed down
feed(z = final_depth)
first = False
else:
if vertex.type == 1:
arc_ccw(vertex.p.x, vertex.p.y, i = vertex.c.x, j = vertex.c.y)
elif vertex.type == -1:
arc_cw(vertex.p.x, vertex.p.y, i = vertex.c.x, j = vertex.c.y)
else:
feed(vertex.p.x, vertex.p.y)
prev_p = vertex.p
return prev_p
def area_distance(a, old_area):
best_dist = None
for curve in a.getCurves():
for vertex in curve.getVertices():
c = old_area.NearestPoint(vertex.p)
d = c.dist(vertex.p)
if best_dist == None or d < best_dist:
best_dist = d
for curve in old_area.getCurves():
for vertex in curve.getVertices():
c = a.NearestPoint(vertex.p)
d = c.dist(vertex.p)
if best_dist == None or d < best_dist:
best_dist = d
return best_dist
def make_obround(p0, p1, radius):
dir = p1 - p0
d = dir.length()
dir.normalize()
right = area.Point(dir.y, -dir.x)
obround = area.Area()
c = area.Curve()
vt0 = p0 + right * radius
vt1 = p1 + right * radius
vt2 = p1 - right * radius
vt3 = p0 - right * radius
c.append(area.Vertex(0, vt0, area.Point(0, 0)))
c.append(area.Vertex(0, vt1, area.Point(0, 0)))
c.append(area.Vertex(1, vt2, p1))
c.append(area.Vertex(0, vt3, area.Point(0, 0)))
c.append(area.Vertex(1, vt0, p0))
obround.append(c)
return obround
def feed_possible(p0, p1):
if p0 == p1:
return True
obround = make_obround(p0, p1, tool_radius_for_pocket)
a = area.Area(area_for_feed_possible)
obround.Subtract(a)
if obround.num_curves() > 0:
return False
return True
def cut_curvelist1(curve_list, rapid_safety_space, current_start_depth, depth, clearance_height, keep_tool_down_if_poss):
p = area.Point(0, 0)
first = True
for curve in curve_list:
need_rapid = True
if first == False:
s = curve.FirstVertex().p
if keep_tool_down_if_poss == True:
# see if we can feed across
if feed_possible(p, s):
need_rapid = False
elif s.x == p.x and s.y == p.y:
need_rapid = False
if need_rapid:
rapid(z = clearance_height)
p = cut_curve(curve, need_rapid, p, rapid_safety_space, current_start_depth, depth)
first = False
rapid(z = clearance_height)
def cut_curvelist2(curve_list, rapid_safety_space, current_start_depth, depth, clearance_height, keep_tool_down_if_poss,start_point):
p = area.Point(0, 0)
start_x,start_y=start_point
first = True
for curve in curve_list:
need_rapid = True
if first == True:
direction = "on";radius = 0.0;offset_extra = 0.0; roll_radius = 0.0;roll_on = 0.0; roll_off = 0.0; rapid_safety_space; step_down = math.fabs(depth);extend_at_start = 0.0;extend_at_end = 0.0
kurve_funcs.make_smaller( curve, start = area.Point(start_x,start_y))
kurve_funcs.profile(curve, direction, radius , offset_extra, roll_radius, roll_on, roll_off, rapid_safety_space , clearance_height, current_start_depth, step_down , depth, extend_at_start, extend_at_end)
else:
s = curve.FirstVertex().p
if keep_tool_down_if_poss == True:
# see if we can feed across
if feed_possible(p, s):
need_rapid = False
elif s.x == p.x and s.y == p.y:
need_rapid = False
cut_curve(curve, need_rapid, p, rapid_safety_space, current_start_depth, depth)
first = False #change to True if you want to rapid back to start side before zigging again with unidirectional set
rapid(z = clearance_height)
def recur(arealist, a1, stepover, from_center):
# this makes arealist by recursively offsetting a1 inwards
if a1.num_curves() == 0:
return
if from_center:
arealist.insert(0, a1)
else:
arealist.append(a1)
a_offset = area.Area(a1)
a_offset.Offset(stepover)
# split curves into new areas
if area.holes_linked():
for curve in a_offset.getCurves():
a2 = area.Area()
a2.append(curve)
recur(arealist, a2, stepover, from_center)
else:
# split curves into new areas
a_offset.Reorder()
a2 = None
for curve in a_offset.getCurves():
if curve.IsClockwise():
if a2 != None:
a2.append(curve)
else:
if a2 != None:
recur(arealist, a2, stepover, from_center)
a2 = area.Area()
a2.append(curve)
if a2 != None:
recur(arealist, a2, stepover, from_center)
def get_curve_list(arealist, reverse_curves = False):
curve_list = list()
for a in arealist:
for curve in a.getCurves():
if reverse_curves == True:
curve.Reverse()
curve_list.append(curve)
return curve_list
curve_list_for_zigs = []
rightward_for_zigs = True
sin_angle_for_zigs = 0.0
cos_angle_for_zigs = 1.0
sin_minus_angle_for_zigs = 0.0
cos_minus_angle_for_zigs = 1.0
one_over_units = 1.0
def make_zig_curve(curve, y0, y, zig_unidirectional):
if rightward_for_zigs:
curve.Reverse()
# find a high point to start looking from
high_point = None
for vertex in curve.getVertices():
if high_point == None:
high_point = vertex.p
elif vertex.p.y > high_point.y:
# use this as the new high point
high_point = vertex.p
elif math.fabs(vertex.p.y - high_point.y) < 0.002 * one_over_units:
# equal high point
if rightward_for_zigs:
# use the furthest left point
if vertex.p.x < high_point.x:
high_point = vertex.p
else:
# use the furthest right point
if vertex.p.x > high_point.x:
high_point = vertex.p
zig = area.Curve()
high_point_found = False
zig_started = False
zag_found = False
for i in range(0, 2): # process the curve twice because we don't know where it will start
prev_p = None
for vertex in curve.getVertices():
if zag_found: break
if prev_p != None:
if zig_started:
zig.append(unrotated_vertex(vertex))
if math.fabs(vertex.p.y - y) < 0.002 * one_over_units:
zag_found = True
break
elif high_point_found:
if math.fabs(vertex.p.y - y0) < 0.002 * one_over_units:
if zig_started:
zig.append(unrotated_vertex(vertex))
elif math.fabs(prev_p.y - y0) < 0.002 * one_over_units and vertex.type == 0:
zig.append(area.Vertex(0, unrotated_point(prev_p), area.Point(0, 0)))
zig.append(unrotated_vertex(vertex))
zig_started = True
elif vertex.p.x == high_point.x and vertex.p.y == high_point.y:
high_point_found = True
prev_p = vertex.p
if zig_started:
if zig_unidirectional == True:
# remove the last bit of zig
if math.fabs(zig.LastVertex().p.y - y) < 0.002 * one_over_units:
vertices = zig.getVertices()
while len(vertices) > 0:
v = vertices[len(vertices)-1]
if math.fabs(v.p.y - y0) < 0.002 * one_over_units:
break
else:
vertices.pop()
zig = area.Curve()
for v in vertices:
zig.append(v)
curve_list_for_zigs.append(zig)
def make_zig(a, y0, y, zig_unidirectional):
for curve in a.getCurves():
make_zig_curve(curve, y0, y, zig_unidirectional)
reorder_zig_list_list = []
def add_reorder_zig(curve):
global reorder_zig_list_list
# look in existing lists
s = curve.FirstVertex().p
for curve_list in reorder_zig_list_list:
last_curve = curve_list[len(curve_list) - 1]
e = last_curve.LastVertex().p
if math.fabs(s.x - e.x) < 0.002 * one_over_units and math.fabs(s.y - e.y) < 0.002 * one_over_units:
curve_list.append(curve)
return
# else add a new list
curve_list = []
curve_list.append(curve)
reorder_zig_list_list.append(curve_list)
def reorder_zigs():
global curve_list_for_zigs
global reorder_zig_list_list
reorder_zig_list_list = []
for curve in curve_list_for_zigs:
add_reorder_zig(curve)
curve_list_for_zigs = []
for curve_list in reorder_zig_list_list:
for curve in curve_list:
curve_list_for_zigs.append(curve)
def rotated_point(p):
return area.Point(p.x * cos_angle_for_zigs - p.y * sin_angle_for_zigs, p.x * sin_angle_for_zigs + p.y * cos_angle_for_zigs)
def unrotated_point(p):
return area.Point(p.x * cos_minus_angle_for_zigs - p.y * sin_minus_angle_for_zigs, p.x * sin_minus_angle_for_zigs + p.y * cos_minus_angle_for_zigs)
def rotated_vertex(v):
if v.type:
return area.Vertex(v.type, rotated_point(v.p), rotated_point(v.c))
return area.Vertex(v.type, rotated_point(v.p), area.Point(0, 0))
def unrotated_vertex(v):
if v.type:
return area.Vertex(v.type, unrotated_point(v.p), unrotated_point(v.c))
return area.Vertex(v.type, unrotated_point(v.p), area.Point(0, 0))
def rotated_area(a):
an = area.Area()
for curve in a.getCurves():
curve_new = area.Curve()
for v in curve.getVertices():
curve_new.append(rotated_vertex(v))
an.append(curve_new)
return an
def zigzag(a, stepover, zig_unidirectional):
if a.num_curves() == 0:
return
global rightward_for_zigs
global curve_list_for_zigs
global sin_angle_for_zigs
global cos_angle_for_zigs
global sin_minus_angle_for_zigs
global cos_minus_angle_for_zigs
global one_over_units
one_over_units = 1 / area.get_units()
a = rotated_area(a)
b = area.Box()
a.GetBox(b)
x0 = b.MinX() - 1.0
x1 = b.MaxX() + 1.0
height = b.MaxY() - b.MinY()
num_steps = int(height / stepover + 1)
y = b.MinY() + 0.1 * one_over_units
null_point = area.Point(0, 0)
rightward_for_zigs = True
curve_list_for_zigs = []
for i in range(0, num_steps):
y0 = y
y = y + stepover
p0 = area.Point(x0, y0)
p1 = area.Point(x0, y)
p2 = area.Point(x1, y)
p3 = area.Point(x1, y0)
c = area.Curve()
c.append(area.Vertex(0, p0, null_point, 0))
c.append(area.Vertex(0, p1, null_point, 0))
c.append(area.Vertex(0, p2, null_point, 1))
c.append(area.Vertex(0, p3, null_point, 0))
c.append(area.Vertex(0, p0, null_point, 1))
a2 = area.Area()
a2.append(c)
a2.Intersect(a)
make_zig(a2, y0, y, zig_unidirectional)
if zig_unidirectional == False:
rightward_for_zigs = (rightward_for_zigs == False)
reorder_zigs()
def pocket(a,tool_radius, extra_offset, stepover, depthparams, from_center, keep_tool_down_if_poss, use_zig_zag, zig_angle, zig_unidirectional = False,start_point=None, cut_mode = 'conventional'):
global tool_radius_for_pocket
global area_for_feed_possible
#if len(a.getCurves()) > 1:
# for crv in a.getCurves():
# ar = area.Area()
# ar.append(crv)
# pocket(ar, tool_radius, extra_offset, rapid_safety_space, start_depth, final_depth, stepover, stepdown, clearance_height, from_center, keep_tool_down_if_poss, use_zig_zag, zig_angle, zig_unidirectional)
# return
tool_radius_for_pocket = tool_radius
if keep_tool_down_if_poss:
area_for_feed_possible = area.Area(a)
area_for_feed_possible.Offset(extra_offset - 0.01)
use_internal_function = (area.holes_linked() == False) # use internal function, if area module is the Clipper library
if use_internal_function:
print "using internal. PathAreaUtils:382 "
curve_list = a.MakePocketToolpath(tool_radius, extra_offset, stepover, from_center, use_zig_zag, zig_angle)
else:
print "not using internal. PathAreaUtils:386 "
global sin_angle_for_zigs
global cos_angle_for_zigs
global sin_minus_angle_for_zigs
global cos_minus_angle_for_zigs
radians_angle = zig_angle * math.pi / 180
sin_angle_for_zigs = math.sin(-radians_angle)
cos_angle_for_zigs = math.cos(-radians_angle)
sin_minus_angle_for_zigs = math.sin(radians_angle)
cos_minus_angle_for_zigs = math.cos(radians_angle)
arealist = list()
a_offset = area.Area(a)
current_offset = tool_radius + extra_offset
a_offset.Offset(current_offset)
do_recursive = True
if use_zig_zag:
zigzag(a_offset, stepover, zig_unidirectional)
curve_list = curve_list_for_zigs
else:
if do_recursive:
recur(arealist, a_offset, stepover, from_center)
else:
while(a_offset.num_curves() > 0):
if from_center:
arealist.insert(0, a_offset)
else:
arealist.append(a_offset)
current_offset = current_offset + stepover
a_offset = area.Area(a)
a_offset.Offset(current_offset)
curve_list = get_curve_list(arealist, cut_mode == 'climb')
depths = depthparams.get_depths()
current_start_depth = depthparams.start_depth
print "Startpoint: " + str(start_point)
if start_point==None:
for depth in depths:
cut_curvelist1(curve_list, depthparams.rapid_safety_space, current_start_depth, depth, depthparams.clearance_height, keep_tool_down_if_poss)
current_start_depth = depth
else:
for depth in depths:
cut_curvelist2(curve_list, depthparams.rapid_safety_space, current_start_depth, depth, depthparams.clearance_height, keep_tool_down_if_poss, start_point)
current_start_depth = depth

View File

@@ -46,24 +46,18 @@ class ObjectDrilling:
def __init__(self,obj):
#obj.addProperty("App::PropertyVector","StartPoint","Path","The start position of the drilling")
obj.addProperty("App::PropertyLinkSub","Base","Path","The base geometry of this toolpath")
obj.addProperty("App::PropertyLinkSubList","Base","Path",translate("Parent Object(s)","The base geometry of this toolpath"))
obj.addProperty("App::PropertyVectorList","locations","Path","The drilling locations")
obj.addProperty("App::PropertyLength", "PeckDepth", "Drilling","Incremental Drill depth before retracting to clear chips")
#obj.PeckDepth = (0,0,1000,1)
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Drilling", "The height needed to clear clamps and obstructions")
obj.addProperty("App::PropertyDistance", "FinalDepth", "Drilling","Final Depth of Tool- lowest value in Z")
obj.addProperty("App::PropertyDistance", "RetractHeight", "Drilling","The height where feed starts and height during retract tool when path is finished")
obj.addProperty("App::PropertyLength", "VertFeed", "Feed","Feed rate for vertical moves in Z")
#obj.addProperty("App::PropertySpeed", "HorizFeed", "Feed","Feed rate for horizontal moves") #not needed for drilling
obj.addProperty("App::PropertyString","Comment","Path","An optional comment for this profile")
obj.addProperty("App::PropertyBool","Active","Path","Make False, to prevent operation from generating code")
obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool","The tool number in use")
obj.addProperty("App::PropertyLength", "PeckDepth", "Depth", translate("PeckDepth","Incremental Drill depth before retracting to clear chips"))
#obj.addProperty("App::PropertyFloat", "StartDepth", "Depth", translate("PathProject","Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", translate("Clearance Height","The height needed to clear clamps and obstructions"))
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", translate("Final Depth","Final Depth of Tool- lowest value in Z"))
obj.addProperty("App::PropertyDistance", "RetractHeight", "Depth", translate("Retract Height","The height where feed starts and height during retract tool when path is finished"))
obj.addProperty("App::PropertyLength", "VertFeed", "Feed",translate("Vert Feed","Feed rate for vertical moves in Z"))
obj.addProperty("App::PropertyString","Comment","Path",translate("PathProject","An optional comment for this profile"))
obj.addProperty("App::PropertyBool","Active","Path",translate("Active","Make False, to prevent operation from generating code"))
obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool",translate("PathProfile","The tool number in use"))
obj.ToolNumber = (0,0,1000,1)
obj.setEditorMode('ToolNumber',1) #make this read only
@@ -76,9 +70,38 @@ class ObjectDrilling:
return None
def execute(self,obj):
locations = []
for loc in obj.Base:
if "Face" in loc[1] or "Edge" in loc[1]:
s = getattr(loc[0].Shape,loc[1])
else:
s = loc[0].Shape
if s.ShapeType in ['Face', 'Wire', 'Edge' ]:
X = s.Edges[0].Curve.Center.x
Y = s.Edges[0].Curve.Center.y
Z = s.Edges[0].Curve.Center.z
elif s.ShapeType == 'Vertex':
X = s.Point.x
Y = s.Point.y
Z = s.Point.z
locations.append(FreeCAD.Vector(X,Y,Z))
# tie the toolnumber to the PathLoadTool object ToolNumber
if len(obj.InList)>0: #check to see if obj is in the Project group yet
project = obj.InList[0]
tl = int(PathUtils.changeTool(obj,project))
obj.ToolNumber= tl
tool = PathUtils.getTool(obj,obj.ToolNumber)
output = "G90 G98\n"
# rapid to clearance height
output += "G0 Z" + str(obj.ClearanceHeight.Value)
# rapid to first hole location, with spindle still retracted:
p0 = obj.locations[0]
p0 = locations[0]
output += "G0 X"+str(p0.x) + " Y" + str(p0.y)+ "\n"
# move tool to clearance plane
output += "G0 Z" + str(obj.ClearanceHeight.Value) + "\n"
@@ -88,13 +111,12 @@ class ObjectDrilling:
else:
cmd = "G81"
qword = ""
for p in obj.locations:
for p in locations:
output += cmd + " X" + str(p.x) + " Y" + str(p.y) + " Z" + str(obj.FinalDepth.Value) + qword + " R" + str(obj.RetractHeight.Value) + " F" + str(obj.VertFeed.Value) + "\n"
output += "G80\n"
print output
path = Path.Path(output)
obj.Path = path
@@ -104,8 +126,7 @@ class ObjectDrilling:
tl = int(PathUtils.changeTool(obj,project))
obj.ToolNumber= tl
class _ViewProviderDrill:
class ViewProviderDrill:
def __init__(self,obj): #mandatory
# obj.addProperty("App::PropertyFloat","SomePropertyName","PropertyGroup","Description of this property")
obj.Proxy = self
@@ -152,45 +173,118 @@ class CommandPathDrilling:
def IsActive(self):
return not FreeCAD.ActiveDocument is None
def Drillable(self, obj):
import Part
drillable = ""
if obj.ShapeType == 'Vertex':
drillable = 'Vertex'
elif obj.ShapeType == 'Edge':
if isinstance(obj.Curve, Part.Circle):
drillable = 'Circle'
elif obj.ShapeType == 'Face':
if isinstance(obj.Edges[0].Curve, Part.Circle):
drillable = 'Circle'
elif obj.ShapeType == 'Wire':
if isinstance(obj.Edges[0].Curve, Part.Circle):
drillable = 'Circle'
else:
drillable = None
return drillable
def Activated(self):
import Path
import Part
from PathScripts import PathUtils,PathDrilling,PathProject
prjexists = False
selection = FreeCADGui.Selection.getSelectionEx()
selection = FreeCADGui.Selection.getSelectionEx()
if not selection:
FreeCAD.Console.PrintError(translate("PathDrilling","Please select points or cirlces for drilling.\n"))
return
diamcount = 0 #keep track of how many different hole sizes we're asked to deal with
lastradius = 0.0
locations = []
vertexcount = 0 #keep track of how many vertices
for s in selection:
if s.HasSubObjects:
for i in s.SubObjects:
d = self.Drillable (i)
if d == 'Circle':
if i.Edges[0].Curve.Radius != lastradius:
diamcount += 1
lastradius = i.Edges[0].Curve.Radius
elif d == 'Vertex':
vertexcount += 1
else:
FreeCAD.Console.PrintError(translate("PathDrilling","No drillable locations were selected.\n"))
return
#subs = []
for n in s.SubElementNames:
# subs.append(n)
locations.append((s.ObjectName, s.Object, n))
else:
d = self.Drillable (s.Object.Shape)
if d == 'Circle':
if not str(s.Object.Shape.Edges[0].Curve.Radius) == str(lastradius):
diamcount += 1
lastradius = s.Object.Shape.Edges[0].Curve.Radius
elif d == 'Vertex':
vertexcount += 1
else:
FreeCAD.Console.PrintError(translate("PathDrilling","No drillable locations were selected.\n"))
return
locations.append((s.ObjectName, s.Object, []))
if diamcount > 1:
FreeCAD.Console.PrintError(translate("PathDrilling","Circles of different radii found. Select only one size circle at a time.\n"))
return
if diamcount >= 1 and vertexcount >= 1:
FreeCAD.Console.PrintError(translate("PathDrilling","Please select either points or circles but not both.\n"))
return
# Take a guess at some reasonable values for Finish depth.
if selection[0].HasSubObjects:
bb = selection[0].Object.Shape.BoundBox #parent boundbox
fbb = selection[0].SubObjects[0].BoundBox #feature boundbox
if fbb.ZMax < bb.ZMax:
zbottom = fbb.ZMax
ztop = bb.ZMax + 1
else:
zbottom = bb.ZMin
ztop = 5
else:
zbottom = 0
ztop = 5
# if everything is ok, execute and register the transaction in the undo/redo stack
FreeCAD.ActiveDocument.openTransaction(translate("Path_Drilling","Create Drilling"))
FreeCADGui.addModule("PathScripts.PathDrilling")
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Drilling")
PathDrilling.ObjectDrilling(obj)
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Drilling")')
FreeCADGui.doCommand('PathScripts.PathDrilling.ObjectDrilling(obj)')
FreeCADGui.doCommand('obj.Active = True')
FreeCADGui.doCommand('PathScripts.PathDrilling.ViewProviderDrill(obj.ViewObject)')
myList = obj.locations
for sub in selection:
for point in sub.SubObjects:
if isinstance(point,Part.Vertex):
myList.append(FreeCAD.Vector(point.X, point.Y, point.Z))
if isinstance(point,Part.Edge):
if isinstance(point.Curve,Part.Circle):
center = point.Curve.Center
myList.append(FreeCAD.Vector(center.x,center.y,center.z))
obj.locations = myList
baselist = "["
for loc in locations:
baselist += "(FreeCAD.ActiveDocument." + str(loc[0]) + ',"' + str(loc[2]) + '"),'
baselist += "]"
PathDrilling._ViewProviderDrill(obj.ViewObject)
# obj.ViewObject.Proxy = 0
obj.Active = True
project = PathUtils.addToProject(obj)
tl = PathUtils.changeTool(obj,project)
if tl:
obj.ToolNumber = tl
FreeCADGui.doCommand('obj.Base = (' + baselist + ')')
FreeCADGui.doCommand('from PathScripts import PathUtils')
FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(ztop))
FreeCADGui.doCommand('obj.RetractHeight= ' + str(ztop))
FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom))
FreeCADGui.doCommand('PathScripts.PathUtils.addToProject(obj)')
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()

View File

@@ -0,0 +1,175 @@
# -*- coding: utf-8 -*-
#***************************************************************************
#* *
#* Copyright (c) 2014 Yorik van Havre <yorik@uncreated.net> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
import FreeCAD,FreeCADGui,Path,PathGui
from PySide import QtCore,QtGui
"""Path Engrave object and FreeCAD command"""
# Qt tanslation handling
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def translate(context, text, disambig=None):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def translate(context, text, disambig=None):
return QtGui.QApplication.translate(context, text, disambig)
class ObjectPathEngrave:
def __init__(self,obj):
obj.addProperty("App::PropertyLinkSub","Base","Path","The base geometry of this object")
obj.addProperty("App::PropertyEnumeration", "Algorithm", "Algorithm",translate("Path", "The library or Algorithm used to generate the path"))
obj.Algorithm = ['OCC Native']
#Depth Properties
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", translate("Path","The height needed to clear clamps and obstructions"))
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", translate("Path","Rapid Safety Height between locations."))
obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", translate("Path","Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", translate("Path","Final Depth of Tool- lowest value in Z"))
obj.addProperty("App::PropertyInteger","StartVertex","Path","The vertex index to start the path from")
#Feed Properties
obj.addProperty("App::PropertySpeed", "VertFeed", "Feed",translate("Path","Feed rate for vertical moves in Z"))
obj.addProperty("App::PropertySpeed", "HorizFeed", "Feed",translate("Path","Feed rate for horizontal moves"))
obj.Proxy = self
def __getstate__(self):
return None
def __setstate__(self,state):
return None
def execute(self,obj):
if obj.Base:
# we only consider the outer wire if this is a Face
wires = obj.Base[0].Shape.Wires
output = ""
if obj.Algorithm == "OCC Native":
output += self.buildpathocc(obj, wires)
#print output
path = Path.Path(output)
obj.Path = path
def buildpathocc(self, obj, wires):
import Part,DraftGeomUtils
output = "G90\nG21\nG40\n"
output += "G0 Z" + str(obj.ClearanceHeight.Value)
# absolute coords, millimeters, cancel offsets
for wire in wires:
offset = wire
# reorder the wire
offset = DraftGeomUtils.rebaseWire(offset,obj.StartVertex)
# we create the path from the offset shape
last = None
for edge in offset.Edges:
if not last:
# we set the first move to our first point
last = edge.Vertexes[0].Point
output += "G0" + " X" + str("%f" % last.x) + " Y" + str("%f" % last.y) #Rapid sto starting position
output += "G1" + " Z" + str("%f" % last.z) +"F " + str(obj.VertFeed.Value)+ "\n" #Vertical feed to depth
if isinstance(edge.Curve,Part.Circle):
point = edge.Vertexes[-1].Point
if point == last: # edges can come flipped
point = edge.Vertexes[0].Point
center = edge.Curve.Center
relcenter = center.sub(last)
v1 = last.sub(center)
v2 = point.sub(center)
if v1.cross(v2).z < 0:
output += "G2"
else:
output += "G3"
output += " X" + str("%f" % point.x) + " Y" + str("%f" % point.y) + " Z" + str("%f" % point.z)
output += " I" + str("%f" % relcenter.x) + " J" + str("%f" % relcenter.y) + " K" + str("%f" % relcenter.z)
output += " F " + str(obj.HorizFeed.Value)
output += "\n"
last = point
else:
point = edge.Vertexes[-1].Point
if point == last: # edges can come flipped
point = edge.Vertexes[0].Point
output += "G1 X" + str("%f" % point.x) + " Y" + str("%f" % point.y) + " Z" + str("%f" % point.z)
output += " F " + str(obj.HorizFeed.Value)
output += "\n"
last = point
output += "G0 Z " + str(obj.SafeHeight.Value)
return output
class CommandPathEngrave:
def GetResources(self):
return {'Pixmap' : 'Path-Engrave',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Engrave","ShapeString Engrave"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Engrave","Creates an Engraving Path around a Draft ShapeString")}
def IsActive(self):
return not FreeCAD.ActiveDocument is None
def Activated(self):
import Draft
# check that the selection contains exactly what we want
selection = FreeCADGui.Selection.getSelectionEx()
if len(selection) != 1:
FreeCAD.Console.PrintError(translate("Path_Engrave","Please select one ShapeString\n"))
return
if len(selection[0].SubObjects) != 0:
FreeCAD.Console.PrintError(translate("Path_Engrave","Please select one ShapeString\n"))
return
if not Draft.getType(selection[0].Object) == "ShapeString":
FreeCAD.Console.PrintError(translate("Path_Engrave","Please select one ShapeString\n"))
return
# if everything is ok, execute and register the transaction in the undo/redo stack
FreeCAD.ActiveDocument.openTransaction("Create Engrave Path")
FreeCADGui.addModule("PathScripts.PathFaceProfile")
FreeCADGui.addModule("PathScripts.PathUtils")
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","PathEngrave")')
FreeCADGui.doCommand('PathScripts.PathEngrave.ObjectPathEngrave(obj)')
FreeCADGui.doCommand('obj.Base = (FreeCAD.ActiveDocument.'+selection[0].ObjectName+',[])')
FreeCADGui.doCommand('obj.ClearanceHeight = 10')
FreeCADGui.doCommand('obj.StartDepth= 0')
FreeCADGui.doCommand('obj.FinalDepth= -0.1' )
FreeCADGui.doCommand('obj.SafeHeight= 5.0' )
FreeCADGui.doCommand('obj.ViewObject.Proxy = 0')
FreeCADGui.doCommand('PathScripts.PathUtils.addToProject(obj)')
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_Engrave',CommandPathEngrave())

View File

@@ -119,7 +119,7 @@ class CommandPathHop:
FreeCAD.Console.PrintError(translate("Path_Hop","The selected object is not a path\n"))
return
FreeCAD.ActiveDocument.openTransaction(translate("Path_Hop","Create Hop"))
FreeCAD.ActiveDocument.openTransaction(translate("Pat_hHop","Create Hop"))
FreeCADGui.addModule("PathScripts.PathHop")
FreeCADGui.addModule("PathScripts.PathUtils")
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Hop")')

View File

@@ -1,290 +0,0 @@
# -*- coding: utf-8 -*-
#***************************************************************************
#* *
#* Copyright (c) 2015 Dan Falck <ddfalck@gmail.com> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
'''PathKurve - Path Profile operation using libarea (created by Dan Heeks) for making simple CNC paths.
libarea, originally from HeeksCNC project must be present for this to work.'''
import FreeCAD,FreeCADGui,Path,PathGui
from PathScripts import PathProject,PathUtils,PathKurveUtils,PathSelection
from PySide import QtCore,QtGui
# Qt tanslation handling
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def translate(context, text, disambig=None):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def translate(context, text, disambig=None):
return QtGui.QApplication.translate(context, text, disambig)
class PathProfile:
def __init__(self,obj):
obj.addProperty("App::PropertyLinkSub","Base","Path","The base geometry of this toolpath")
obj.addProperty("App::PropertyLinkSub","StartPoint", "Path","Linked Start Point of Profile")
obj.addProperty("App::PropertyLinkSub","EndPoint", "Path","Linked End Point of Profile")
obj.addProperty("App::PropertyBool","Active","Path","Make False, to prevent operation from generating code")
obj.addProperty("App::PropertyString","Comment","Path","An optional comment for this profile")
obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool","The tool number in use")
obj.ToolNumber = (0,0,1000,1)
obj.setEditorMode('ToolNumber',1) #make this read only
#Depth Properties
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth","The height needed to clear clamps and obstructions")
obj.addProperty("App::PropertyLength", "StepDown", "Depth","Incremental Step Down of Tool")
# obj.addProperty("App::PropertyBool","UseStartDepth","Depth","make True, if manually specifying a Start Start Depth")
obj.addProperty("App::PropertyDistance", "StartDepth", "Depth","Starting Depth of Tool- first cut depth in Z")
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth","Final Depth of Tool- lowest value in Z")
obj.addProperty("App::PropertyDistance", "RetractHeight", "Depth","The height desired to retract tool when path is finished")
#Feed Properties
obj.addProperty("App::PropertyLength", "VertFeed", "Feed","Feed rate (in units per minute) for vertical moves in Z")
obj.addProperty("App::PropertyLength", "HorizFeed", "Feed","Feed rate (in units per minute) for horizontal moves")
#Profile Properties
obj.addProperty("App::PropertyEnumeration", "Side", "Profile","Side of edge that tool should cut")
obj.Side = ['left','right','on'] #side of profile that cutter is on in relation to direction of profile
obj.addProperty("App::PropertyEnumeration", "Direction", "Profile","The direction that the toolpath should go around the part ClockWise CW or CounterClockWise CCW")
obj.Direction = ['CW','CCW'] #this is the direction that the profile runs
obj.addProperty("App::PropertyBool","UseComp","Profile","make True, if using Cutter Radius Compensation")
obj.addProperty("App::PropertyIntegerList","Edgelist","Profile","List of edges selected")
obj.addProperty("App::PropertyDistance", "OffsetExtra", "Profile","Extra value to stay away from final profile- good for roughing toolpath")
# obj.addProperty("App::PropertyLength", "SegLen", "Profile","Tesselation value for tool paths made from beziers, bsplines, and ellipses")
# #Start Point Properties
obj.addProperty("App::PropertyString","StartPtName","Profile","The name of the start point of this path")
obj.addProperty("App::PropertyBool","UseStartPt","Profile","Make True, if specifying a Start Point")
# obj.addProperty("App::PropertyLength", "ExtendAtStart", "Profile", "extra length of tool path before start of part edge")
# obj.addProperty("App::PropertyLength", "LeadInLineLen", "Profile","length of straight segment of toolpath that comes in at angle to first part edge")
# #End Point Properties
obj.addProperty("App::PropertyString","EndPtName","Profile","The name of the end point of this path")
obj.addProperty("App::PropertyBool","UseEndPt","Profile","Make True, if specifying an End Point")
# obj.addProperty("App::PropertyLength", "ExtendAtEnd", "Profile","extra length of tool path after end of part edge")
# obj.addProperty("App::PropertyLength", "LeadOutLineLen", "Profile","length of straight segment of toolpath that comes in at angle to last edge selected")
# obj.addProperty("App::PropertyDistance", "RollRadius", "Profile", "Radius at start and end")
obj.Proxy = self
def __getstate__(self):
return None
def __setstate__(self,state):
return None
def execute(self,obj):
if obj.Base:
# tie the toolnumber to the PathLoadTool object ToolNumber
if len(obj.InList)>0: #check to see if obj is in the Project group yet
project = obj.InList[0]
tl = int(PathUtils.changeTool(obj,project))
obj.ToolNumber= tl
tool = PathUtils.getTool(obj,obj.ToolNumber)
if tool:
self.radius = tool.Diameter/2
else:
# temporary value,in case we don't have any tools defined already
self.radius = 0.25
# self.radius = 0.25
self.clearance = obj.ClearanceHeight.Value
self.step_down=obj.StepDown.Value
self.start_depth=obj.StartDepth.Value
self.final_depth=obj.FinalDepth.Value
self.rapid_safety_space=obj.RetractHeight.Value
self.side=obj.Side
self.offset_extra=obj.OffsetExtra.Value
self.use_CRC=obj.UseComp
self.vf=obj.VertFeed.Value
self.hf=obj.HorizFeed.Value
edgelist = []
if obj.StartPtName and obj.UseStartPt:
self.startpt = FreeCAD.ActiveDocument.getObject(obj.StartPtName).Shape
else:
self.startpt = None
if obj.EndPtName and obj.UseEndPt:
self.endpt = FreeCAD.ActiveDocument.getObject(obj.EndPtName).Shape
else:
self.endpt = None
for e in obj.Edgelist:
edgelist.append(FreeCAD.ActiveDocument.getObject(obj.Base[0].Name).Shape.Edges[e-1])
output=PathKurveUtils.makePath(edgelist,self.side,self.radius,self.vf,self.hf,self.offset_extra, \
self.rapid_safety_space,self.clearance,self.start_depth,self.step_down, \
self.final_depth,self.use_CRC,obj.Direction,self.startpt,self.endpt)
if obj.Active:
path = Path.Path(output)
obj.Path = path
obj.ViewObject.Visibility = True
else:
path = Path.Path("(inactive operation)")
obj.Path = path
obj.ViewObject.Visibility = False
class _ViewProviderKurve:
def __init__(self,vobj): #mandatory
vobj.Proxy = self
def __getstate__(self): #mandatory
return None
def __setstate__(self,state): #mandatory
return None
def getIcon(self): #optional
return ":/icons/Path-Kurve.svg"
class CommandPathKurve:
def GetResources(self):
return {'Pixmap' : 'Path-Kurve',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Kurve","Profile"),
'Accel': "P, P",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Kurve","Creates a Path Profile object from selected edges, using libarea for offset algorithm")}
def IsActive(self):
return not FreeCAD.ActiveDocument is None
def Activated(self):
FreeCAD.ActiveDocument.openTransaction(translate("Path_Kurve","Create a Profile operation using libarea"))
FreeCADGui.addModule("PathScripts.PathKurve")
snippet = '''
import Path
from PathScripts import PathSelection,PathProject,PathUtils
import area
def profileop():
selection = PathSelection.multiSelect()
if not selection:
FreeCAD.Console.PrintError('please select some edges\\n')
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Profile")
PathScripts.PathKurve.PathProfile(obj)
obj.Active = True
PathScripts.PathKurve._ViewProviderKurve(obj.ViewObject)
obj.Base = (FreeCAD.ActiveDocument.getObject(selection['objname']))
elist = []
for e in selection['edgenames']:
elist.append(eval(e.lstrip('Edge')))
obj.Edgelist = elist
if selection['pointnames']:
FreeCAD.Console.PrintMessage('There are points selected.\\n')
if len(selection['pointnames'])>1:
obj.StartPtName = selection['pointnames'][0]
obj.StartPoint= FreeCAD.ActiveDocument.getObject(obj.StartPtName)
obj.EndPtName = selection['pointnames'][-1]
obj.EndPoint=FreeCAD.ActiveDocument.getObject(obj.EndPtName)
else:
obj.StartPtName = selection['pointnames'][0]
obj.StartPoint= FreeCAD.ActiveDocument.getObject(obj.StartPtName)
obj.ClearanceHeight = 2.0
obj.StepDown = 1.0
obj.StartDepth=0.0
obj.FinalDepth=-1.0
obj.RetractHeight = 5.0
obj.Side = 'left'
obj.OffsetExtra = 0.0
if selection['clockwise']:
obj.Direction = 'CW'
else:
obj.Direction = 'CCW'
obj.UseComp = False
project = PathUtils.addToProject(obj)
tl = PathUtils.changeTool(obj,project)
if tl:
obj.ToolNumber = tl
from PathScripts import PathProject,PathUtils,PathKurve, PathKurveUtils,PathSelection
try:
import area
except:
FreeCAD.Console.PrintError('libarea needs to be installed for this command to work\\n')
profileop()
'''
FreeCADGui.doCommand(snippet)
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_Kurve',CommandPathKurve())
FreeCAD.Console.PrintLog("Loading PathKurve... done\n")

View File

@@ -32,7 +32,15 @@ import math
import area
import Path
from PathScripts import PathUtils
import PathSelection
# import PathSelection
from nc.nc import *
import PathScripts.nc.iso
def makeAreaVertex(seg):
if seg.ShapeType =='Edge':
@@ -52,31 +60,32 @@ def makeAreaCurve(edges,direction,startpt=None,endpt=None):
curveobj = area.Curve()
cleanededges = PathUtils.cleanedges(edges, 0.01)
#sort the edges
vlist,edgestart,common = PathSelection.Sort2Edges([cleanededges[0],cleanededges[1]])
if cleanededges[0].valueAt(cleanededges[0].FirstParameter)<>edgestart:
firstedge=PathUtils.reverseEdge(cleanededges[0])
else:
firstedge=cleanededges[0]
edgelist=[]
edgelist.append(firstedge)
if len(cleanededges) == 1: #user selected a single edge.
edgelist = cleanededges
else:
edgelist = [] #Multiple edges. Need to sequence the vetexes.
#First get the first segment oriented correctly.
#get start and end points of each edge aligned
for e in cleanededges[1:]:
if DraftVecUtils.equals(common,e.valueAt(e.FirstParameter)):
edgelist.append(e)
common= e.valueAt(e.LastParameter)
#We first compare the last parameter of the first segment to see if it matches either end of the second segment. If not, it must need flipping.
if cleanededges[0].valueAt(cleanededges[0].LastParameter) in [cleanededges[1].valueAt(cleanededges[1].FirstParameter), cleanededges[1].valueAt(cleanededges[1].LastParameter)]:
edge0 = cleanededges[0]
else:
newedge = PathUtils.reverseEdge(e)
common= newedge.valueAt(newedge.LastParameter)
edgelist.append(newedge)
curveobj.append(area.Point(edgestart.x,edgestart.y))
edge0 = PathUtils.reverseEdge(cleanededges[0])
edgelist.append(edge0)
#Now iterate the rest of the edges matching the last parameter of the previous segment.
for edge in cleanededges[1:]:
if edge.valueAt(edge.FirstParameter) == edgelist[-1].valueAt(edgelist[-1].LastParameter):
nextedge = edge
else:
nextedge = PathUtils.reverseEdge(edge)
edgelist.append(nextedge)
#print (str(area.Point(edgelist[0].Vertexes[0].X) + ", " + str(edgelist[0].Vertexes[0].Y)))
curveobj.append(area.Point(edgelist[0].Vertexes[0].X,edgelist[0].Vertexes[0].Y))
# seglist =[]
# if direction=='CW':
# edgelist.reverse()
@@ -85,7 +94,7 @@ def makeAreaCurve(edges,direction,startpt=None,endpt=None):
# else:
# for e in edgelist:
# seglist.append(e)
for s in edgelist:
curveobj.append(makeAreaVertex(s))
@@ -98,7 +107,7 @@ def makeAreaCurve(edges,direction,startpt=None,endpt=None):
# curveobj.ChangeStart(area.Point(perppoint1[0].x,perppoint1[0].y))
# else:
# curveobj.ChangeStart(area.Point(startpt.X,startpt.Y))
curveobj.ChangeStart(area.Point(startpt.X,startpt.Y))
curveobj.ChangeStart(area.Point(startpt.x,startpt.y))
if endpt:
# future nearest point code yet to be worked out -fixme
# v2 = Vector(endpt.X,endpt.Y,endpt.Z)
@@ -107,16 +116,19 @@ def makeAreaCurve(edges,direction,startpt=None,endpt=None):
# curveobj.ChangeEnd(area.Point(perppoint2[0].x,perppoint2[0].y))
# else:
# curveobj.ChangeEnd(area.Point(endpt.X,endpt.Y))
curveobj.ChangeEnd(area.Point(endpt.X,endpt.Y))
if direction == 'CW':
curveobj.Reverse()
curveobj.ChangeEnd(area.Point(endpt.x,endpt.y))
if curveobj.IsClockwise() and direction == 'CCW':
curveobj.Reverse()
elif not curveobj.IsClockwise() and direction == 'CW':
curveobj.Reverse()
print "direction is clockwise: " + str(curveobj.IsClockwise())
print "numvertices: " + str(curveobj.getNumVertices())
return curveobj
# profile command,
# side_of_line should be 'left' or 'right' or 'on'
# side_of_line should be 'Left' or 'Right' or 'On'
def profile(curve,side_of_line,radius=1.0,vertfeed=0.0,horizfeed=0.0,offset_extra=0.0, \
rapid_safety_space=None,clearance=None,start_depth=None,stepdown=None, \
final_depth=None,use_CRC=False, \
@@ -124,16 +136,18 @@ def profile(curve,side_of_line,radius=1.0,vertfeed=0.0,horizfeed=0.0,offset_extr
roll_start_pt=None,roll_end_pt=None):
output = ""
output += "G0 Z" + str(clearance)+"\n"
offset_curve = area.Curve(curve)
if offset_curve.getNumVertices() <= 1:
raise Exception,"Sketch has no elements!"
if side_of_line == "on":
if side_of_line == "On":
use_CRC =False
elif (side_of_line == "left") or (side_of_line == "right"):
elif (side_of_line == "Left") or (side_of_line == "Right"):
# get tool radius plus little bit of extra offset, if needed to clean up profile a little more
offset = radius + offset_extra
if side_of_line == 'left':
if side_of_line == 'Left':
offset_curve.Offset(offset)
else:
@@ -142,7 +156,7 @@ def profile(curve,side_of_line,radius=1.0,vertfeed=0.0,horizfeed=0.0,offset_extr
if offset_curve == False:
raise Exception, "couldn't offset kurve " + str(offset_curve)
else:
raise Exception,"Side must be 'left','right', or 'on'"
raise Exception,"Side must be 'Left','Right', or 'On'"
#===============================================================================
# #roll_on roll_off section
@@ -244,15 +258,412 @@ def profile(curve,side_of_line,radius=1.0,vertfeed=0.0,horizfeed=0.0,offset_extr
return output
def makePath(edges,side,radius,vertfeed,horizfeed,offset_extra,rapid_safety_space,clearance,start_depth,step_down,final_depth,use_CRC,direction,startpt=None,endpt=None):
# def makePath(edges,side,radius,vertfeed,horizfeed,offset_extra,rapid_safety_space,clearance,start_depth,step_down,final_depth,use_CRC,direction,startpt=None,endpt=None):
curve = makeAreaCurve(edges,direction,startpt, endpt)
if direction == 'CW':
curve.Reverse()
path = profile(curve,side,radius,vertfeed,horizfeed,offset_extra,rapid_safety_space,clearance,start_depth,step_down,final_depth,use_CRC)
del curve
return path
# curve = makeAreaCurve(edges,direction,startpt, endpt)
# path = profile(curve,side,radius,vertfeed,horizfeed,offset_extra,rapid_safety_space,clearance,start_depth,step_down,final_depth,use_CRC)
# del curve
# return path
# def edgedumper (mylist):
# import Part, PathUtils
# print "The amazing edgedumper"
# print "mylist: " + str(mylist)
# edgs = PathUtils.cleanedges(mylist, 0.01)
# edgs = Part.Wire(edgs)
# for i in edgs.Edges:
# mystring = str(i)
# for v in i.Vertexes:
# mystring = mystring + " : " + str(v.Point)
# print mystring
'''The following procedures are copied almost directly from heekscnc kurve_funcs.py. They depend on nc directory existing below PathScripts and have not been
throughly optimized, understood, or tested for FreeCAD.'''
def profile2(curve, direction = "on", radius = 1.0, vertfeed=0.0,horizfeed=0.0, offset_extra = 0.0, roll_radius = 2.0, roll_on = None, roll_off = None, depthparams = None, extend_at_start = 0.0, extend_at_end = 0.0, lead_in_line_len=0.0,lead_out_line_len= 0.0):
print "we're in"
from PathScripts.nc.nc import *
global tags
direction = direction.lower()
offset_curve = area.Curve(curve)
if direction == "on":
use_CRC() == False
if direction != "on":
if direction != "left" and direction != "right":
raise "direction must be left or right", direction
# get tool diameter
offset = radius + offset_extra
if use_CRC() == False or (use_CRC()==True and CRC_nominal_path()==True):
if math.fabs(offset) > 0.00005:
if direction == "right":
offset = -offset
offset_success = offset_curve.Offset(offset)
if offset_success == False:
global using_area_for_offset
if curve.IsClosed() and (using_area_for_offset == False):
cw = curve.IsClockwise()
using_area_for_offset = True
a = area.Area()
a.append(curve)
a.Offset(-offset)
for curve in a.getCurves():
curve_cw = curve.IsClockwise()
if cw != curve_cw:
curve.Reverse()
set_good_start_point(curve, False)
profile(curve, direction, 0.0, 0.0, roll_radius, roll_on, roll_off, depthparams, extend_at_start, extend_at_end, lead_in_line_len, lead_out_line_len)
using_area_for_offset = False
return
else:
raise Exception, "couldn't offset kurve " + str(offset_curve)
# extend curve
if extend_at_start > 0.0:
span = offset_curve.GetFirstSpan()
new_start = span.p + span.GetVector(0.0) * ( -extend_at_start)
new_curve = area.Curve()
new_curve.append(new_start)
for vertex in offset_curve.getVertices():
new_curve.append(vertex)
offset_curve = new_curve
if extend_at_end > 0.0:
span = offset_curve.GetLastSpan()
new_end = span.v.p + span.GetVector(1.0) * extend_at_end
offset_curve.append(new_end)
# remove tags further than radius from the offset kurve
new_tags = []
for tag in tags:
if tag.dist(offset_curve) <= radius + 0.001:
new_tags.append(tag)
tags = new_tags
if offset_curve.getNumVertices() <= 1:
raise "sketch has no spans!"
# do multiple depths
depths = depthparams.get_depths()
current_start_depth = depthparams.start_depth
# tags
if len(tags) > 0:
# make a copy to restore to after each level
copy_of_offset_curve = area.Curve(offset_curve)
prev_depth = depthparams.start_depth
endpoint = None
for depth in depths:
mat_depth = prev_depth
if len(tags) > 0:
split_for_tags(offset_curve, radius, depthparams.start_depth, depth, depthparams.final_depth)
# make the roll on and roll off kurves
roll_on_curve = area.Curve()
add_roll_on(offset_curve, roll_on_curve, direction, roll_radius, offset_extra, roll_on)
roll_off_curve = area.Curve()
add_roll_off(offset_curve, roll_off_curve, direction, roll_radius, offset_extra, roll_off)
if use_CRC():
crc_start_point = area.Point()
add_CRC_start_line(offset_curve,roll_on_curve,roll_off_curve,radius,direction,crc_start_point,lead_in_line_len)
# get the tag depth at the start
start_z = get_tag_z_for_span(0, offset_curve, radius, depthparams.start_depth, depth, depthparams.final_depth)
if start_z > mat_depth: mat_depth = start_z
# rapid across to the start
s = roll_on_curve.FirstVertex().p
# start point
if (endpoint == None) or (endpoint != s):
if use_CRC():
rapid(crc_start_point.x,crc_start_point.y)
else:
rapid(s.x, s.y)
# rapid down to just above the material
if endpoint == None:
rapid(z = mat_depth + depthparams.rapid_safety_space)
else:
rapid(z = mat_depth)
# feed down to depth
mat_depth = depth
if start_z > mat_depth: mat_depth = start_z
feed(z = mat_depth)
if use_CRC():
start_CRC(direction == "left", radius)
# move to the startpoint
feed(s.x, s.y)
# cut the roll on arc
cut_curve(roll_on_curve)
# cut the main kurve
current_perim = 0.0
for span in offset_curve.GetSpans():
# height for tags
current_perim += span.Length()
ez = get_tag_z_for_span(current_perim, offset_curve, radius, depthparams.start_depth, depth, depthparams.final_depth)
if span.v.type == 0:#line
feed(span.v.p.x, span.v.p.y, ez)
else:
if span.v.type == 1:# anti-clockwise arc
arc_ccw(span.v.p.x, span.v.p.y, ez, i = span.v.c.x, j = span.v.c.y)
else:
arc_cw(span.v.p.x, span.v.p.y, ez, i = span.v.c.x, j = span.v.c.y)
# cut the roll off arc
cut_curve(roll_off_curve)
endpoint = offset_curve.LastVertex().p
if roll_off_curve.getNumVertices() > 0:
endpoint = roll_off_curve.LastVertex().p
#add CRC end_line
if use_CRC():
crc_end_point = area.Point()
add_CRC_end_line(offset_curve,roll_on_curve,roll_off_curve,radius,direction,crc_end_point,lead_out_line_len)
if direction == "on":
rapid(z = depthparams.clearance_height)
else:
feed(crc_end_point.x, crc_end_point.y)
# restore the unsplit kurve
if len(tags) > 0:
offset_curve = area.Curve(copy_of_offset_curve)
if use_CRC():
end_CRC()
if endpoint != s:
# rapid up to the clearance height
rapid(z = depthparams.clearance_height)
prev_depth = depth
rapid(z = depthparams.clearance_height)
del offset_curve
if len(tags) > 0:
del copy_of_offset_curve
class Tag:
def __init__(self, p, width, angle, height):
self.p = p
self.width = width # measured at the top of the tag. In the toolpath, the tag width will be this with plus the tool diameter, so that the finished tag has this "width" at it's smallest
self.angle = angle # the angle of the ramp in radians. Between 0 and Pi/2; 0 is horizontal, Pi/2 is vertical
self.height = height # the height of the tag, always measured above "final_depth"
self.ramp_width = self.height / math.tan(self.angle)
def split_curve(self, curve, radius, start_depth, depth, final_depth):
tag_top_depth = final_depth + self.height
if depth > tag_top_depth - 0.0000001:
return # kurve is above this tag, so doesn't need splitting
height_above_depth = tag_top_depth - depth
ramp_width_at_depth = height_above_depth / math.tan(self.angle)
cut_depth = start_depth - depth
half_flat_top = radius + self.width / 2
d = curve.PointToPerim(self.p)
d0 = d - half_flat_top
perim = curve.Perim()
if curve.IsClosed():
while d0 < 0: d0 += perim
while d0 > perim: d0 -= perim
p = curve.PerimToPoint(d0)
curve.Break(p)
d1 = d + half_flat_top
if curve.IsClosed():
while d1 < 0: d1 += perim
while d1 > perim: d1 -= perim
p = curve.PerimToPoint(d1)
curve.Break(p)
d0 = d - half_flat_top - ramp_width_at_depth
if curve.IsClosed():
while d0 < 0: d0 += perim
while d0 > perim: d0 -= perim
p = curve.PerimToPoint(d0)
curve.Break(p)
d1 = d + half_flat_top + ramp_width_at_depth
if curve.IsClosed():
while d1 < 0: d1 += perim
while d1 > perim: d1 -= perim
p = curve.PerimToPoint(d1)
curve.Break(p)
def get_z_at_perim(self, current_perim, curve, radius, start_depth, depth, final_depth):
# return the z for this position on the kurve ( specified by current_perim ), for this tag
# if the position is not within the tag, then depth is returned
cut_depth = start_depth - depth
half_flat_top = radius + self.width / 2
z = depth
d = curve.PointToPerim(self.p)
dist_from_d = math.fabs(current_perim - d)
if dist_from_d < half_flat_top:
# on flat top of tag
z = final_depth + self.height
elif dist_from_d < half_flat_top + self.ramp_width:
# on ramp
dist_up_ramp = (half_flat_top + self.ramp_width) - dist_from_d
z = final_depth + dist_up_ramp * math.tan(self.angle)
if z < depth: z = depth
return z
def dist(self, curve):
# return the distance from the tag point to the given kurve
d = curve.PointToPerim(self.p)
p = curve.PerimToPoint(d)
v = self.p - p
return v.length()
tags = []
def add_roll_on(curve, roll_on_curve, direction, roll_radius, offset_extra, roll_on):
if direction == "on": roll_on = None
if curve.getNumVertices() <= 1: return
first_span = curve.GetFirstSpan()
if roll_on == None:
rollstart = first_span.p
elif roll_on == 'auto':
if roll_radius < 0.0000000001:
rollstart = first_span.p
v = first_span.GetVector(0.0)
if direction == 'right':
off_v = area.Point(v.y, -v.x)
else:
off_v = area.Point(-v.y, v.x)
rollstart = first_span.p + off_v * roll_radius
else:
rollstart = roll_on
rvertex = area.Vertex(first_span.p)
if first_span.p == rollstart:
rvertex.type = 0
else:
v = first_span.GetVector(0.0) # get start direction
rvertex.c, rvertex.type = area.TangentialArc(first_span.p, rollstart, -v)
rvertex.type = -rvertex.type # because TangentialArc was used in reverse
# add a start roll on point
roll_on_curve.append(rollstart)
# add the roll on arc
roll_on_curve.append(rvertex)
def add_roll_off(curve, roll_off_curve, direction, roll_radius, offset_extra, roll_off):
if direction == "on": return
if roll_off == None: return
if curve.getNumVertices() <= 1: return
last_span = curve.GetLastSpan()
if roll_off == 'auto':
if roll_radius < 0.0000000001: return
v = last_span.GetVector(1.0) # get end direction
if direction == 'right':
off_v = area.Point(v.y, -v.x)
else:
off_v = area.Point(-v.y, v.x)
rollend = last_span.v.p + off_v * roll_radius;
else:
rollend = roll_off
# add the end of the original kurve
roll_off_curve.append(last_span.v.p)
if rollend == last_span.v.p: return
rvertex = area.Vertex(rollend)
v = last_span.GetVector(1.0) # get end direction
rvertex.c, rvertex.type = area.TangentialArc(last_span.v.p, rollend, v)
# add the roll off arc
roll_off_curve.append(rvertex)
def clear_tags():
global tags
tags = []
def add_tag(p, width, angle, height):
global tags
tag = Tag(p, width, angle, height)
tags.append(tag)
def split_for_tags( curve, radius, start_depth, depth, final_depth ):
global tags
for tag in tags:
tag.split_curve(curve, radius, start_depth, depth, final_depth)
def get_tag_z_for_span(current_perim, curve, radius, start_depth, depth, final_depth):
global tags
max_z = None
perim = curve.Perim()
for tag in tags:
z = tag.get_z_at_perim(current_perim, curve, radius, start_depth, depth, final_depth)
if max_z == None or z > max_z:
max_z = z
if curve.IsClosed():
# do the same test, wrapped around the closed kurve
z = tag.get_z_at_perim(current_perim - perim, curve, radius, start_depth, depth, final_depth)
if max_z == None or z > max_z:
max_z = z
z = tag.get_z_at_perim(current_perim + perim, curve, radius, start_depth, depth, final_depth)
if max_z == None or z > max_z:
max_z = z
return max_z
def cut_curve(curve):
for span in curve.GetSpans():
if span.v.type == 0:#line
feed(span.v.p.x, span.v.p.y)
else:
if span.v.type == 1:# anti-clockwise arc
arc_ccw(span.v.p.x, span.v.p.y, i = span.v.c.x, j = span.v.c.y)
else:
arc_cw(span.v.p.x, span.v.p.y, i = span.v.c.x, j = span.v.c.y)
def add_CRC_start_line(curve,roll_on_curve,roll_off_curve,radius,direction,crc_start_point,lead_in_line_len):
first_span = curve.GetFirstSpan()
v = first_span.GetVector(0.0)
if direction == 'right':
off_v = area.Point(v.y, -v.x)
else:
off_v = area.Point(-v.y, v.x)
startpoint_roll_on = roll_on_curve.FirstVertex().p
crc_start = startpoint_roll_on + off_v * lead_in_line_len
crc_start_point.x = crc_start.x
crc_start_point.y = crc_start.y
def add_CRC_end_line(curve,roll_on_curve,roll_off_curve,radius,direction,crc_end_point,lead_out_line_len):
last_span = curve.GetLastSpan()
v = last_span.GetVector(1.0)
if direction == 'right':
off_v = area.Point(v.y, -v.x)
else:
off_v = area.Point(-v.y, v.x)
endpoint_roll_off = roll_off_curve.LastVertex().p
crc_end = endpoint_roll_off + off_v * lead_out_line_len
crc_end_point.x = crc_end.x
crc_end_point.y = crc_end.y
using_area_for_offset = False

View File

@@ -41,26 +41,26 @@ except AttributeError:
class Machine:
def __init__(self,obj):
obj.addProperty("App::PropertyString", "MachineName","Base","Name of the Machine that will use the CNC program")
obj.addProperty("App::PropertyString", "MachineName","Base",translate("Machine Name","Name of the Machine that will use the CNC program"))
obj.addProperty("App::PropertyFile", "PostProcessor", "CodeOutput", "Select the Post Processor file for this machine")
obj.setEditorMode("PostProcessor",1) #set to read only
obj.addProperty("App::PropertyEnumeration", "MachineUnits","CodeOutput", "Units that the machine works in, ie Metric or Inch")
obj.addProperty("App::PropertyFile", "PostProcessor", "CodeOutput", translate("Post Processor","Select the Post Processor file for this machine"))
#obj.setEditorMode("PostProcessor",1) #set to read only
obj.addProperty("App::PropertyEnumeration", "MachineUnits","CodeOutput", translate( "Machine Units", "Units that the machine works in, ie Metric or Inch"))
obj.MachineUnits=['Metric', 'Inch']
obj.addProperty("Path::PropertyTooltable","Tooltable", "Base","The tooltable used for this CNC program")
obj.addProperty("Path::PropertyTooltable","Tooltable", "Base",translate("Tool Table","The tooltable used for this CNC program"))
obj.addProperty("App::PropertyDistance", "X_Max", "Limits", "The Maximum distance in X the machine can travel")
obj.addProperty("App::PropertyDistance", "Y_Max", "Limits", "The Maximum distance in X the machine can travel")
obj.addProperty("App::PropertyDistance", "Z_Max", "Limits", "The Maximum distance in X the machine can travel")
obj.addProperty("App::PropertyDistance", "X_Max", "Limits", translate("X Maximum Limit","The Maximum distance in X the machine can travel"))
obj.addProperty("App::PropertyDistance", "Y_Max", "Limits", translate("Y Maximum Limit","The Maximum distance in X the machine can travel"))
obj.addProperty("App::PropertyDistance", "Z_Max", "Limits", translate("Y Maximum Limit","The Maximum distance in X the machine can travel"))
obj.addProperty("App::PropertyDistance", "X_Min", "Limits", "The Minimum distance in X the machine can travel")
obj.addProperty("App::PropertyDistance", "Y_Min", "Limits", "The Minimum distance in X the machine can travel")
obj.addProperty("App::PropertyDistance", "Z_Min", "Limits", "The Minimum distance in X the machine can travel")
obj.addProperty("App::PropertyDistance", "X_Min", "Limits", translate("X Minimum Limit","The Minimum distance in X the machine can travel"))
obj.addProperty("App::PropertyDistance", "Y_Min", "Limits", translate("Y Minimum Limit","The Minimum distance in X the machine can travel"))
obj.addProperty("App::PropertyDistance", "Z_Min", "Limits", translate("Y Minimum Limit","The Minimum distance in X the machine can travel"))
obj.addProperty("App::PropertyDistance", "X", "HomePosition", "Home position of machine, in X (mainly for visualization)")
obj.addProperty("App::PropertyDistance", "Y", "HomePosition", "Home position of machine, in Y (mainly for visualization)")
obj.addProperty("App::PropertyDistance", "Z", "HomePosition", "Home position of machine, in Z (mainly for visualization)")
obj.addProperty("App::PropertyDistance", "X", "HomePosition", translate("X Home Position","Home position of machine, in X (mainly for visualization)"))
obj.addProperty("App::PropertyDistance", "Y", "HomePosition", translate("Y Home Position","Home position of machine, in Y (mainly for visualization)"))
obj.addProperty("App::PropertyDistance", "Z", "HomePosition", translate("Z Home Position","Home position of machine, in Z (mainly for visualization)"))
obj.Proxy = self
mode = 2
@@ -199,15 +199,15 @@ class _ViewProviderMachine:
class CommandPathMachine:
def GetResources(self):
return {'Pixmap' : 'Path-Machine',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Machine","Machine Object"),
'MenuText': QtCore.QT_TRANSLATE_NOOP("PathMachine","Machine Object"),
'Accel': "P, M",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Machine","Create a Machine object")}
'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathMachine","Create a Machine object")}
def IsActive(self):
return not FreeCAD.ActiveDocument is None
def Activated(self):
FreeCAD.ActiveDocument.openTransaction(translate("Path_Machine","Create a Machine object"))
FreeCAD.ActiveDocument.openTransaction(translate("PathMachine","Create a Machine object"))
CommandPathMachine.Create()
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()

View File

@@ -22,11 +22,23 @@
#* *
#***************************************************************************
import FreeCAD,FreeCADGui,Path,PathGui
import FreeCAD,Path
from FreeCAD import Vector
from PySide import QtCore,QtGui
from PathScripts import PathUtils,PathSelection,PathProject
if FreeCAD.GuiUp:
import FreeCADGui, PathGui
from PySide import QtCore, QtGui
from DraftTools import translate
from pivy import coin
else:
def translate(ctxt,txt):
return txt
__title__="Path Profile Operation"
__author__ = "sliptonic (Brad Collette)"
__url__ = "http://www.freecadweb.org"
"""Path Profile object and FreeCAD command"""
# Qt tanslation handling
@@ -38,59 +50,84 @@ except AttributeError:
def translate(context, text, disambig=None):
return QtGui.QApplication.translate(context, text, disambig)
def makeProfile(self, name="Profile"):
'''creates a Profile operation'''
#obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython",name)
#obj.Label = translate("Path",name)
obj=self
ObjectProfile(obj)
if FreeCAD.GuiUp:
_ViewProviderProfile(obj.ViewObject)
locations = []
angles = []
lengths = []
heights = []
obj.locs = locations
obj.angles = angles
obj.lengths = lengths
obj.heights = heights
FreeCAD.ActiveDocument.recompute()
return obj
class ObjectProfile:
def __init__(self,obj):
obj.addProperty("App::PropertyLinkSub","Base","Path","The base geometry of this toolpath")
obj.addProperty("App::PropertyLinkSub","Face1","Path","First Selected Face to help determine where final depth of tool path is")
obj.addProperty("App::PropertyLinkSub","Face2","Path","Second Selected Face to help determine where the upper level of tool path is")
obj.addProperty("App::PropertyBool","PathClosed","Path","If the toolpath is a closed polyline this is True")
obj.addProperty("App::PropertyLinkSub","Edge1","Path","First Selected Edge to help determine which geometry to make a toolpath around")
obj.addProperty("App::PropertyLinkSub","Edge2","Path","Second Selected Edge to help determine which geometry to make a toolpath around")
obj.addProperty("App::PropertyBool","Active","Path","Make False, to prevent operation from generating code")
obj.addProperty("App::PropertyBool","UsePlacements","Path","make True, if using the profile operation placement properties to transform toolpath in post processor")
obj.addProperty("App::PropertyLinkSub","Base","Path",translate("Parent Object","The base geometry of this toolpath"))
obj.addProperty("App::PropertyBool","Active","Path",translate("Path","Make False, to prevent operation from generating code"))
obj.addProperty("App::PropertyString","Comment","Path",translate("Path","An optional comment for this profile"))
obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool","The tool number in use")
obj.addProperty("App::PropertyEnumeration", "Algorithm", "Algorithm",translate("Path", "The library or algorithm used to generate the path"))
obj.Algorithm = ['OCC Native','libarea']
obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool",translate("Path","The tool number in use"))
obj.ToolNumber = (0,0,1000,1)
obj.setEditorMode('ToolNumber',1) #make this read only
#Depth Properties
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth","The height needed to clear clamps and obstructions")
obj.addProperty("App::PropertyLength", "StepDown", "Depth", "Incremental Step Down of Tool")
obj.addProperty("App::PropertyBool","UseStartDepth","Depth","make True, if manually specifying a Start Start Depth")
obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", "Starting Depth of Tool- first cut depth in Z")
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", "Final Depth of Tool- lowest value in Z")
obj.addProperty("App::PropertyDistance", "RetractHeight", "Depth","The height desired to retract tool when path is finished")
obj.addProperty("App::PropertyString","Comment","Path","An optional comment for this profile")
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", translate("Path","The height needed to clear clamps and obstructions"))
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", translate("Path","Rapid Safety Height between locations."))
obj.addProperty("App::PropertyFloatConstraint", "StepDown", "Depth", translate("Path","Incremental Step Down of Tool"))
obj.StepDown = (1,0.01,1000,0.5)
obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", translate("Path","Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", translate("Path","Final Depth of Tool- lowest value in Z"))
#obj.addProperty("App::PropertyDistance", "RetractHeight", "Depth", translate("Retract Height","The height desired to retract tool when path is finished"))
#Feed Properties
obj.addProperty("App::PropertySpeed", "VertFeed", "Feed","Feed rate for vertical moves in Z")
obj.addProperty("App::PropertySpeed", "HorizFeed", "Feed","Feed rate for horizontal moves")
obj.addProperty("App::PropertySpeed", "VertFeed", "Feed",translate("Path","Feed rate for vertical moves in Z"))
obj.addProperty("App::PropertySpeed", "HorizFeed", "Feed",translate("Path","Feed rate for horizontal moves"))
#Start Point Properties
obj.addProperty("App::PropertyVector","StartPoint","Start Point","The start point of this path")
obj.addProperty("App::PropertyBool","UseStartPoint","Start Point","make True, if specifying a Start Point")
obj.addProperty("App::PropertyLength", "ExtendAtStart", "Start Point","extra length of tool path before start of part edge")
obj.addProperty("App::PropertyLength", "LeadInLineLen", "Start Point","length of straight segment of toolpath that comes in at angle to first part edge")
obj.addProperty("App::PropertyVector","StartPoint","Start Point",translate("Path_Profile","The start point of this path"))
obj.addProperty("App::PropertyBool","UseStartPoint","Start Point",translate("Path_Profile","make True, if specifying a Start Point"))
obj.addProperty("App::PropertyLength", "ExtendAtStart", "Start Point", translate("Path_Profile", "extra length of tool path before start of part edge"))
obj.addProperty("App::PropertyLength", "LeadInLineLen", "Start Point", translate("Path_Profile","length of straight segment of toolpath that comes in at angle to first part edge"))
#End Point Properties
obj.addProperty("App::PropertyBool","UseEndPoint","End Point","make True, if specifying an End Point")
obj.addProperty("App::PropertyLength", "ExtendAtEnd", "End Point","extra length of tool path after end of part edge")
obj.addProperty("App::PropertyLength", "LeadOutLineLen", "End Point","length of straight segment of toolpath that comes in at angle to last part edge")
obj.addProperty("App::PropertyVector","EndPoint","End Point","The end point of this path")
obj.addProperty("App::PropertyBool","UseEndPoint","End Point",translate("Path_Profile","make True, if specifying an End Point"))
obj.addProperty("App::PropertyLength", "ExtendAtEnd", "End Point", translate("Path_Profile","extra length of tool path after end of part edge"))
obj.addProperty("App::PropertyLength", "LeadOutLineLen", "End Point", translate("Path_Profile","length of straight segment of toolpath that comes in at angle to last part edge"))
obj.addProperty("App::PropertyVector","EndPoint","End Point",translate("Path_Profile","The end point of this path"))
#Profile Properties
obj.addProperty("App::PropertyEnumeration", "Side", "Profile","Side of edge that tool should cut")
obj.addProperty("App::PropertyEnumeration", "Side", "Profile", translate("Path_Profile","Side of edge that tool should cut"))
obj.Side = ['Left','Right','On'] #side of profile that cutter is on in relation to direction of profile
obj.addProperty("App::PropertyEnumeration", "Direction", "Profile","The direction that the toolpath should go around the part ClockWise CW or CounterClockWise CCW")
obj.addProperty("App::PropertyEnumeration", "Direction", "Profile",translate("Path_Profile", "The direction that the toolpath should go around the part ClockWise CW or CounterClockWise CCW"))
obj.Direction = ['CW','CCW'] #this is the direction that the profile runs
obj.addProperty("App::PropertyBool","UseComp","Profile",translate("Path_Profile","make True, if using Cutter Radius Compensation"))
obj.addProperty("App::PropertyDistance", "RollRadius", "Profile","Radius at start and end")
obj.addProperty("App::PropertyDistance", "OffsetExtra", "Profile","Extra value to stay away from final profile- good for roughing toolpath")
obj.addProperty("App::PropertyLength", "SegLen", "Profile","Tesselation value for tool paths made from beziers, bsplines, and ellipses")
obj.addProperty("App::PropertyDistance", "RollRadius", "Profile", translate("Path_Profile","Radius at start and end"))
obj.addProperty("App::PropertyDistance", "OffsetExtra", "Profile",translate("Path_Profile","Extra value to stay away from final profile- good for roughing toolpath"))
obj.addProperty("App::PropertyLength", "SegLen", "Profile",translate("Path_Profile","Tesselation value for tool paths made from beziers, bsplines, and ellipses"))
obj.addProperty("App::PropertyVectorList", "locs", "Tags", translate("Path_Profile", "List of holding tag locations"))
obj.addProperty("App::PropertyFloatList","angles","Tags", translate("Path_Profile", "List of angles for the holding tags"))
obj.addProperty("App::PropertyFloatList","heights","Tags", translate("Path_Profile", "List of angles for the holding tags"))
obj.addProperty("App::PropertyFloatList","lengths","Tags", translate("Path_Profile", "List of angles for the holding tags"))
obj.Proxy = self
@@ -101,68 +138,125 @@ class ObjectProfile:
return None
def execute(self,obj):
import Part, DraftGeomUtils, math
import PathScripts.PathKurveUtils as PathKurveUtils
from PathScripts.PathUtils import depth_params
if obj.Base:
# tie the toolnumber to the PathLoadTool object ToolNumber
if len(obj.InList)>0: #check to see if obj is in the Project group yet
project = obj.InList[0]
tl = int(PathUtils.changeTool(obj,project))
obj.ToolNumber= tl
tool = PathUtils.getTool(obj,obj.ToolNumber)
if tool:
radius = tool.Diameter/2
else:
# temporary value, to be taken from the properties later on
radius = 0.001
if obj.Base[0].Shape.ShapeType == "Wire": #a pure wire was picked
wire = obj.Base[0].Shape
else: #we are dealing with a face and it's edges or just a face
if obj.Edge1:
e1 = FreeCAD.ActiveDocument.getObject(obj.Base[0].Name).Shape.Edges[eval(obj.Edge1[1][0].lstrip('Edge'))-1]
if e1.BoundBox.ZMax <> e1.BoundBox.ZMin:
FreeCAD.Console.PrintError('vertical edges not valid yet\n')
return
if obj.Base[0].Shape.ShapeType =='Wire':
wire = obj.Base[0].Shape
if obj.Base[0].Shape.ShapeType =='Solid' or obj.Base[0].Shape.ShapeType =='Compound':
shape = obj.Base[0].Shape
for fw in shape.Wires:
if (fw.BoundBox.ZMax == e1.BoundBox.ZMax) and (fw.BoundBox.ZMin == e1.BoundBox.ZMin):
for e in fw.Edges:
if e.isSame(e1):
#FreeCAD.Console.PrintMessage('found the same objects\n')
wire = fw
elif obj.Face1: # we are only dealing with a face or faces
f1 = FreeCAD.ActiveDocument.getObject(obj.Base[0].Name).Shape.Faces[eval(obj.Face1[1][0].lstrip('Face'))-1]
# make the side Left and direction CW for normal cnc milling
obj.Direction = 'CW'
obj.Side = "Left"
# we only consider the outer wire if this is a single Face
wire = f1.OuterWire
# temporary value,in case we don't have any tools defined already
radius = 0.25
depthparams = depth_params (obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, 0.0, obj.FinalDepth.Value, None)
clearance = obj.ClearanceHeight.Value
step_down=obj.StepDown
start_depth=obj.StartDepth.Value
final_depth=obj.FinalDepth.Value
rapid_safety_space=obj.SafeHeight.Value
side=obj.Side
offset_extra=obj.OffsetExtra.Value
use_CRC=obj.UseComp
vf=obj.VertFeed.Value
hf=obj.HorizFeed.Value
seglen=obj.SegLen.Value
direction = obj.Direction
# we only consider the outer wire if this is a Face
shape = getattr(obj.Base[0].Shape,obj.Base[1][0])
if shape.ShapeType in ["Edge"]:
edges = [getattr(obj.Base[0].Shape,sub) for sub in obj.Base[1]]
wire = Part.Wire(edges)
if not wire.Edges[0].isSame(shape):
wire.Edges.reverse()
if obj.Direction == 'CCW':
clockwise=False
else:
clockwise=True
output =""
output += '('+ str(obj.Comment)+')\n'
wire = shape.OuterWire
FirstEdge= None
if obj.Edge1:
ename = obj.Edge1[1][0]
edgeNumber = int(ename[4:])-1
FirstEdge = obj.Base[0].Shape.Edges[edgeNumber]
ZMax = obj.Base[0].Shape.BoundBox.ZMax
edgelist = wire.Edges
#edgelist = Part.__sortEdges__(wire.Edges)
ZCurrent = obj.ClearanceHeight.Value
if obj.UseStartDepth:
output += PathUtils.MakePath(wire,obj.Side,radius,clockwise,obj.ClearanceHeight.Value,obj.StepDown.Value,obj.StartDepth.Value, obj.FinalDepth.Value,FirstEdge,obj.PathClosed,obj.SegLen.Value,obj.VertFeed.Value,obj.HorizFeed.Value)
if obj.StartPoint and obj.UseStartPoint:
startpoint = obj.StartPoint
else:
output += PathUtils.MakePath(wire,obj.Side,radius,clockwise,obj.ClearanceHeight.Value,obj.StepDown.Value,ZMax, obj.FinalDepth.Value,FirstEdge,obj.PathClosed,obj.SegLen.Value,obj.VertFeed.Value,obj.HorizFeed.Value)
startpoint = None
if obj.EndPoint and obj.UseEndPoint:
endpoint = obj.EndPoint
else:
endpoint = None
edgelist = Part.__sortEdges__(edgelist)
if obj.Algorithm == "OCC Native":
output = ""
output += '('+ str(obj.Comment)+')\n'
if obj.Direction == 'CCW':
clockwise=False
else:
clockwise=True
FirstEdge= None
PathClosed = DraftGeomUtils.isReallyClosed(wire)
output += PathUtils.MakePath(wire, side, radius, clockwise, clearance, step_down, start_depth, final_depth, FirstEdge, PathClosed, seglen, vf, hf)
else:
try:
import area
except:
FreeCAD.Console.PrintError(translate("Path","libarea needs to be installed for this command to work.\n"))
return
PathKurveUtils.output('mem')
output = ""
curve = PathKurveUtils.makeAreaCurve(edgelist,direction,startpoint, endpoint)
'''The following line uses a profile function written for use with FreeCAD. It's clean but incomplete. It doesn't handle
holding tags
start location
CRC
or probably other features in heekscnc'''
#output += PathKurveUtils.profile(curve, side, radius, vf, hf, offset_extra, rapid_safety_space, clearance, start_depth, step_down, final_depth, use_CRC)
'''The following calls the original procedure from heekscnc profile function. This, in turn, calls many other procedures to modify the profile.
This procedure is hacked together from heekscnc and has not been thoroughly reviewed or understood for FreeCAD. It can probably be
thoroughly optimized and improved but it'll take a smarter mind than mine to do it. -sliptonic Feb16'''
roll_radius = 2.0
extend_at_start = 0.0
extend_at_end = 0.0
lead_in_line_len=0.0
lead_out_line_len= 0.0
'''
Right here, I need to know the Holding Tags group from the tree that refers to this profile operation and build up the tags for PathKurve Utils.
I need to access the location vector, length, angle in radians and height.
'''
PathKurveUtils.clear_tags()
for i in range(len(obj.locs)):
tag = obj.locs[i]
h = obj.heights[i]
l = obj.lengths[i]
a = math.radians(obj.angles[i])
PathKurveUtils.add_tag(area.Point(tag.x,tag.y), l, a, h)
PathKurveUtils.profile2(curve, side, radius, vf, hf, offset_extra, roll_radius, None,None, depthparams, extend_at_start, extend_at_end, lead_in_line_len,lead_out_line_len)
output += PathKurveUtils.retrieve_gcode()
if obj.Active:
path = Path.Path(output)
@@ -175,19 +269,141 @@ class ObjectProfile:
obj.ViewObject.Visibility = False
# class ViewProviderProfile:
# def __init__(self,vobj):
# vobj.Proxy = self
# def attach(self,vobj):
# self.Object = vobj.Object
# return
# def getIcon(self):
# return ":/icons/Path-Profile.svg"
# def __getstate__(self):
# return None
# def __setstate__(self,state):
# return None
class ViewProviderProfile:
class CommandPathProfile:
def GetResources(self):
return {'Pixmap' : 'Path-Profile',
'MenuText': QtCore.QT_TRANSLATE_NOOP("PathProfile","Profile"),
'Accel': "P, P",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathProfile","Creates a Path Profile object from selected faces")}
def IsActive(self):
return not FreeCAD.ActiveDocument is None
def Activated(self):
import Path
from PathScripts import PathProject, PathUtils, PathKurve, PathKurveUtils
# check that the selection contains exactly what we want
selection = FreeCADGui.Selection.getSelectionEx()
if len(selection) != 1:
FreeCAD.Console.PrintError(translate("Path","Select one or more edges or a face from one Document object.\n"))
return
if len(selection[0].SubObjects) == 0:
FreeCAD.Console.PrintError(translate("Path","Select one or more edges or a face from one Document object.\n"))
return
for s in selection[0].SubObjects:
if s.ShapeType != "Edge":
if (s.ShapeType != "Face") or (len(selection[0].SubObjects) != 1):
FreeCAD.Console.PrintError(translate("Path","Please select only edges or a single face\n"))
return
if selection[0].SubObjects[0].ShapeType == "Edge":
try:
import Part
w = Part.Wire(selection[0].SubObjects)
except:
FreeCAD.Console.PrintError(translate("Path","The selected edges don't form a loop\n"))
return
# if everything is ok, execute and register the transaction in the undo/redo stack
# Take a guess at some reasonable values for Finish depth.
bb = selection[0].Object.Shape.BoundBox #parent boundbox
fbb = selection[0].SubObjects[0].BoundBox #feature boundbox
if fbb.ZMax < bb.ZMax:
zbottom = fbb.ZMax
else:
zbottom = bb.ZMin
FreeCAD.ActiveDocument.openTransaction(translate("Path","Create a Profile operation using libarea"))
FreeCADGui.addModule("PathScripts.PathProfile")
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Profile")')
FreeCADGui.doCommand('PathScripts.PathProfile.makeProfile(obj)')
#FreeCADGui.doCommand('PathScripts.PathProfile.ObjectProfile(obj)')
FreeCADGui.doCommand('obj.Active = True')
subs ="["
for s in selection[0].SubElementNames:
subs += '"' + s + '",'
subs += "]"
FreeCADGui.doCommand('obj.Base = (FreeCAD.ActiveDocument.' + selection[0].ObjectName + ',' + subs + ')')
#FreeCADGui.doCommand('obj.ViewObject.Proxy = 0')
FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(bb.ZMax + 10.0))
FreeCADGui.doCommand('obj.StepDown = 1.0')
FreeCADGui.doCommand('obj.StartDepth= ' + str(bb.ZMax))
FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom))
FreeCADGui.doCommand('obj.SafeHeight = '+ str(bb.ZMax + 2.0))
FreeCADGui.doCommand('obj.Side = "Left"')
FreeCADGui.doCommand('obj.OffsetExtra = 0.0')
FreeCADGui.doCommand('obj.Direction = "CW"')
FreeCADGui.doCommand('obj.UseComp = False')
FreeCADGui.doCommand('PathScripts.PathUtils.addToProject(obj)')
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
class _ViewProviderProfile:
"A View Provider for the Holding object"
def __init__(self,vobj):
vobj.Proxy = self
def attach(self,vobj):
self.Object = vobj.Object
return
def getIcon(self):
return ":/icons/Path-Profile.svg"
def claimChildren(self):
return []
def attach(self, vobj):
return
def getDisplayModes(self,vobj):
return ["Default"]
def getDefaultDisplayMode(self):
return "Default"
def setDisplayMode(self,mode):
return mode
def updateData(self,obj,prop):
return
def onChanged(self, vobj, prop):
return
def setEdit(self,vobj,mode=0):
FreeCADGui.Control.closeDialog()
taskd = _EditPanel()
taskd.obj = vobj.Object
taskd.update()
FreeCADGui.Control.showDialog(taskd)
return True
def unsetEdit(self,vobj,mode):
FreeCADGui.Control.closeDialog()
return
def doubleClicked(self,vobj):
self.setEdit(vobj)
def __getstate__(self):
return None
@@ -195,88 +411,160 @@ class ViewProviderProfile:
def __setstate__(self,state):
return None
class _EditPanel:
'''The editmode TaskPanel for profile tags'''
def __init__(self):
# the panel has a tree widget that contains categories
# for the subcomponents, such as additions, subtractions.
# the categories are shown only if they are not empty.
class CommandPathProfile:
def GetResources(self):
return {'Pixmap' : 'Path-Profile',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Profile","Profile"),
'Accel': "P, P",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Profile","Creates a Path Profile object from selected faces")}
self.updating = False
def IsActive(self):
return not FreeCAD.ActiveDocument is None
self.obj = None
self.form = QtGui.QWidget()
self.form.setObjectName("TaskPanel")
self.grid = QtGui.QGridLayout(self.form)
self.grid.setObjectName("grid")
self.title = QtGui.QLabel(self.form)
self.grid.addWidget(self.title, 0, 0, 1, 2)
# tree
self.tree = QtGui.QTreeWidget(self.form)
self.grid.addWidget(self.tree, 1, 0, 1, 2)
self.tree.setColumnCount(4)
self.tree.header().resizeSection(0,50)
self.tree.header().resizeSection(1,80)
self.tree.header().resizeSection(2,60)
self.tree.header().resizeSection(3,60)
# buttons
self.addButton = QtGui.QPushButton(self.form)
self.addButton.setObjectName("addButton")
self.addButton.setIcon(QtGui.QIcon(":/icons/Arch_Add.svg"))
self.grid.addWidget(self.addButton, 3, 0, 1, 1)
self.addButton.setEnabled(True)
self.delButton = QtGui.QPushButton(self.form)
self.delButton.setObjectName("delButton")
self.delButton.setIcon(QtGui.QIcon(":/icons/Arch_Remove.svg"))
self.grid.addWidget(self.delButton, 3, 1, 1, 1)
self.delButton.setEnabled(True)
QtCore.QObject.connect(self.addButton, QtCore.SIGNAL("clicked()"), self.addElement)
QtCore.QObject.connect(self.delButton, QtCore.SIGNAL("clicked()"), self.removeElement)
QtCore.QObject.connect(self.tree, QtCore.SIGNAL("itemChanged(QTreeWidgetItem *, int)"), self.edit)
self.update()
self.retranslateUi(self.form)
def isAllowedAlterSelection(self):
return False
def isAllowedAlterView(self):
return True
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Close)
def update(self):
'fills the treewidget'
self.updating = True
self.tree.clear()
if self.obj:
for i in range(len(self.obj.locs)):
item = QtGui.QTreeWidgetItem(self.tree)
item.setText(0,str(i+1))
l = self.obj.locs[i]
item.setText(1,str(l.x)+", " + str(l.y) +", " + str(l.z))
item.setText(2,str(self.obj.heights[i]))
item.setText(3,str(self.obj.lengths[i]))
item.setText(4,str(self.obj.angles[i]))
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
item.setTextAlignment(0,QtCore.Qt.AlignLeft)
self.retranslateUi(self.form)
self.updating = False
return
def addElement(self):
self.updating = True
item = QtGui.QTreeWidgetItem(self.tree)
item.setText(0,str(self.tree.topLevelItemCount()))
item.setText(1,"0.0, 0.0, 0.0")
item.setText(2, str(float(4.0)))
item.setText(3, str(float(10.0)))
item.setText(4, str(float(45.0)))
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
self.updating = False
self.resetObject()
def removeElement(self):
it = self.tree.currentItem()
if it:
nr = int(it.text(0))-1
self.resetObject(remove=nr)
self.update()
def edit(self,item,column):
if not self.updating:
self.resetObject()
def resetObject(self,remove=None):
"transfers the values from the widget to the object"
loc = []
h = []
l = []
a = []
def Activated(self):
import Path
from PathScripts import PathUtils,PathProfile,PathProject
prjexists = False
selection = PathSelection.multiSelect()
for i in range(self.tree.topLevelItemCount()):
it = self.tree.findItems(str(i+1),QtCore.Qt.MatchExactly,0)[0]
if (remove == None) or (remove != i):
if it.text(1):
x = float(it.text(1).split()[0].rstrip(","))
y = float(it.text(1).split()[1].rstrip(","))
z = float(it.text(1).split()[2].rstrip(","))
loc.append(Vector(x,y,z))
if not selection:
return
else:
loc.append(0.0)
if it.text(2):
h.append(float(it.text(2)))
else:
h.append(4.0)
if it.text(3):
l.append(float(it.text(3)))
else:
l.append(5.0)
if it.text(4):
a.append(float(it.text(4)))
else:
a.append(45.0)
# if everything is ok, execute and register the transaction in the undo/redo stack
FreeCAD.ActiveDocument.openTransaction(translate("Path_Profile","Create Profile"))
FreeCADGui.addModule("PathScripts.PathProfile")
self.obj.locs = loc
self.obj.heights = h
self.obj.lengths = l
self.obj.angles = a
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Profile")
PathProfile.ObjectProfile(obj)
PathProfile.ViewProviderProfile(obj.ViewObject)
obj.Base = (FreeCAD.ActiveDocument.getObject(selection['objname']))
if selection['facenames']:
#FreeCAD.Console.PrintMessage('There are edges selected\n')
obj.Face1 = (FreeCAD.ActiveDocument.getObject(selection['objname']),selection['facenames'][0])
if len(selection['facenames'])>1:
obj.Face2 = (FreeCAD.ActiveDocument.getObject(selection['objname']),selection['facenames'][-1])
if selection['edgenames']:
#FreeCAD.Console.PrintMessage('There are edges selected\n')
obj.Edge1 =(FreeCAD.ActiveDocument.getObject(selection['objname']),(selection['edgenames'][0]))
if len(selection['edgenames'])>1:
obj.Edge2 =(FreeCAD.ActiveDocument.getObject(selection['objname']),(selection['edgenames'][-1]))
if selection['pointlist']:
FreeCADGui.doCommand('from FreeCAD import Vector')
stptX, stptY, stptZ = selection['pointlist'][0].X, selection['pointlist'][0].Y, selection['pointlist'][0].Z
obj.StartPoint = Vector((stptX),(stptY),(stptZ))
if len(selection['pointlist'])>1: # we have more than one point so we have an end point
endptX, endptY, endptZ = selection['pointlist'][-1].X, selection['pointlist'][-1].Y, selection['pointlist'][-1].Z
obj.EndPoint = Vector(endptX,endptY,endptZ)
if selection['pathwire'].isClosed():
obj.PathClosed = True
if selection['clockwise']:
obj.Side = "Left"
obj.Direction = "CW"
elif selection['clockwise'] == False:
obj.Side = "Right"
obj.Direction = "CCW"
else:
obj.Side = "On"
obj.Direction = "CCW"
obj.PathClosed = False
ZMax = obj.Base[0].Shape.BoundBox.ZMax
ZMin = obj.Base[0].Shape.BoundBox.ZMin
obj.StepDown.Value = 1.0
obj.StartDepth.Value = ZMax- obj.StepDown.Value
obj.FinalDepth.Value = ZMin-1.0
obj.ClearanceHeight.Value = ZMax + 5.0
obj.SegLen.Value = 0.5
obj.Active = True
obj.ViewObject.ShowFirstRapid = False
project = PathUtils.addToProject(obj)
tl = PathUtils.changeTool(obj,project)
if tl:
obj.ToolNumber = tl
FreeCAD.ActiveDocument.commitTransaction()
self.obj.touch()
FreeCAD.ActiveDocument.recompute()
def reject(self):
FreeCAD.ActiveDocument.recompute()
FreeCADGui.ActiveDocument.resetEdit()
return True
def retranslateUi(self, TaskPanel=None):
TaskPanel.setWindowTitle(QtGui.QApplication.translate("Path", "Holding Tags", None, QtGui.QApplication.UnicodeUTF8))
self.delButton.setText(QtGui.QApplication.translate("Path", "Remove", None, QtGui.QApplication.UnicodeUTF8))
self.addButton.setText(QtGui.QApplication.translate("Path", "Add", None, QtGui.QApplication.UnicodeUTF8))
self.title.setText(QtGui.QApplication.translate("Path", "Tag Locations and Properties", None, QtGui.QApplication.UnicodeUTF8))
self.tree.setHeaderLabels([QtGui.QApplication.translate("Path", "", None, QtGui.QApplication.UnicodeUTF8),
QtGui.QApplication.translate("Path", "Location", None, QtGui.QApplication.UnicodeUTF8),
QtGui.QApplication.translate("Path", "Height", None, QtGui.QApplication.UnicodeUTF8),
QtGui.QApplication.translate("Path", "Length", None, QtGui.QApplication.UnicodeUTF8),
QtGui.QApplication.translate("Path", "Angle", None, QtGui.QApplication.UnicodeUTF8)])
if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_Profile',CommandPathProfile())

View File

@@ -39,43 +39,6 @@ def equals(p1,p2):
def Sort2Edges(edgelist):
'''Sort2Edges(edgelist) simple function to reorder the start and end pts of two edges
based on their selection order. Returns the list, the start point,
and their common point, => edgelist, vertex, vertex'''
if len(edgelist)>=2:
vlist = []
e0 = edgelist[0]
e1=edgelist[1]
a0 = e0.Vertexes[0]
a1 = e0.Vertexes[1]
b0 = e1.Vertexes[0]
b1 = e1.Vertexes[1]
# comparison routine to order two edges:
if equals(a1,b0):
vlist.append((a0.Point.x,a0.Point.y))
vlist.append((a1.Point.x,a1.Point.y))
vlist.append((b1.Point.x,b1.Point.y))
if equals(a0,b0):
vlist.append((a1.Point.x,a1.Point.y))
vlist.append((a0.Point.x,a0.Point.y))
vlist.append((b1.Point.x,b1.Point.y))
if equals(a0,b1):
vlist.append((a1.Point.x,a1.Point.y))
vlist.append((a0.Point.x,a0.Point.y))
vlist.append((b0.Point.x,b0.Point.y))
if equals(a1,b1):
vlist.append((a0.Point.x,a0.Point.y))
vlist.append((a1.Point.x,a1.Point.y))
vlist.append((b0.Point.x,b0.Point.y))
edgestart = Vector(vlist[0][0],vlist[0][1],e0.Vertexes[1].Z)
edgecommon = Vector(vlist[1][0],vlist[1][1],e0.Vertexes[1].Z)
return vlist,edgestart,edgecommon
def segments(poly):
''' A sequence of (x,y) numeric coordinates pairs '''
@@ -92,135 +55,5 @@ def check_clockwise(poly):
return clockwise
def multiSelect():
'''
multiSelect() A function for selecting elements of an object for CNC path operations.
Select just a face, an edge,or two edges to indicate direction, a vertex on the object, a point not on the object,
or some combination. Returns a dictionary.
'''
sel = FreeCADGui.Selection.getSelectionEx()
numobjs = len([selobj.Object for selobj in sel])
if numobjs == 0:
FreeCAD.Console.PrintError('Please select some objects and try again.\n')
return
goodselect = False
for s in sel:
for i in s.SubObjects:
if i.ShapeType == 'Face':
goodselect = True
if i.ShapeType == 'Edge':
goodselect = True
if i.ShapeType == 'Vertex':
goodselect = True
if not goodselect:
FreeCAD.Console.PrintError('Please select a face and/or edges along with points (optional) and try again.\n')
return
selItems = {}
selItems['objname']=None #the parent object name - a 3D solid
selItems['pointlist']=None #start and end points
selItems['pointnames']=None #names of points for document object
selItems['facenames']=None # the selected face name
selItems['facelist']=None #list of faces selected
selItems['edgelist']=None #some edges that could be selected along with points and faces
selItems['edgenames']=None
selItems['pathwire']=None #the whole wire around edges of the face
selItems['clockwise']=None
selItems['circles']=None
facenames = []
edgelist =[]
edgenames=[]
ptlist=[]
ptnames=[]
circlelist=[]
face = False
edges = False
points = False
wireobj = False
circles = False
facelist= []
for s in sel:
if s.Object.Shape.ShapeType in ['Solid','Compound','Wire','Vertex']:
if not (s.Object.Shape.ShapeType =='Vertex'):
objname = s.ObjectName
selItems['objname'] =objname
if s.Object.Shape.ShapeType == 'Wire':
wireobj = True
if s.Object.Shape.ShapeType == 'Vertex':
ptnames.append(s.ObjectName)
# ptlist.append(s.Object)
points = True
for sub in s.SubObjects:
if sub.ShapeType =='Face':
facelist.append(sub)
face = True
if sub.ShapeType =='Edge':
edge = sub
edgelist.append(edge)
edges = True
if isinstance(sub.Curve,Part.Circle):
circlelist.append(edge)
circles = True
if sub.ShapeType =='Vertex':
ptlist.append(sub)
points = True
for sub in s.SubElementNames:
if 'Face' in sub:
facename = sub
facenames.append(facename)
if 'Edge' in sub:
edgenames.append(sub)
# now indicate which wire is going to be processed, based on which edges are selected
if facelist:
selItems['facelist']=facelist
if edges:
if face:
selItems['edgelist'] =edgelist
for fw in facelist[0].Wires:
for e in fw.Edges:
if e.isSame(edge):
pathwire = fw
selItems['pathwire'] =pathwire
elif wireobj:
selItems['pathwire'] =s.Object.Shape
selItems['edgelist'] =edgelist
else:
for w in s.Object.Shape.Wires:
for e in w.Edges:
if e.BoundBox.ZMax == e.BoundBox.ZMin: #if they are on same plane in Z as sel edge
if e.isSame(edge):
pathwire = w
selItems['pathwire'] =pathwire
selItems['edgelist'] =edgelist
if not edges:
if face:
selItems['pathwire'] =facelist[0].OuterWire
if edges and (len(edgelist)>=2):
vlist,edgestart,edgecommon=Sort2Edges(edgelist)
edgepts ={}
edgepts['vlist'] = vlist
edgepts['edgestart']=edgestart # start point of edges selected
edgepts['edgecommon']=edgecommon # point where two edges join- will be last point in in first gcode line
selItems['edgepts']=edgepts
if check_clockwise(vlist):
selItems['clockwise']=True
elif check_clockwise(vlist) == False:
selItems['clockwise']=False
if points:
selItems['pointlist'] = ptlist
selItems['pointnames'] = ptnames
if edges:
selItems['edgenames']=edgenames
if face:
selItems['facenames'] = facenames
if circles:
selItems['circles'] = circlelist
return selItems

View File

@@ -0,0 +1,237 @@
# -*- coding: utf-8 -*-
#***************************************************************************
#* *
#* Copyright (c) 2016 sliptonic <shopinthewoods@gmail.com> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
import FreeCAD,FreeCADGui,Path,PathGui
from FreeCAD import Vector
from PySide import QtCore,QtGui
from PathScripts import PathUtils,PathSelection,PathProject
"""Path Surface object and FreeCAD command"""
'''Surface operation is used for 3D sculpting, roughing, and finishing
Possible algorithms include waterline, zigzag, and adaptive roughing.
Libraries to consider: opencamlib and libactp'''
# Qt tanslation handling
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def translate(context, text, disambig=None):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def translate(context, text, disambig=None):
return QtGui.QApplication.translate(context, text, disambig)
class ObjectProfile:
def __init__(self,obj):
obj.addProperty("App::PropertyLinkSub","Base","Path",translate("Parent Object","The base geometry of this toolpath"))
obj.addProperty("App::PropertyBool","Active","Path",translate("Active","Make False, to prevent operation from generating code"))
obj.addProperty("App::PropertyString","Comment","Path",translate("Comment","An optional comment for this profile"))
obj.addProperty("App::PropertyEnumeration", "Algorithm", "Algorithm",translate("PathProject", "The library to use to generate the path"))
obj.Algorithm = ['OCL Waterline']
obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool",translate("PathProfile","The tool number in use"))
obj.ToolNumber = (0,0,1000,1)
obj.setEditorMode('ToolNumber',1) #make this read only
#Depth Properties
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", translate("Clearance Height","The height needed to clear clamps and obstructions"))
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", translate("PathProject","Rapid Safety Height between locations."))
obj.addProperty("App::PropertyFloatConstraint", "StepDown", "Depth", translate("StepDown","Incremental Step Down of Tool"))
obj.StepDown = (1,0.01,1000,0.5)
obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", translate("Start Depth","Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", translate("Final Depth","Final Depth of Tool- lowest value in Z"))
#Feed Properties
obj.addProperty("App::PropertySpeed", "VertFeed", "Feed",translate("Vert Feed","Feed rate for vertical moves in Z"))
obj.addProperty("App::PropertySpeed", "HorizFeed", "Feed",translate("Horiz Feed","Feed rate for horizontal moves"))
#Start Point Properties
obj.addProperty("App::PropertyVector","StartPoint","Start Point",translate("Start Point","The start point of this path"))
obj.addProperty("App::PropertyBool","UseStartPoint","Start Point",translate("Use Start Point","make True, if specifying a Start Point"))
obj.addProperty("App::PropertyLength", "ExtendAtStart", "Start Point", translate("extend at start", "extra length of tool path before start of part edge"))
obj.addProperty("App::PropertyLength", "LeadInLineLen", "Start Point", translate("lead in length","length of straight segment of toolpath that comes in at angle to first part edge"))
#End Point Properties
obj.addProperty("App::PropertyBool","UseEndPoint","End Point",translate("Use End Point","make True, if specifying an End Point"))
obj.addProperty("App::PropertyLength", "ExtendAtEnd", "End Point", translate("extend at end","extra length of tool path after end of part edge"))
obj.addProperty("App::PropertyLength", "LeadOutLineLen", "End Point", translate("lead_out_line_len","length of straight segment of toolpath that comes in at angle to last part edge"))
obj.addProperty("App::PropertyVector","EndPoint","End Point",translate("End Point","The end point of this path"))
#Surface Properties
obj.Proxy = self
def __getstate__(self):
return None
def __setstate__(self,state):
return None
def execute(self,obj):
import Part, DraftGeomUtils
from PathScripts.PathUtils import depth_params
if obj.Base:
# tie the toolnumber to the PathLoadTool object ToolNumber
if len(obj.InList)>0: #check to see if obj is in the Project group yet
project = obj.InList[0]
tl = int(PathUtils.changeTool(obj,project))
obj.ToolNumber= tl
tool = PathUtils.getTool(obj,obj.ToolNumber)
if tool:
radius = tool.Diameter/2
else:
# temporary value,in case we don't have any tools defined already
radius = 0.25
depthparams = depth_params (obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, 0.0, obj.FinalDepth.Value, None)
clearance = obj.ClearanceHeight.Value
step_down=obj.StepDown
start_depth=obj.StartDepth.Value
final_depth=obj.FinalDepth.Value
rapid_safety_space=obj.SafeHeight.Value
vf=obj.VertFeed.Value
hf=obj.HorizFeed.Value
'''Parse the base and get the necessary geometry here'''
if obj.Algorithm == "OCL Waterline":
try:
import ocl
except:
FreeCAD.Console.PrintError(translate("Path","OpenCAMLib needs to be installed for this command to work.\n"))
return
output = ""
output += '('+ str(obj.Comment)+')\n'
output += self.buildoclwaterline()
else:
return
if obj.Active:
path = Path.Path(output)
obj.Path = path
obj.ViewObject.Visibility = True
else:
path = Path.Path("(inactive operation)")
obj.Path = path
obj.ViewObject.Visibility = False
def buildoclwaterline(self):
output = "Some text"
return output
class ViewProviderProfile:
def __init__(self,vobj):
vobj.Proxy = self
def attach(self,vobj):
self.Object = vobj.Object
return
def getIcon(self):
return ":/icons/Path-Surface.svg"
def __getstate__(self):
return None
def __setstate__(self,state):
return None
class CommandPathProfile:
def GetResources(self):
return {'Pixmap' : 'Path-Surface',
'MenuText': QtCore.QT_TRANSLATE_NOOP("PathSurface","Surface"),
'Accel': "P, P",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathSurface","Creates a Path Surface object from selected solid")}
def IsActive(self):
return not FreeCAD.ActiveDocument is None
def Activated(self):
import Path
from PathScripts import PathProject, PathUtils
# check that the selection contains exactly what we want
selection = FreeCADGui.Selection.getSelectionEx()
if len(selection) != 1:
FreeCAD.Console.PrintError(translate("Path","Select a Solid.\n"))
return
if len(selection[0].SubObjects) == 0:
FreeCAD.Console.PrintError(translate("Path","Select a Solid.\n"))
return
# if everything is ok, execute and register the transaction in the undo/redo stack
# Take a guess at some reasonable values for Finish depth.
bb = selection[0].Object.Shape.BoundBox #parent boundbox
fbb = selection[0].SubObjects[0].BoundBox #feature boundbox
if fbb.ZMax < bb.ZMax:
zbottom = fbb.ZMax
else:
zbottom = bb.ZMin
FreeCAD.ActiveDocument.openTransaction(translate("Path","Create a Surfacing Operation"))
FreeCADGui.addModule("PathScripts.PathSurface")
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Surface")')
FreeCADGui.doCommand('PathScripts.PathSurface.ObjectProfile(obj)')
FreeCADGui.doCommand('obj.Active = True')
# subs ="["
# for s in selection[0].SubElementNames:
# subs += '"' + s + '",'
# subs += "]"
# FreeCADGui.doCommand('obj.Base = (FreeCAD.ActiveDocument.' + selection[0].ObjectName + ',' + subs + ')')
FreeCADGui.doCommand('obj.ViewObject.Proxy = 0')
FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(bb.ZMax + 10.0))
FreeCADGui.doCommand('obj.StepDown = 1.0')
FreeCADGui.doCommand('obj.StartDepth= ' + str(bb.ZMax))
FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom))
FreeCADGui.doCommand('obj.SafeHeight = '+ str(bb.ZMax + 2.0))
FreeCADGui.doCommand('PathScripts.PathUtils.addToProject(obj)')
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_Surface',CommandPathSurface())
FreeCAD.Console.PrintLog("Loading PathSurface... done\n")

View File

@@ -53,8 +53,9 @@ def cleanedges(splines,precision):
edges = curvetowire(spline, 1.0) #fixme hardcoded value
elif geomType(spline)=="Circle":
#arcs=filterArcs(spline)
edges.append(spline)
arcs=filterArcs(spline)
for i in arcs:
edges.append(Part.Edge(i))
elif geomType(spline)=="Line":
edges.append(spline)
@@ -285,7 +286,8 @@ def MakePath(wire,Side,radius,clockwise,ZClearance,StepDown,ZStart,ZFinalDepth,f
''' makes the path - just a simple profile for now '''
offset = SortPath(wire,Side,radius,clockwise,firstedge,SegLen=0.5)
toolpath = offset.Edges[:]
paths = ""
paths = ""
paths += "G0 Z" + str(ZClearance)+"\n"
first = toolpath[0].Vertexes[0].Point
paths += "G0 X"+str(fmt(first.x))+"Y"+str(fmt(first.y))+"\n"
ZCurrent = ZStart- StepDown
@@ -382,3 +384,79 @@ def getLastZ(obj):
lastZ= c.Parameters['Z']
return lastZ
def frange(start, stop, step, finish):
x = []
curdepth = start
if step == 0:
return x
# do the base cuts until finishing round
while curdepth >= stop + step + finish:
curdepth = curdepth - step
if curdepth <= stop + finish:
curdepth = stop + finish
x.append(curdepth)
# we might have to do a last pass or else finish round might be too far away
if curdepth - stop > finish:
x.append(stop + finish)
# do the the finishing round
if curdepth >= stop:
curdepth = stop
x.append(curdepth)
# Why this?
# if start >= stop:
# start = stop
# x.append (start)
return x
class depth_params:
def __init__(self, clearance_height, rapid_safety_space, start_depth, step_down, z_finish_depth, final_depth, user_depths=None):
self.clearance_height = clearance_height
self.rapid_safety_space = math.fabs(rapid_safety_space)
self.start_depth = start_depth
self.step_down = math.fabs(step_down)
self.z_finish_depth = math.fabs(z_finish_depth)
self.final_depth = final_depth
self.user_depths = user_depths
def get_depths(self):
depths = []
if self.user_depths != None:
depths = self.user_depths
else:
depth = self.final_depth
depths = [depth]
depth += self.z_finish_depth
if depth + 0.0000001 < self.start_depth:
if self.z_finish_depth > 0.0000001: depths.insert(0, depth)
layer_count = int((self.start_depth - depth) / self.step_down - 0.0000001) + 1
if layer_count > 0:
layer_depth = (self.start_depth - depth)/layer_count
for i in range(1, layer_count):
depth += layer_depth
depths.append(depth)
return depths
# def get_depths(start_depth, final_depth, step_down, z_finish_depth):
# '''get_depths returns a list of z heights for pocket clearing. First value is Z depth of the first pass, etc.
# start_depth: starting depth of pocket
# step_down: max amount removed per pocket pass
# z_finish_depth: amount to remove on last (finishing) pass
# final_depth: bottom of pocket'''
# depths = [depth]
# depth += z_finish_depth
# if depth + 0.0000001 < start_depth:
# if z_finish_depth > 0.0000001: depths.insert(0, depth)
# layer_count = int((start_depth - depth) / step_down - 0.0000001) + 1
# if layer_count > 0:
# layer_depth = (start_depth - depth)/layer_count
# for i in range(1, layer_count):
# depth += layer_depth
# depths.insert(0, depth)
# return depths

View File

@@ -0,0 +1,31 @@
import math
class depth_params:
def __init__(self, clearance_height, rapid_safety_space, start_depth, step_down, z_finish_depth, z_thru_depth, final_depth, user_depths):
self.clearance_height = clearance_height
self.rapid_safety_space = math.fabs(rapid_safety_space)
self.start_depth = start_depth
self.step_down = math.fabs(step_down)
self.z_finish_depth = math.fabs(z_finish_depth)
self.z_thru_depth = math.fabs(z_thru_depth)
self.final_depth = final_depth
self.user_depths = user_depths
def get_depths(self):
if self.user_depths != None:
depths = self.user_depths
else:
depth = self.final_depth - self.z_thru_depth
depths = [depth]
depth += self.z_finish_depth
if depth + 0.0000001 < self.start_depth:
if self.z_finish_depth > 0.0000001: depths.insert(0, depth)
depth += self.z_thru_depth
layer_count = int((self.start_depth - depth) / self.step_down - 0.0000001) + 1
if layer_count > 0:
layer_depth = (self.start_depth - depth)/layer_count
for i in range(1, layer_count):
depth += layer_depth
depths.insert(0, depth)
return depths

View File

@@ -0,0 +1,30 @@
import nc
import iso
import math
import datetime
import time
from format import Format
now = datetime.datetime.now()
class Creator(iso.Creator):
def __init__(self):
iso.Creator.__init__(self)
self.output_tool_definitions = False
self.fmt = Format(dp_wanted = False, add_trailing_zeros = True, add_plus = True)
def SPACE_STR(self): return ' '
def PROGRAM(self): return None
def PROGRAM_END(self): return( 'T0' + self.SPACE() + 'M06' + self.SPACE() + 'M02')
############################################################################
## Begin Program
def program_begin(self, id, comment):
self.write( ('(Created with Deckel FP4Ma post processor ' + str(now.strftime("%Y/%m/%d %H:%M")) + ')' + '\n') )
iso.Creator.program_begin(self, id, comment)
nc.creator = Creator()

View File

@@ -0,0 +1,6 @@
################################################################################
# __init__.py
#
# This is here to make python see NC folder
#
# Hirutso Enni, 2009-01-13

View File

@@ -0,0 +1,111 @@
# Preliminary postprocessor support for Anilam Crusader M CNC controller
# This code modified from iso.py and emc2.py distriuted with HeeksCAD as of Sep 2010
# Kurt Jensen 6 Sep 2010
# Use at your own risk.
import nc
import iso
class Creator(iso.Creator):
def init(self):
iso.Creator.init(self)
self.arc_centre_absolute = True
def SPACE(self): return(' ')
# This version of COMMENT removes comments from the resultant GCode
# Note: The Anilam hates comments when importing code.
def COMMENT(self,comment): return('')
def program_begin(self, id, comment):
self.write('%\n'); # Start of file token that Anilam Crusader M likes
# No Comments for the Anilam crusaher M, please......
#self.write( ('(' + comment + ')' + '\n') )
def program_end(self):
self.write_blocknum()
self.write('G29E\n') # End of code signal for Anilam Crusader M
self.write('%\n') # EOF signal for Anilam Crusader M
############################################################################
## Settings
def imperial(self):
self.write_blocknum()
self.write( self.IMPERIAL() + '\n')
self.fmt.number_of_decimal_places = 4
def metric(self):
self.write_blocknum()
self.write( self.METRIC() + '\n' )
self.fmt.number_of_decimal_places = 3
def absolute(self):
self.write_blocknum()
self.write( self.ABSOLUTE() + '\n')
def incremental(self):
self.write_blocknum()
self.write( self.INCREMENTAL() + '\n' )
def polar(self, on=True):
if (on) :
self.write_blocknum()
self.write(self.POLAR_ON() + '\n' )
else :
self.write_blocknum()
self.write(self.POLAR_OFF() + '\n' )
def set_plane(self, plane):
if (plane == 0) :
self.write_blocknum()
self.write('G17\n')
elif (plane == 1) :
self.write_blocknum()
self.write('G18\n')
elif (plane == 2) :
self.write_blocknum()
self.write('G19\n')
def comment(self, text):
self.write_blocknum()
############################################################################
## Tools
def tool_change(self, id):
self.write_blocknum()
self.write(('T%i' % id) + '\n')
self.t = id
def tool_defn(self, id, name='', params=None):
self.write_blocknum()
self.write(('T10%.2d' % id) + ' ')
if (radius != None):
self.write(('X%.3f' % radius) + ' ')
if (length != None):
self.write('Z%.3f' % length)
self.write('\n')
# This is the coordinate system we're using. G54->G59, G59.1, G59.2, G59.3
# These are selected by values from 1 to 9 inclusive.
def workplane(self, id):
if ((id >= 1) and (id <= 6)):
self.write_blocknum()
self.write( (self.WORKPLANE() % (id + self.WORKPLANE_BASE())) + '\n')
if ((id >= 7) and (id <= 9)):
self.write_blocknum()
self.write( ((self.WORKPLANE() % (6 + self.WORKPLANE_BASE())) + ('.%i' % (id - 6))) + '\n')
# inhibit N codes being generated for line numbers:
def write_blocknum(self):
pass
def drill(self, x=None, y=None, dwell=None, depthparams = None, retract_mode=None, spindle_mode=None, internal_coolant_on=None, rapid_to_clearance = None):
self.write('(Canned drill cycle ops are not yet supported here on this Anilam Crusader M postprocessor)')
nc.creator = Creator()

View File

@@ -0,0 +1,13 @@
# Preliminary backplot support for Anilam Crusader M CNC controller
# This code modified from iso_read.py and emc2_read.py distriuted with HeeksCAD as of Sep 2010
# Kurt Jensen 6 Sep 2010
# Use at your own risk.
import iso_read as iso
import sys
# Override some iso parser methods to interpret arc centers as relative to origin, not relative to start of arc.
class Parser(iso.Parser):
def __init__(self, writer):
iso.Parser.__init__(self, writer)
self.arc_centre_absolute = True

View File

@@ -0,0 +1,134 @@
################################################################################
# attach.py
#
# NC code creator for attaching Z coordinates to a surface
#
import recreator
import ocl
import ocl_funcs
import nc
attached = False
units = 1.0
################################################################################
class Creator(recreator.Redirector):
def __init__(self, original):
recreator.Redirector.__init__(self, original)
self.stl = None
self.cutter = None
self.minz = None
self.path = None
self.pdcf = None
self.material_allowance = 0.0
############################################################################
## Shift in Z
def setPdcfIfNotSet(self):
if self.pdcf == None:
self.pdcf = ocl.PathDropCutter()
self.pdcf.setSTL(self.stl)
self.pdcf.setCutter(self.cutter)
self.pdcf.setSampling(0.1)
self.pdcf.setZ(self.minz/units)
def z2(self, z):
path = ocl.Path()
# use a line with no length
path.append(ocl.Line(ocl.Point(self.x, self.y, self.z), ocl.Point(self.x, self.y, self.z)))
self.setPdcfIfNotSet()
if (self.z>self.minz):
self.pdcf.setZ(self.z) # Adjust Z if we have gotten a higher limit (Fix pocketing loosing steps when using attach?)
else:
self.pdcf.setZ(self.minz/units) # Else use minz
self.pdcf.setPath(path)
self.pdcf.run()
plist = self.pdcf.getCLPoints()
p = plist[0]
return p.z + self.material_allowance/units
def cut_path(self):
if self.path == None: return
self.setPdcfIfNotSet()
if (self.z>self.minz):
self.pdcf.setZ(self.z) # Adjust Z if we have gotten a higher limit (Fix pocketing loosing steps when using attach?)
else:
self.pdcf.setZ(self.minz/units) # Else use minz
# get the points on the surface
self.pdcf.setPath(self.path)
self.pdcf.run()
plist = self.pdcf.getCLPoints()
#refine the points
f = ocl.LineCLFilter()
f.setTolerance(0.005)
for p in plist:
f.addCLPoint(p)
f.run()
plist = f.getCLPoints()
i = 0
for p in plist:
if i > 0:
self.original.feed(p.x/units, p.y/units, p.z/units + self.material_allowance/units)
i = i + 1
self.path = ocl.Path()
def rapid(self, x=None, y=None, z=None, a=None, b=None, c=None ):
if z != None:
if z < self.z:
return
recreator.Redirector.rapid(self, x, y, z, a, b, c)
def feed(self, x=None, y=None, z=None, a=None, b=None, c=None):
px = self.x
py = self.y
pz = self.z
recreator.Redirector.feed(self, x, y, z, a, b, c)
if self.x == None or self.y == None or self.z == None:
return
if px == self.x and py == self.y:
return
# add a line to the path
if self.path == None: self.path = ocl.Path()
self.path.append(ocl.Line(ocl.Point(px, py, pz), ocl.Point(self.x, self.y, self.z)))
def arc(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None, ccw = True):
px = self.x
py = self.y
pz = self.z
recreator.Redirector.arc(self, x, y, z, i, j, k, r, ccw)
# add an arc to the path
if self.path == None: self.path = ocl.Path()
self.path.append(ocl.Arc(ocl.Point(px, py, pz), ocl.Point(self.x, self.y, self.z), ocl.Point(i, j, pz), ccw))
def set_ocl_cutter(self, cutter):
self.cutter = cutter
################################################################################
def attach_begin():
global attached
if attached == True:
attach_end()
nc.creator = Creator(nc.creator)
recreator.units = units
attached = True
nc.creator.pdcf = None
nc.creator.path = None
def attach_end():
global attached
nc.creator.cut_path()
nc.creator = nc.creator.original
attached = False

View File

@@ -0,0 +1,229 @@
################################################################################
# iso_read.py
#
# Simple ISO NC code parsing
#
# Hirutso Enni, 2009-01-13
""" use this script to backplot nc files to *.scr file for autocad,bricscad,
draftsight,progecad,ares commander, etc....
usage: python cad_iso_read.py temp.nc temp.scr
"""
import cad_nc_read as nc
import re
import sys
################################################################################
class Parser(nc.Parser):
def __init__(self, writer):
nc.Parser.__init__(self, writer)
self.pattern_main = re.compile('([(!;].*|\s+|[a-zA-Z0-9_:](?:[+-])?\d*(?:\.\d*)?|\w\#\d+|\(.*?\)|\#\d+\=(?:[+-])?\d*(?:\.\d*)?)')
#if ( or ! or ; at least one space or a letter followed by some character or not followed by a +/- followed by decimal, with a possible decimal point
# followed by a possible deimcal, or a letter followed by # with a decimal . deimcal
# add your character here > [(!;] for comments char
# then look for the 'comment' function towards the end of the file and add another elif
def ParseWord(self, word):
if (word[0] == 'A' or word[0] == 'a'):
self.col = "axis"
self.a = eval(word[1:])
self.move = True
elif (word[0] == 'B' or word[0] == 'b'):
self.col = "axis"
self.b = eval(word[1:])
self.move = True
elif (word[0] == 'C' or word[0] == 'c'):
self.col = "axis"
self.c = eval(word[1:])
self.move = True
elif (word[0] == 'F' or word[0] == 'f'):
self.col = "axis"
self.f = eval(word[1:])
self.move = True
elif (word == 'G0' or word == 'G00' or word == 'g0' or word == 'g00'):
self.path_col = "rapid"
self.col = "rapid"
self.arc = 0
elif (word == 'G1' or word == 'G01' or word == 'g1' or word == 'g01'):
self.path_col = "feed"
self.col = "feed"
self.arc = 0
elif (word == 'G2' or word == 'G02' or word == 'g2' or word == 'g02' or word == 'G12' or word == 'g12'):
self.path_col = "feed"
self.col = "feed"
self.arc = -1
elif (word == 'G3' or word == 'G03' or word == 'g3' or word == 'g03' or word == 'G13' or word == 'g13'):
self.path_col = "feed"
self.col = "feed"
self.arc = +1
elif (word == 'G10' or word == 'g10'):
self.no_move = True
elif (word == 'L1' or word == 'l1'):
self.no_move = True
elif (word == 'G61.1' or word == 'g61.1' or word == 'G61' or word == 'g61' or word == 'G64' or word == 'g64'):
self.no_move = True
elif (word == 'G20' or word == 'G70'):
self.col = "prep"
self.set_mode(units=25.4)
elif (word == 'G21' or word == 'G71'):
self.col = "prep"
self.set_mode(units=1.0)
elif (word == 'G81' or word == 'g81'):
self.drill = True
self.no_move = True
self.path_col = "feed"
self.col = "feed"
elif (word == 'G82' or word == 'g82'):
self.drill = True;
self.no_move = True
self.path_col = "feed"
self.col = "feed"
elif (word == 'G83' or word == 'g83'):
self.drill = True
self.no_move = True
self.path_col = "feed"
self.col = "feed"
elif (word == 'G90' or word == 'g90'):
self.absolute()
elif (word == 'G91' or word == 'g91'):
self.incremental()
elif (word[0] == 'G') : col = "prep"
elif (word[0] == 'I' or word[0] == 'i'):
self.col = "axis"
self.i = eval(word[1:])
self.move = True
elif (word[0] == 'J' or word[0] == 'j'):
self.col = "axis"
self.j = eval(word[1:])
self.move = True
elif (word[0] == 'K' or word[0] == 'k'):
self.col = "axis"
self.k = eval(word[1:])
self.move = True
elif (word[0] == 'M') : self.col = "misc"
elif (word[0] == 'N') : self.col = "blocknum"
elif (word[0] == 'O') : self.col = "program"
elif (word[0] == 'P' or word[0] == 'p'):
if (self.no_move != True):
self.col = "axis"
self.p = eval(word[1:])
self.move = True
elif (word[0] == 'Q' or word[0] == 'q'):
if (self.no_move != True):
self.col = "axis"
self.q = eval(word[1:])
self.move = True
elif (word[0] == 'R' or word[0] == 'r'):
self.col = "axis"
self.r = eval(word[1:])
self.move = True
elif (word[0] == 'S' or word[0] == 's'):
self.col = "axis"
self.s = eval(word[1:])
self.move = True
elif (word[0] == 'T') :
self.col = "tool"
self.set_tool( eval(word[1:]) )
elif (word[0] == 'X' or word[0] == 'x'):
self.col = "axis"
self.x = eval(word[1:])
self.move = True
elif (word[0] == 'Y' or word[0] == 'y'):
self.col = "axis"
self.y = eval(word[1:])
self.move = True
elif (word[0] == 'Z' or word[0] == 'z'):
self.col = "axis"
self.z = eval(word[1:])
self.move = True
elif (word[0] == '(') : (self.col, self.cdata) = ("comment", True)
elif (word[0] == '!') : (self.col, self.cdata) = ("comment", True)
elif (word[0] == ';') : (self.col, self.cdata) = ("comment", True)
elif (word[0] == '#') : self.col = "variable"
elif (word[0] == ':') : self.col = "blocknum"
elif (ord(word[0]) <= 32) : self.cdata = True
def Parse(self, name, oname=None):
self.files_open(name,oname)
#self.begin_ncblock()
#self.begin_path(None)
#self.add_line(z=500)
#self.end_path()
#self.end_ncblock()
self.path_col = None
self.f = None
self.arc = 0
while (self.readline()):
self.a = None
self.b = None
self.c = None
self.i = None
self.j = None
self.k = None
self.p = None
self.q = None
self.r = None
self.s = None
self.x = None
self.y = None
self.z = None
#self.begin_ncblock()
self.move = False
self.drill = False
self.no_move = False
words = self.pattern_main.findall(self.line)
for word in words:
self.col = None
self.cdata = False
self.ParseWord(word)
self.add_text(word, self.col, self.cdata)
if (self.drill):
self.begin_path("rapid")
self.add_line(self.x, self.y, self.r)
self.end_path()
self.begin_path("feed")
self.add_line(self.x, self.y, self.z)
self.end_path()
self.begin_path("feed")
self.add_line(self.x, self.y, self.r)
self.end_path()
else:
if (self.move and not self.no_move):
self.begin_path(self.path_col)
if (self.arc==-1):
self.add_arc(self.x, self.y, self.z, self.i, self.j, self.k, self.r, self.arc)
elif (self.arc==1):
#self.add_arc(x, y, z, i, j, k, -r, arc) #if you want to use arcs with R values uncomment the first part of this line and comment the next one
self.add_arc(self.x, self.y, self.z, self.i, self.j, self.k, self.r, self.arc)
else : self.add_line(self.x, self.y, self.z, self.a, self.b, self.c)
self.end_path()
self.end_ncblock()
self.files_close()
################################################################################
if __name__ == '__main__':
parser = ParserIso()
if len(sys.argv)>2:
parser.Parse(sys.argv[1],sys.argv[2])
else:
parser.Parse(sys.argv[1])

View File

@@ -0,0 +1,113 @@
################################################################################
# cad_nc_read.py
#
# Base class for NC code parsing and backplotting
#
# Dan Falck 2011/01/06
################################################################################
class Parser:
def __init__(self):
self.currentx = -1.0
self.currenty = 0.0
self.currentz = 0.0
x,y,z = 0.0,0.0,0.0
self.absolute_flag = True
############################################################################
## Internals
def files_open(self, name, oname=None):
if (oname == None ):
oname = (name+'.scr')
self.file_in = open(name, 'r')
self.file_out = open(oname, 'w')
def files_close(self):
self.file_in.close()
self.file_out.write('-linetype set continuous\n')
self.file_out.write('\n')
self.file_out.close()
def readline(self):
self.line = self.file_in.readline().rstrip()
if (len(self.line)):
return True
else:
return False
def write(self, s):
self.file_out.write(s)
############################################################################
def end_ncblock(self):
self.file_out.write('Delay 0\n')
def add_text(self, s, col=None, cdata=False):
return
def set_mode(self, units=None):
#self.file_out.write(' units="'+str(units)+'"')
return
def set_tool(self, number=None):
if (number != None):
self.file_out.write('-LAYER New T'+str(number)+'\n')
self.file_out.write('-LAYER Set T'+str(number)+'\n')
def begin_path(self, col=None):
if (col != None):
if col == 'rapid':
self.file_out.write('-color Red\n')
#self.file_out.write('')
self.file_out.write('-linetype set dashed\n')
self.file_out.write('\n')
else:
self.file_out.write('-color Green\n')
#self.file_out.write('')
self.file_out.write('-linetype set continuous\n')
self.file_out.write('\n')
else : self.file_out.write('\n')
def end_path(self):
self.file_out.write('\n')
def add_line(self, x=None, y=None, z=None, a=None, b=None, c=None):
if (x == None and y == None and z == None and a == None and b == None and c == None) : return
#self.file_out.write('line %s,%s %s,%s' %(self.currentx,self.currenty,x,y))
if (x == None) : x = self.currentx
if (y == None) : y = self.currenty
if (z == None) : z = self.currentz
self.file_out.write('line %s,%s,%s %s,%s,%s\n' %(self.currentx,self.currenty,self.currentz,x,y,z))
self.currentx = x
self.currenty = y
self.currentz = z
def add_arc(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None, d=None):
if (x == None and y == None and z == None and i == None and j == None and k == None and r == None and d == None) : return
z = self.currentz
if (x == None) : x = self.currentx
if (y == None) : y = self.currenty
if (z == None) : z = self.currentz
if (d == 1):
self.file_out.write('arc %s,%s,%s\n' %(self.currentx,self.currenty,self.currentz))
self.file_out.write('c\n')
self.file_out.write('%s,%s,%s\n' %(self.currentx+i,self.currenty+j,self.currentz))
self.file_out.write('%s,%s,%s' %(x,y,z))
else:
self.file_out.write('arc %s,%s,%s\n' %(x,y,z))
self.file_out.write('c\n')
self.file_out.write('%s,%s,%s\n' %(self.currentx+i,self.currenty+j,self.currentz))
self.file_out.write('%s,%s,%s' %(self.currentx,self.currenty,self.currentz))
self.currentx = x
self.currenty = y
self.currentz = z
def incremental(self):
self.absolute_flag = False
def absolute(self):
self.absolute_flag = True

View File

@@ -0,0 +1,275 @@
# Preliminary backplot support for autocad clone applications
# This code modified from iso_read.py and emc2_read.py distriuted with HeeksCAD as of Sep 2010
# Dan Falck 2011/01/06
#
""" use this script to backplot nc files to *.scr file for autocad,bricscad,
draftsight,progecad,ares commander, etc....
usage: python cad_read.py temp.nc temp.scr
"""
import cad_iso_read as iso
import sys
# Override some iso parser methods to interpret arc centers as relative to origin, not relative to start of arc.
#def write_layer(name,number):
#FILE.write('-LAYER New %s%s \n' %(name,number))
#FILE.write('-LAYER Set %s%s \n' %(name,number))
class CAD_backplot(iso.Parser):
def __init__(self):
iso.Parser.__init__(self)
def Parse(self, name, oname=None):
self.files_open(name,oname)
#self.begin_ncblock()
#self.begin_path(None)
#self.add_line(z=500)
#self.end_path()
#self.end_ncblock()
path_col = None
f = None
arc = 0
# Storage for tool position history of last block processed to properly convert absolute arc centers
oldx = -1.0
oldy = 0.0
oldz = 0.0
movelist = []
while (self.readline()):
# self.readline returns false if the line is empty - the parsing stops if the line is empty.
a = None
b = None
c = None
#f = None
i = None
j = None
k = None
p = None
q = None
r = None
s = None
x = None
y = None
z = None
iout = None
jout = None
kout = None
tool = 0
#self.begin_ncblock()
move = False
#arc = 0
#path_col = None
drill = False
no_move = False
words = self.pattern_main.findall(self.line)
for word in words:
col = None
cdata = False
if (word[0] == 'A' or word[0] == 'a'):
col = "axis"
a = eval(word[1:])
move = True
elif (word[0] == 'B' or word[0] == 'b'):
col = "axis"
b = eval(word[1:])
move = True
elif (word[0] == 'C' or word[0] == 'c'):
col = "axis"
c = eval(word[1:])
move = True
elif (word[0] == 'F' or word[0] == 'f'):
col = "axis"
f = eval(word[1:])
move = True
elif (word == 'G0' or word == 'G00' or word == 'g0' or word == 'g00'):
##FILE.write('-color Magenta\n')
path_col = "rapid"
col = "rapid"
arc = 0
elif (word == 'G1' or word == 'G01' or word == 'g1' or word == 'g01'):
##FILE.write('-color Green\n')
path_col = "feed"
col = "feed"
arc = 0
elif (word == 'G2' or word == 'G02' or word == 'g2' or word == 'g02' or word == 'G12' or word == 'g12'):
##FILE.write('-color Green\n')
path_col = "feed"
col = "feed"
arc = -1
elif (word == 'G3' or word == 'G03' or word == 'g3' or word == 'g03' or word == 'G13' or word == 'g13'):
##FILE.write('-color Green\n')
path_col = "feed"
col = "feed"
arc = +1
elif (word == 'G10' or word == 'g10'):
no_move = True
elif (word == 'L1' or word == 'l1'):
no_move = True
elif (word == 'G20' or word == 'G70'):
col = "prep"
self.set_mode(units=25.4)
elif (word == 'G21' or word == 'G71'):
col = "prep"
self.set_mode(units=1.0)
# Note: Anilam has very non standard params for drill cycles. Not Yet implemented!
elif (word == 'G81' or word == 'g81'):
drill = True
no_move = True
path_col = "feed"
col = "feed"
elif (word == 'G82' or word == 'g82'):
drill = True;
no_move = True
path_col = "feed"
col = "feed"
elif (word == 'G83' or word == 'g83'):
drill = True
no_move = True
path_col = "feed"
col = "feed"
elif (word[0] == 'G') : col = "prep"
elif (word[0] == 'I' or word[0] == 'i'):
col = "axis"
i = eval(word[1:])
move = True
elif (word[0] == 'J' or word[0] == 'j'):
col = "axis"
j = eval(word[1:])
move = True
elif (word[0] == 'K' or word[0] == 'k'):
col = "axis"
k = eval(word[1:])
move = True
elif (word[0] == 'M') : col = "misc"
elif (word[0] == 'N') : col = "blocknum"
elif (word[0] == 'O') : col = "program"
elif (word[0] == 'P' or word[0] == 'p'):
col = "axis"
p = eval(word[1:])
move = True
elif (word[0] == 'Q' or word[0] == 'q'):
col = "axis"
q = eval(word[1:])
move = True
elif (word[0] == 'R' or word[0] == 'r'):
col = "axis"
r = eval(word[1:])
move = True
elif (word[0] == 'S' or word[0] == 's'):
col = "axis"
s = eval(word[1:])
move = True
elif (word[0] == 'T') :
col = "tool"
self.set_tool( eval(word[1:]) )
tool = eval(word[1:])
elif (word[0] == 'X' or word[0] == 'x'):
col = "axis"
x = eval(word[1:])
move = True
elif (word[0] == 'Y' or word[0] == 'y'):
col = "axis"
y = eval(word[1:])
move = True
elif (word[0] == 'Z' or word[0] == 'z'):
col = "axis"
z = eval(word[1:])
move = True
elif (word[0] == '(') : (col, cdata) = ("comment", True)
elif (word[0] == '!') : (col, cdata) = ("comment", True)
elif (word[0] == ';') : (col, cdata) = ("comment", True)
elif (word[0] == '#') : col = "variable"
elif (word[0] == ':') : col = "blocknum"
elif (ord(word[0]) <= 32) : cdata = True
#self.add_text(word, col, cdata)
if (drill):
self.begin_path("rapid")
self.add_line(x, y, r)
self.end_path()
self.begin_path("feed")
self.add_line(x, y, z)
self.end_path()
self.begin_path("feed")
self.add_line(x, y, r)
self.end_path()
#elif (tool):
#write_layer('T',tool)
else:
if (move and not no_move):
self.begin_path(path_col)
#use absolute arc centers for IJK params.
# Subtract old XYZ off to get relative centers as expected:
#if path_col == 'rapid':
#FILE.write('-color Red\n')
#else:
#FILE.write('-color Green\n')
if (arc) :
z = oldz
if (x != None) and (oldx != None) and (i != None): iout = i
if (y != None) and (oldy != None) and (j != None): jout = j
if (z != None) and (oldz != None) and (k != None): kout = k
self.add_arc(x, y, z, iout, jout, kout, r, arc)
#if (arc == -1):
##FILE.write('arc %s,%s,%s\n' %(x,y,z))
##FILE.write('c\n')
##FILE.write('%s,%s,%s\n' %(oldx+i,oldy+j,oldz))
##FILE.write('%s,%s,%s\n' %(oldx,oldy,z))
#else:
##FILE.write('arc %s,%s,%s\n' %(oldx,oldy,z))
##FILE.write('c\n')
##FILE.write('%s,%s,%s\n' %(oldx+i,oldy+j,oldz))
##FILE.write('%s,%s,%s\n' %(x,y,z))
else:
self.add_line(x, y, z, a, b, c)
if (x == None) : x = oldx
if (y == None) : y = oldy
if (z == None) : z = oldz
scr_line = ('line %s,%s,%s %s,%s,%s \n' %(oldx,oldy,oldz,x,y,z))
#print scr_line
##FILE.write(scr_line)
self.end_path()
if (x != None) : oldx = x
if (y != None) : oldy = y
if (z != None) : oldz = z
#oldx = x
#oldy = y
#oldz = z
self.end_ncblock()
self.files_close()
#FILE.write('\n')
#FILE.close()
################################################################################
if __name__ == '__main__':
parser = CAD_backplot()
if len(sys.argv)>2:
parser.Parse(sys.argv[1],sys.argv[2])
else:
parser.Parse(sys.argv[1])

View File

@@ -0,0 +1,168 @@
################################################################################
# centroid1.py
#
# Post Processor for the centroid M40 machine
#
#
# Dan Falck, 7th March 2010
import nc
import iso_modal
import math
import datetime
now = datetime.datetime.now()
################################################################################
class Creator(iso_modal.Creator):
def __init__(self):
iso_modal.Creator.__init__(self)
self.useCrc = True
self.useCrcCenterline = True
self.absolute_flag = True
self.prev_g91 = ''
self.safe_z =None
def SPINDLE(self, format, speed): return(self.SPACE() + 'S' + (format % speed))
################################################################################
#cutter comp
#def crc_on(self):
# self.useCrc = True
# self.useCrcCenterline = True
#def crc_off(self):
# self.useCrc = False
################################################################################
# general
def comment(self, text):
self.write(';' + text +'\n')
def write_blocknum(self):
pass
################################################################################
# settings for absolute or incremental mode
def absolute(self):
self.write(self.ABSOLUTE()+'\n')
self.absolute_flag = True
def incremental(self):
self.write(self.INCREMENTAL()+'\n')
self.absolute_flag = False
################################################################################
# APT style INSERT- insert anything into program
def insert(self, text):
self.write((text + '\n'))
################################################################################
# program begin and end
def program_begin(self, id, name=''):
self.write(';time:'+str(now)+'\n')
self.write('G17 G20 G80 G40 G90\n')
def program_end(self):
self.write('M05\n')
self.write('M25\n')
self.write('G00 X-1.0 Y1.0\n')
self.write('G17 G80 G40 G90\n')
self.write('M99\n')
def program_stop(self, optional=False):
self.write_blocknum()
if (optional) :
self.write(self.STOP_OPTIONAL() + '\n')
else :
self.write('M05\n')
self.write('M25\n')
self.write(self.STOP() + '\n')
self.prev_g0123 = ''
################################################################################
# coordinate system ie G54-G59
def workplane(self, id):
self.write('M25\n')
if ((id >= 1) and (id <= 6)):
self.g_list.append(self.WORKPLANE() % (id + self.WORKPLANE_BASE()))
if ((id >= 7) and (id <= 9)):
self.g_list.append(((self.WORKPLANE() % (6 + self.WORKPLANE_BASE())) + ('.%i' % (id - 6))))
self.prev_g0123 = ''
################################################################################
# clearance plane
def clearanceplane(self,z=None):
self.safe_z = z
################################################################################
# return to home
def rapid_home(self, x=None, y=None, z=None, a=None, b=None, c=None):
"""Rapid relative to home position"""
self.write('M05\n')
self.write('M25\n')
self.write(self.RAPID())
self.write(self.X() + (self.fmt % x))
self.write(self.Y() + (self.fmt % y))
self.write('\n')
################################################################################
# tool info
def tool_change(self, id):
self.write_blocknum()
self.write((self.TOOL() % id) + '\n')
self.t = id
self.write('M25\n')
if self.safe_z == None:
self.write('G43 H'+ str(id) + ' Z')
self.write('1.0')
self.write ('\n')
else:
self.write('G43 H'+ str(id) + ' Z')
self.write(str(self.safe_z))
self.write ('\n')
def tool_defn(self, id, name='', params=None):
#self.write('G43 \n')
pass
def write_spindle(self):
pass
def spindle(self, s, clockwise):
if s < 0:
clockwise = not clockwise
s = abs(s)
self.s = self.SPINDLE(self.FORMAT_ANG(), s)
if clockwise:
#self.s = self.SPINDLE_CW() + self.s
self.s = self.SPINDLE_CW()
self.write(self.s + '\n')
self.write('G04 P2.0 \n')
else:
self.s = self.SPINDLE_CCW() + self.s
def end_canned_cycle(self):
self.write_blocknum()
self.write(self.SPACE() + self.END_CANNED_CYCLE() + '\n')
self.prev_drill = ''
self.prev_g0123 = ''
self.prev_z = ''
self.prev_f = ''
self.prev_retract = ''
self.write('M05\n')
self.write('M25\n')
self.write('G00 X-1.0 Y1.0\n')
nc.creator = Creator()

View File

@@ -0,0 +1,8 @@
import iso_read as iso
import sys
# just use the iso reader
class Parser(iso.Parser):
def __init__(self, writer):
iso.Parser.__init__(self, writer)

View File

@@ -0,0 +1,34 @@
def tool_defn(self, id, params):
self.write('(TOOL/')
type = params['type']
if type == 0:#eDrill = 0,
#;TOOL/DRILL, Diameter, Point Angle, Height
self.write('DRILL, ' + str(params['diameter']))
self.write(', ' + str(params['cutting edge angle'] * 2.0))
self.write(', ' + str(params['cutting edge height']))
elif type == 1:#eCentreDrill,
#;TOOL/CDRILL, D1, A1, L, D2, A2, H (see Fig. below)
self.write('CDRILL, ' + str(params['flat radius'] * 2))
self.write(', ' + str(params['cutting edge angle']))
self.write(', ' + str(params['flat radius'] * 2))
self.write(', ' + str(params['diameter']))
self.write(', ' + str(params['cutting edge angle'] * 2.0))
self.write(', ' + str(params['cutting edge height']))
elif type == 2 or type == 3 or type == 4:#eSlotCutter,#eEndmill,#eBallEndMill,
#TOOL/MILL, Diameter, Corner radius, Height, Taper Angle
self.write('MILL, ' + str(params['diameter']))
self.write(', ' + str(params['corner radius']))
self.write(', ' + str(params['cutting edge height']))
self.write(', ' + str(params['cutting edge angle']))
elif type == 5 or type == 6:#eChamfer,#eEngravingTool,
#;TOOL/CHAMFER, Diameter, Point Angle, Height
#;TOOL/CHAMFER, Diameter, Point Angle, Height, Chamfer Length
self.write('CHAMFER, ' + str(params['diameter']))
self.write(', ' + str(params['cutting edge angle']))
self.write(', ' + str(params['cutting edge height']))
else:#eUndefinedToolType
pass
self.write(')\n')
# to do
#;TOOL/CRMILL, Diameter1, Diameter2, Radius, Height, Length

View File

@@ -0,0 +1,72 @@
################################################################################
# drag knife.py
#
# NC code creator for attaching Z coordinates to a surface
#
# Dan Heeks 26th April 2012
import recreator
dragging = False
from kurve_funcs import cut_curve as cut_curve
import nc
import area
################################################################################
class Creator(recreator.Redirector):
def __init__(self, original, drag_distance):
recreator.Redirector.__init__(self, original)
self.drag_distance = drag_distance
self.path = None
def cut_path(self):
if self.path == None: return
print self.drag_distance
self.path.OffsetForward(self.drag_distance, False)
nc.creator = nc.creator.original
if self.path.getNumVertices() > 0:
v = self.path.FirstVertex()
nc.creator.feed(v.p.x, v.p.y)
cut_curve(self.path)
nc.creator = self
self.path = area.Curve()
def feed(self, x=None, y=None, z=None, a=None, b=None, c=None):
px = self.x
py = self.y
pz = self.z
recreator.Redirector.feed(self, x, y, z, a, b, c)
if self.x == None or self.y == None or self.z == None:
return
if px == self.x and py == self.y:
return
# add a line to the path
if self.path == None: self.path = area.Curve()
self.path.append(area.Point(self.x, self.y))
def arc(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None, ccw = True):
recreator.Redirector.arc(self, x, y, z, i, j, k, r, ccw)
# add an arc to the path
if self.path == None: self.path = area.Curve()
self.path.append(area.Vertex(1 if ccw else -1, area.Point(self.x, self.y), area.Point(i, j)))
def drag_begin(drag_distance):
global dragging
if dragging == True:
drag_end()
nc.creator = Creator(nc.creator, drag_distance)
dragging = True
def drag_end():
global dragging
nc.creator.cut_path()
nc.creator = nc.creator.original
attached = False

View File

@@ -0,0 +1,38 @@
import nc
import iso
import math
import datetime
import time
from format import Format
now = datetime.datetime.now()
class Creator(iso.Creator):
def __init__(self):
iso.Creator.__init__(self)
self.output_tool_definitions = False
self.m_codes_on_their_own_line = True
self.output_g98_and_g99 = False
#self.fmt = Format(dp_wanted = False, add_trailing_zeros = True, add_plus = True)
#def SPACE_STR(self): return ' '
def PROGRAM(self): return None
def RETRACT(self, height): return('R' + (self.fmt.string(height)))
def PECK_DEPTH(self, depth): return('O' + (self.fmt.string(depth)))
def program_begin(self, id, name=''):
self.write('(' + name + ')\n')
def imperial(self):
#self.g_list.append(self.IMPERIAL())
self.fmt.number_of_decimal_places = 4
def metric(self):
#self.g_list.append(self.METRIC())
self.fmt.number_of_decimal_places = 3
def comment(self, text):
pass
nc.creator = Creator()

View File

@@ -0,0 +1,235 @@
import nc
import iso
import math
class Creator(iso.Creator):
def init(self):
iso.Creator.init(self)
def SPACE(self): return('')
def TAP(self): return('G33.1')
def TAP_DEPTH(self, format, depth): return(self.SPACE() + 'K' + (format.string(depth)))
def BORE_FEED_OUT(self): return('G85')
def BORE_SPINDLE_STOP_RAPID_OUT(self): return('G86')
def BORE_DWELL_FEED_OUT(self, format, dwell): return('G89') + self.SPACE() + (format.string(dwell))
def FEEDRATE(self): return((self.SPACE() + ' F'))
def program_begin(self, id, comment):
self.write( ('(' + comment + ')' + '\n') )
############################################################################
## Settings
def imperial(self):
self.write( self.IMPERIAL() + '\t (Imperial Values)\n')
self.fmt.number_of_decimal_places = 4
def metric(self):
self.fmt.number_of_decimal_places = 3
self.write( self.METRIC() + '\t (Metric Values)\n' )
def absolute(self):
self.write( self.ABSOLUTE() + '\t (Absolute Coordinates)\n')
def incremental(self):
self.write( self.INCREMENTAL() + '\t (Incremental Coordinates)\n' )
def polar(self, on=True):
if (on) :
self.write(self.POLAR_ON() + '\t (Polar ON)\n' )
else :
self.write(self.POLAR_OFF() + '\t (Polar OFF)\n' )
def set_plane(self, plane):
if (plane == 0) :
self.write(self.PLANE_XY() + '\t (Select XY Plane)\n')
elif (plane == 1) :
self.write(self.PLANE_XZ() + '\t (Select XZ Plane)\n')
elif (plane == 2) :
self.write(self.PLANE_YZ() + '\t (Select YZ Plane)\n')
def comment(self, text):
self.write((self.COMMENT(text) + '\n'))
# This is the coordinate system we're using. G54->G59, G59.1, G59.2, G59.3
# These are selected by values from 1 to 9 inclusive.
def workplane(self, id):
if ((id >= 1) and (id <= 6)):
self.write( (self.WORKPLANE() % (id + self.WORKPLANE_BASE())) + '\t (Select Relative Coordinate System)\n')
if ((id >= 7) and (id <= 9)):
self.write( ((self.WORKPLANE() % (6 + self.WORKPLANE_BASE())) + ('.%i' % (id - 6))) + '\t (Select Relative Coordinate System)\n')
def report_probe_results(self, x1=None, y1=None, z1=None, x2=None, y2=None, z2=None, x3=None, y3=None, z3=None, x4=None, y4=None, z4=None, x5=None, y5=None, z5=None, x6=None, y6=None, z6=None, xml_file_name=None ):
if (xml_file_name != None):
self.comment('Generate an XML document describing the probed coordinates found');
self.write('(LOGOPEN,')
self.write(xml_file_name)
self.write(')\n')
self.write('(LOG,<POINTS>)\n')
if ((x1 != None) or (y1 != None) or (z1 != None)):
self.write('(LOG,<POINT>)\n')
if (x1 != None):
self.write('#<_value>=[' + x1 + ']\n')
self.write('(LOG,<X>#<_value></X>)\n')
if (y1 != None):
self.write('#<_value>=[' + y1 + ']\n')
self.write('(LOG,<Y>#<_value></Y>)\n')
if (z1 != None):
self.write('#<_value>=[' + z1 + ']\n')
self.write('(LOG,<Z>#<_value></Z>)\n')
if ((x1 != None) or (y1 != None) or (z1 != None)):
self.write('(LOG,</POINT>)\n')
if ((x2 != None) or (y2 != None) or (z2 != None)):
self.write('(LOG,<POINT>)\n')
if (x2 != None):
self.write('#<_value>=[' + x2 + ']\n')
self.write('(LOG,<X>#<_value></X>)\n')
if (y2 != None):
self.write('#<_value>=[' + y2 + ']\n')
self.write('(LOG,<Y>#<_value></Y>)\n')
if (z2 != None):
self.write('#<_value>=[' + z2 + ']\n')
self.write('(LOG,<Z>#<_value></Z>)\n')
if ((x2 != None) or (y2 != None) or (z2 != None)):
self.write('(LOG,</POINT>)\n')
if ((x3 != None) or (y3 != None) or (z3 != None)):
self.write('(LOG,<POINT>)\n')
if (x3 != None):
self.write('#<_value>=[' + x3 + ']\n')
self.write('(LOG,<X>#<_value></X>)\n')
if (y3 != None):
self.write('#<_value>=[' + y3 + ']\n')
self.write('(LOG,<Y>#<_value></Y>)\n')
if (z3 != None):
self.write('#<_value>=[' + z3 + ']\n')
self.write('(LOG,<Z>#<_value></Z>)\n')
if ((x3 != None) or (y3 != None) or (z3 != None)):
self.write('(LOG,</POINT>)\n')
if ((x4 != None) or (y4 != None) or (z4 != None)):
self.write('(LOG,<POINT>)\n')
if (x4 != None):
self.write('#<_value>=[' + x4 + ']\n')
self.write('(LOG,<X>#<_value></X>)\n')
if (y4 != None):
self.write('#<_value>=[' + y4 + ']\n')
self.write('(LOG,<Y>#<_value></Y>)\n')
if (z4 != None):
self.write('#<_value>=[' + z4 + ']\n')
self.write('(LOG,<Z>#<_value></Z>)\n')
if ((x4 != None) or (y4 != None) or (z4 != None)):
self.write('(LOG,</POINT>)\n')
if ((x5 != None) or (y5 != None) or (z5 != None)):
self.write('(LOG,<POINT>)\n')
if (x5 != None):
self.write('#<_value>=[' + x5 + ']\n')
self.write('(LOG,<X>#<_value></X>)\n')
if (y5 != None):
self.write('#<_value>=[' + y5 + ']\n')
self.write('(LOG,<Y>#<_value></Y>)\n')
if (z5 != None):
self.write('#<_value>=[' + z5 + ']\n')
self.write('(LOG,<Z>#<_value></Z>)\n')
if ((x5 != None) or (y5 != None) or (z5 != None)):
self.write('(LOG,</POINT>)\n')
if ((x6 != None) or (y6 != None) or (z6 != None)):
self.write('(LOG,<POINT>)\n')
if (x6 != None):
self.write('#<_value>=[' + x6 + ']\n')
self.write('(LOG,<X>#<_value></X>)\n')
if (y6 != None):
self.write('#<_value>=[' + y6 + ']\n')
self.write('(LOG,<Y>#<_value></Y>)\n')
if (z6 != None):
self.write('#<_value>=[' + z6 + ']\n')
self.write('(LOG,<Z>#<_value></Z>)\n')
if ((x6 != None) or (y6 != None) or (z6 != None)):
self.write('(LOG,</POINT>)\n')
self.write('(LOG,</POINTS>)\n')
if (xml_file_name != None):
self.write('(LOGCLOSE)\n')
def open_log_file(self, xml_file_name=None ):
self.write('(LOGOPEN,')
self.write(xml_file_name)
self.write(')\n')
def close_log_file(self):
self.write('(LOGCLOSE)\n')
def log_coordinate(self, x=None, y=None, z=None):
if ((x != None) or (y != None) or (z != None)):
self.write('(LOG,<POINT>)\n')
if (x != None):
self.write('#<_value>=[' + x + ']\n')
self.write('(LOG,<X>#<_value></X>)\n')
if (y != None):
self.write('#<_value>=[' + y + ']\n')
self.write('(LOG,<Y>#<_value></Y>)\n')
if (z != None):
self.write('#<_value>=[' + z + ']\n')
self.write('(LOG,<Z>#<_value></Z>)\n')
if ((x != None) or (y != None) or (z != None)):
self.write('(LOG,</POINT>)\n')
def log_message(self, message=None ):
self.write('(LOG,' + message + ')\n')
def start_CRC(self, left = True, radius = 0.0):
if self.t == None:
raise "No tool specified for start_CRC()"
if left:
self.write(('G41' + self.SPACE() + 'D%i') % self.t + '\t (start left cutter radius compensation)\n' )
else:
self.write(('G42' + self.SPACE() + 'D%i') % self.t + '\t (start right cutter radius compensation)\n' )
def end_CRC(self):
self.g = 'G40'
self.write_preps()
self.write_misc()
self.write('\t (end cutter radius compensation)\n')
def tool_defn(self, id, name='', params=None):
pass
nc.creator = Creator()

View File

@@ -0,0 +1,39 @@
import nc
import iso_modal
import math
import datetime
import time
now = datetime.datetime.now()
class Creator(iso_modal.Creator):
def __init__(self):
iso_modal.Creator.__init__(self)
self.output_block_numbers = False
self.output_tool_definitions = False
self.output_g43_on_tool_change_line = True
def SPACE(self):
if self.start_of_line == True:
self.start_of_line = False
return ''
else:
return ' '
def PROGRAM(self): return None
def PROGRAM_END(self): return( 'T0' + self.SPACE() + 'M06' + self.SPACE() + 'M02')
############################################################################
## Begin Program
def program_begin(self, id, comment):
if (self.useCrc == False):
self.write( ('(Created with emc2b post processor ' + str(now.strftime("%Y/%m/%d %H:%M")) + ')' + '\n') )
else:
self.write( ('(Created with emc2b Cutter Radius Compensation post processor ' + str(now.strftime("%Y/%m/%d %H:%M")) + ')' + '\n') )
iso_modal.Creator.program_begin(self, id, comment)
nc.creator = Creator()

View File

@@ -0,0 +1,21 @@
################################################################################
# emc2b_crc.py
#
# a class derived from emc2b machine, with Cutter Radius Compensation turned on.
#
# Dan Heeks, 18th Jan 2011
import nc
import emc2b
import math
################################################################################
class Creator(emc2b.Creator):
def __init__(self):
emc2b.Creator.__init__(self)
self.useCrc = True
################################################################################
nc.creator = Creator()

View File

@@ -0,0 +1,85 @@
import nc
import iso_codes
import emc2
class CodesEMC2(iso_codes.Codes):
def SPACE(self): return(' ')
def TAP(self): return('G33.1')
def TAP_DEPTH(self, format, depth): return(self.SPACE() + 'K' + (format % depth))
# This version of COMMENT removes comments from the resultant GCode
#def COMMENT(self,comment): return('')
iso_codes.codes = CodesEMC2()
class CreatorEMC2tap(emc2.CreatorEMC2):
def init(self):
iso.CreatorEMC2.init(self)
# G33.1 tapping with EMC for now
# unsynchronized (chuck) taps NIY (tap_mode = 1)
def tap(self, x=None, y=None, z=None, zretract=None, depth=None, standoff=None, dwell_bottom=None, pitch=None, stoppos=None, spin_in=None, spin_out=None, tap_mode=None, direction=None):
# mystery parameters:
# zretract=None, dwell_bottom=None,pitch=None, stoppos=None, spin_in=None, spin_out=None):
# I dont see how to map these to EMC Gcode
if (standoff == None):
# This is a bad thing. All the drilling cycles need a retraction (and starting) height.
return
if (z == None):
return # We need a Z value as well. This input parameter represents the top of the hole
if (pitch == None):
return # We need a pitch value.
if (direction == None):
return # We need a direction value.
if (tap_mode != 0):
self.comment('only rigid tapping currently supported')
return
self.write_preps()
self.write_blocknum()
self.write_spindle()
self.write('\n')
# rapid to starting point; z first, then x,y iff given
# Set the retraction point to the 'standoff' distance above the starting z height.
retract_height = z + standoff
# unsure if this is needed:
if self.z != retract_height:
self.rapid(z = retract_height)
# then continue to x,y if given
if (x != None) or (y != None):
self.write_blocknum()
self.write(iso_codes.codes.RAPID() )
if (x != None):
self.write(iso_codes.codes.X() + (self.fmt % x))
self.x = x
if (y != None):
self.write(iso_codes.codes.Y() + (self.fmt % y))
self.y = y
self.write('\n')
self.write_blocknum()
self.write( iso_codes.codes.TAP() )
self.write( iso_codes.codes.TAP_DEPTH(self.ffmt,pitch) + iso_codes.codes.SPACE() )
self.write(iso_codes.codes.Z() + (self.fmt % (z - depth))) # This is the 'z' value for the bottom of the tap.
self.write_misc()
self.write('\n')
self.z = retract_height # this cycle returns to the start position, so remember that as z value
nc.creator = CreatorEMC2tap()

View File

@@ -0,0 +1,105 @@
import math
class Format:
def __init__(self, number_of_decimal_places = 3, add_leading_zeros = 1, add_trailing_zeros = False, dp_wanted = True, add_plus = False, no_minus = False, round_down = False):
self.number_of_decimal_places = number_of_decimal_places
self.add_leading_zeros = add_leading_zeros # fill the start of the number with zeros, so there are at least this number of digits before the decimal point
self.add_trailing_zeros = add_trailing_zeros # fill the end of the number with zeros, as defined by "number_of_decimal_places"
self.dp_wanted = dp_wanted
self.add_plus = add_plus
self.no_minus = no_minus
self.round_down = round_down
def string(self, number):
if number == None:
return 'None'
f = float(number) * math.pow(10, self.number_of_decimal_places)
s = str(f)
if self.round_down == False:
if f < 0: f = f - .5
else: f = f + .5
s = str(number)
if math.fabs(f) < 1.0:
s = '0'
minus = False
if s[0] == '-':
minus = True
if self.no_minus:
s = s[1:]
dot = s.find('.')
if dot == -1:
before_dp = s
after_dp = ''
else:
before_dp = s[0:dot]
after_dp = s[dot + 1: dot + 1 + self.number_of_decimal_places]
before_dp = before_dp.zfill(self.add_leading_zeros)
if self.add_trailing_zeros:
for i in range(0, self.number_of_decimal_places - len(after_dp)):
after_dp += '0'
else:
after_dp = after_dp.rstrip('0')
s = ''
if minus == False:
if self.add_plus == True:
s += '+'
s += before_dp
if len(after_dp):
if self.dp_wanted: s += '.'
s += after_dp
return s
class Address:
def __init__(self, text, fmt = Format(), modal = True):
self.text = text
self.fmt = fmt
self.modal = modal
self.str = None
self.previous = None
def set(self, number):
self.str = self.text + self.fmt.string(number)
def write(self, writer):
if self.str == None: return ''
if self.modal:
if self.str != self.previous:
writer.write(self.str)
self.previous = self.str
else:
writer.write(self.str)
self.str = None
class AddressPlusMinus(Address):
def __init__(self, text, fmt = Format(), modal = True):
Address.__init__(self, text, fmt, modal)
self.str2 = None
self.previous2 = None
def set(self, number, text_plus, text_minus):
Address.set(self, number)
if float(number) > 0.0:
self.str2 = text_plus
else:
self.str2 = text_minus
def write(self, writer):
Address.write(self, writer)
if self.str2 == None: return ''
if self.modal:
if self.str2 != self.previous2:
writer.write(writer.SPACE())
writer.write(self.str2)
self.previous2 = self.str2
else:
writer.write(writer.SPACE())
writer.write(self.str2)
self.str2 = None

View File

@@ -0,0 +1,18 @@
import nc
import emc2
class Creator(emc2.Creator):
def init(self):
emc2.Creator.init(self)
def program_begin(self, id, comment):
self.write( ('(' + comment + ')' + '\n') )
def tool_defn(self, id, name='', params=None):
pass
def spindle(self, s, clockwise):
pass
nc.creator = Creator()

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,152 @@
################################################################################
# heiden_read.py
#
# Simple ISO NC code parsing
#
import nc_read as nc
import re
import sys
import math
################################################################################
class Parser(nc.Parser):
def __init__(self, writer):
nc.Parser.__init__(self, writer)
self.pattern_main = re.compile('([(!;].*'
'|\s+|[a-zA-Z0-9_:](?:[+-])?\d*(?:\.\d*)?'
'|\w\#\d+|\(.*?\)'
'|\#\d+\=(?:[+-])?\d*(?:\.\d*)? )')
self.pattern_tool = re.compile('([(!;].*'
'|\S+'
'|\s+|\d)')
self.oldx = 0
self.oldy = 0
self.oldz = 150
self.olda = 0
self.oldb = 0
self.oldc = 0
def ParseTool(self, word):
# parse the first numeric parameter that comes after 'tool call'
try:
if (word[0:] == 'TOOL'):
self.col = "tool"
self.move = False
elif (word[0:] == 'CALL'):
self.col = "tool call"
self.move = False
elif self.col == 'tool call':
if not self.t > 0:
if word[0] >= '0' and word[0] <= '9':
self.t = eval(word[0:])
self.col = 'tool no'
except:
pass
def change_tool(self, t):
pass
def ParseWord(self, word):
try:
if (word[0] == 'A' or word[0] == 'a'):
self.col = "axis"
self.a = eval(word[1:])
self.move = True
elif (word[0] == 'B' or word[0] == 'b'):
self.col = "axis"
self.b = eval(word[1:])
self.move = True
elif (word[0] == 'C' or word[0] == 'c'):
self.col = "axis"
self.c = eval(word[1:])
self.move = True
elif (word[0] == 'F' or word[0] == 'f'):
self.col = "axis"
if word[1:] == 'FMAX':
self.rapid = True
self.path_col = "rapid"
self.col = "rapid"
else:
self.f = eval(word[1:])
self.rapid = False
self.path_col = "feed"
self.col = "feed"
self.move = True
elif (word == 'L' or word == 'l'):
self.arc = 0
self.move = True
elif (word[0] == 'X' or word[0] == 'x'):
self.col = "axis"
self.x = eval(word[1:])
self.move = True
elif (word[0] == 'Y' or word[0] == 'y'):
self.col = "axis"
self.y = eval(word[1:])
self.move = True
elif (word[0] == 'Z' or word[0] == 'z'):
self.col = "axis"
self.z = eval(word[1:])
self.move = True
self.t = eval(word[1:])
except:
pass
def Parsey(self, name):
self.files_open(name)
for_full_machine_sim = True # to do, make derived class to do this
#for_full_machine_sim = False
self.f = None
self.arc = 0
self.rapid = True
while (self.readline()):
self.a = None
self.b = None
self.c = None
self.h = None
self.i = None
self.j = None
self.k = None
self.p = None
self.q = None
self.r = None
self.s = None
self.x = None
self.y = None
self.z = None
self.t = 0
self.move = False
self.no_move = False
words = self.pattern_tool.findall(self.line)
for word in words:
self.ParseTool(word)
if not self.t:
words = self.pattern_main.findall(self.line)
for word in words:
self.ParseWord(word)
if (self.move and not self.no_move):
if (self.arc==0):
self.add_line(self.x, self.y, self.z, self.a, self.b, self.rapid)
else:
self.add_arc(self.x, self.y, self.z, self.i, self.j, self.k, self.r, self.arc)
if self.x != None: self.oldx = self.x
if self.y != None: self.oldy = self.y
if self.z != None: self.oldz = self.z
if self.a != None: self.olda = self.a
if self.b != None: self.oldb = self.b
if self.c != None: self.oldc = self.c
elif (self.t):
self.change_tool(self.t)
self.files_close()

View File

@@ -0,0 +1,24 @@
import nc
import emc2
class Creator(emc2.Creator):
def init(self):
iso.Creator.init(self)
def program_begin(self, id, comment):
self.write( ('(' + comment + ')' + '\n') )
def tool_change(self, id):
self.write_blocknum()
self.write('G53 G00 Z30\n')
self.write_blocknum()
self.write((self.TOOL() % id) + '\n')
self.write_blocknum()
self.write('G01 Z100.000 F800.000\n')
self.write_blocknum()
self.write('M0\n')
self.write_blocknum()
self.write('G01 Z10.000 F300.000\n')
nc.creator = Creator()

View File

@@ -0,0 +1,109 @@
# hpgl2d.py
#
# Copyright (c) 2009, Dan Heeks
# This program is released under the BSD license. See the file COPYING for details.
#
import nc
import math
class Creator(nc.Creator):
def __init__(self):
nc.Creator.__init__(self)
self.x = int(0)
self.y = int(0) # these are in machine units, like 0.01mm or maybe 0.25mm
self.metric() # set self.units_to_mc_units
def imperial(self):
self.units_to_mc_units = 2540 # multiplier from inches to machine units
def metric(self):
self.units_to_mc_units = 100 # multiplier from mm to machine units
def program_begin(self, id, name=''):
self.write('IN;\n')
self.write('VS32,1;\n')
self.write('VS32,2;\n')
self.write('VS32,3;\n')
self.write('VS32,4;\n')
self.write('VS32,5;\n')
self.write('VS32,6;\n')
self.write('VS32,7;\n')
self.write('VS32,8;\n')
self.write('WU0;\n')
self.write('PW0.349,1;\n')
self.write('PW0.349,2;\n')
self.write('PW0.349,3;\n')
self.write('PW0.349,4;\n')
self.write('PW0.349,5;\n')
self.write('PW0.349,6;\n')
self.write('PW0.349,7;\n')
self.write('PW0.349,8;\n')
self.write('SP1;\n')
def program_end(self):
self.write('SP0;\n')
def closest_int(self, f):
if math.fabs(f) < 0.3:
return 0
elif f > 0:
return int(f + 0.5)
else:
return int(f - 0.5)
def get_machine_x_y(self, x=None, y=None):
machine_x = self.x
machine_y = self.y
if x != None:
machine_x = self.closest_int(x * self.units_to_mc_units)
if y != None:
machine_y = self.closest_int(y * self.units_to_mc_units)
return machine_x, machine_y
def rapid(self, x=None, y=None, z=None, a=None, b=None, c=None):
# ignore the z, any rapid will be assumed to be done with the pen up
mx, my = self.get_machine_x_y(x, y)
if mx != self.x or my != self.y:
self.write(('PU%i' % mx) + (' %i;\n' % my))
self.x = mx
self.y = my
def feed(self, x=None, y=None, z=None, a=None, b=None, c=None):
# ignore the z, any feed will be assumed to be done with the pen down
mx, my = self.get_machine_x_y(x, y)
if mx != self.x or my != self.y:
self.write(('PD%i' % mx) + (' %i;\n' % my))
self.x = mx
self.y = my
def arc(self, cw, x=None, y=None, z=None, i=None, j=None, k=None, r=None):
mx, my = self.get_machine_x_y(x, y)
if mx != self.x or my != self.y:
cx = float(self.x) / self.units_to_mc_units + i
cy = float(self.y) / self.units_to_mc_units + j
sdx = -i
sdy = -j
edx = x - cx
edy = y - cy
start_angle = math.atan2(sdy, sdx)
end_angle = math.atan2(edy, edx)
if cw:
if start_angle < end_angle: start_angle += 2 * math.pi
else:
if end_angle < start_angle: end_angle += 2 * math.pi
a = math.fabs(end_angle - start_angle)
if cw: a = -a
mcx, mcy = self.get_machine_x_y(cx, cy)
self.write(('AA%i' % mcx) + (',%i' % mcy) + (',%d;\n' % (a * 180 / math.pi)))
def arc_cw(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None):
self.arc(True, x, y, z, i, j, k, r)
def arc_ccw(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None):
self.arc(False, x, y, z, i, j, k, r)
nc.creator = Creator()

View File

@@ -0,0 +1,90 @@
import num_reader
import sys
import math
class Parser(num_reader.NumReader):
def __init__(self, writer):
num_reader.NumReader.__init__(self, writer)
self.i = 0
self.j = 0
self.x = 0
self.y = 0
self.down_z = 0
self.up_z = 20
self.up = True
self.units_to_mm = 0.01
def ParsePuOrPd(self, up):
self.line_index = self.line_index + 1
x = self.get_number()
if len(x) > 0:
y = self.get_number()
if len(y) > 0:
if up: color = "rapid"
else: color = "feed"
self.add_word(color)
self.writer.begin_path(color)
if up: z = self.up_z
else: z = self.down_z
if self.up != up:
self.writer.add_line(self.x * self.units_to_mm, self.y * self.units_to_mm, z)
self.writer.add_line(int(x) * self.units_to_mm, int(y) * self.units_to_mm, z)
self.writer.end_path()
self.up = up
self.x = int(x)
self.y = int(y)
def ParseAA(self):
self.line_index = self.line_index + 1
cx = self.get_number()
if len(cx) > 0:
cy = self.get_number()
if len(cy) > 0:
a = self.get_number()
if len(a) > 0:
self.add_word("feed")
self.writer.begin_path("feed")
z = self.down_z
if self.up:
self.writer.add_line(self.x * self.units_to_mm, self.y * self.units_to_mm, z)
sdx = self.x - int(cx)
sdy = self.y - int(cy)
start_angle = math.atan2(sdy, sdx)
end_angle = start_angle + int(a) * math.pi/180
radius = math.sqrt(sdx*sdx + sdy*sdy)
ex = int(cx) + radius * math.cos(end_angle)
ey = int(cy) + radius * math.sin(end_angle)
if int(a) > 0: d = 1
else: d = -1
self.writer.add_arc(ex * self.units_to_mm, ey * self.units_to_mm, 0.0, i = int(-sdx) * self.units_to_mm, j = int(-sdy) * self.units_to_mm, d = d)
self.writer.end_path()
self.up = False
self.x = int(ex)
self.y = int(ey)
def ParseFromFirstLetter(self, c):
if c == 'P':
self.line_index = self.line_index + 1
if self.line_index < self.line_length:
c1 = self.line[self.line_index]
self.parse_word += c1
if c1 == 'U': # PU
self.ParsePuOrPd(True)
elif c1 == 'D': # PD
self.ParsePuOrPd(False)
elif c == 'A':
self.line_index = self.line_index + 1
if self.line_index < self.line_length:
c1 = self.line[self.line_index]
self.parse_word += c1
if c1 == 'A': # AA, arc absolute
self.ParseAA()

View File

@@ -0,0 +1,22 @@
# hpgl2dv.py
#
# Copyright (c) 2009, Dan Heeks
# This program is released under the BSD license. See the file COPYING for details.
#
# This is the same as the hpgl2d machine, but uses units of 0.25mm instead of 0.01mm
import nc
import hpgl2d
class Creator(hpgl2d.Creator):
def init(self):
hpgl2d.Creator.init(self)
def imperial(self):
self.units_to_mc_units = 101.6 # multiplier from inches to machine units
def metric(self):
self.units_to_mc_units = 4 # multiplier from mm to machine units
nc.creator = Creator()

View File

@@ -0,0 +1,9 @@
import hpgl2d_read as hpgl
import sys
# same as hpgl2d, but with 0.25mm units, instead of 0.01mm
class Parser(hpgl.Parser):
def __init__(self, writer):
hpgl.Parser.__init__(self, writer)
self.units_to_mm = 0.25

View File

@@ -0,0 +1,64 @@
# hpgl3d.py
#
# Copyright (c) 2009, Dan Heeks
# This program is released under the BSD license. See the file COPYING for details.
#
import nc
import hpgl2d
import math
class Creator(hpgl2d.Creator):
def __init__(self):
hpgl2d.Creator.__init__(self)
self.z = int(0)
self.metric() # set self.units_to_mc_units
self.doing_rapid = True
def program_begin(self, id, name=''):
self.write(';;^IN;!MC0;\n')
self.write('V50.0;^PR;Z0,0,10500;^PA;\n')
self.write('!RC15;\n')
self.write('!MC1;\n')
def program_end(self):
self.write('!VZ50.0;!ZM0;\n')
self.write('!MC0;^IN;\n')
def get_machine_xyz(self, x=None, y=None, z=None):
machine_x = self.x
machine_y = self.y
machine_z = self.z
if x != None:
machine_x = self.closest_int(x * self.units_to_mc_units)
if y != None:
machine_y = self.closest_int(y * self.units_to_mc_units)
if z != None:
machine_z = self.closest_int(z * self.units_to_mc_units)
return machine_x, machine_y, machine_z
def rapid(self, x=None, y=None, z=None, a=None, b=None, c=None):
# do a rapid move.
# for now, do all rapid moves at V50 ( 50 mm/s )
mx, my, mz = self.get_machine_xyz(x, y, z)
if mx != self.x or my != self.y or mz != self.z:
if self.doing_rapid == False: self.write('V50.0;')
self.write(('Z%i' % mx) + (',%i' % my) + (',%i;\n' % mz))
self.x = mx
self.y = my
self.z = mz
self.doing_rapid = True
def feed(self, x=None, y=None, z=None, a=None, b=None, c=None):
# do a feed move.
# for now, do all feed moves at V10 ( 10 mm/s )
mx, my, mz = self.get_machine_xyz(x, y, z)
if mx != self.x or my != self.y or mz != self.z:
if self.doing_rapid == True: self.write('V10.0;')
self.write(('Z%i' % mx) + (',%i' % my) + (',%i;\n' % mz))
self.x = mx
self.y = my
self.z = mz
self.doing_rapid = False
nc.creator = Creator()

View File

@@ -0,0 +1,45 @@
import num_reader
import sys
import math
class Parser(num_reader.NumReader):
def __init__(self, writer):
num_reader.NumReader.__init__(self, writer)
self.x = 0
self.y = 0
self.z = 10000
self.f = 0
self.units_to_mm = 0.01
def ParseV(self):
self.line_index = self.line_index + 1
f = self.get_number()
if len(f) > 0:
self.f = float(f)
self.add_word("prep")
def ParseZ(self):
self.line_index = self.line_index + 1
x = self.get_number()
if len(x) > 0:
y = self.get_number()
if len(y) > 0:
z = self.get_number()
if len(z) > 0:
if self.f > 40: color = "rapid"
else: color = "feed"
self.add_word(color)
self.writer.begin_path(color)
self.writer.add_line(int(x) * self.units_to_mm, int(y) * self.units_to_mm, int(z) * self.units_to_mm)
self.writer.end_path()
self.x = int(x)
self.y = int(y)
self.z = int(z)
def ParseFromFirstLetter(self, c):
if c == 'Z':
self.ParseZ()
elif c == 'V':
self.ParseV()

View File

@@ -0,0 +1,130 @@
import tempfile
class HxmlWriter:
def __init__(self):
self.file_out = open(tempfile.gettempdir()+'/backplot.xml', 'w')
self.file_out.write('<?xml version="1.0" ?>\n')
self.file_out.write('<nccode>\n')
self.t = None
self.oldx = None
self.oldy = None
self.oldz = None
def __del__(self):
self.file_out.write('</nccode>\n')
self.file_out.close()
def write(self, s):
self.file_out.write(s)
############################################
def begin_ncblock(self):
self.file_out.write('\t<ncblock>\n')
def end_ncblock(self):
self.file_out.write('\t</ncblock>\n')
def add_text(self, s, col, cdata):
s.replace('&', '&amp;')
s.replace('"', '&quot;')
s.replace('<', '&lt;')
s.replace('>', '&gt;')
if (cdata) : (cd1, cd2) = ('<![CDATA[', ']]>')
else : (cd1, cd2) = ('', '')
if (col != None) : self.file_out.write('\t\t<text col="'+col+'">'+cd1+s+cd2+'</text>\n')
else : self.file_out.write('\t\t<text>'+cd1+s+cd2+'</text>\n')
def set_mode(self, units):
self.file_out.write('\t\t<mode')
if (units != None) : self.file_out.write(' units="'+str(units)+'"')
self.file_out.write(' />\n')
def metric(self):
self.set_mode(units = 1.0)
def imperial(self):
self.set_mode(units = 25.4)
def begin_path(self, col):
if (col != None) : self.file_out.write('\t\t<path col="'+col+'">\n')
else : self.file_out.write('\t\t<path>\n')
def end_path(self):
self.file_out.write('\t\t</path>\n')
def rapid(self, x=None, y=None, z=None, a=None, b=None, c=None):
self.begin_path("rapid")
self.add_line(x, y, z, a, b, c)
self.end_path()
def feed(self, x=None, y=None, z=None, a=None, b=None, c=None):
self.begin_path("feed")
self.add_line(x, y, z, a, b, c)
self.end_path()
def arc_cw(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None):
self.begin_path("feed")
self.add_arc(x, y, z, i, j, k, r, -1)
self.end_path()
def arc_ccw(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None):
self.begin_path("feed")
self.add_arc(x, y, z, i, j, k, r, 1)
self.end_path()
def tool_change(self, id):
self.file_out.write('\t\t<tool')
if (id != None) :
self.file_out.write(' number="'+str(id)+'"')
self.file_out.write(' />\n')
self.t = id
def current_tool(self):
return self.t
def spindle(self, s, clockwise):
pass
def feedrate(self, f):
pass
def add_line(self, x, y, z, a = None, b = None, c = None):
self.file_out.write('\t\t\t<line')
if (x != None) :
self.file_out.write(' x="%.6f"' % x)
if (y != None) :
self.file_out.write(' y="%.6f"' % y)
if (z != None) :
self.file_out.write(' z="%.6f"' % z)
if (a != None) : self.file_out.write(' a="%.6f"' % a)
if (b != None) : self.file_out.write(' b="%.6f"' % b)
if (c != None) : self.file_out.write(' c="%.6f"' % c)
self.file_out.write(' />\n')
if x != None: self.oldx = x
if y != None: self.oldy = y
if z != None: self.oldz = z
def add_arc(self, x, y, z, i, j, k, r = None, d = None):
self.file_out.write('\t\t\t<arc')
if (x != None) :
self.file_out.write(' x="%.6f"' % x)
if (y != None) :
self.file_out.write(' y="%.6f"' % y)
if (z != None) :
self.file_out.write(' z="%.6f"' % z)
if (i != None):
if self.oldx == None: print 'arc move "i" without x set!'
else: self.file_out.write(' i="%.6f"' % (i - self.oldx))
if (j != None):
if self.oldy == None: print 'arc move "j" without y set!'
else: self.file_out.write(' j="%.6f"' % (j - self.oldy))
if (k != None):
if self.oldz == None: print 'arc move "k" without z set!'
else: self.file_out.write(' k="%.6f"' % (k - self.oldz))
if (r != None) : self.file_out.write(' r="%.6f"' % r)
if (d != None) : self.file_out.write(' d="%i"' % d)
self.file_out.write(' />\n')
if x != None: self.oldx = x
if y != None: self.oldy = y
if z != None: self.oldz = z

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
class Codes():
pass
codes = Codes()

View File

@@ -0,0 +1,21 @@
################################################################################
# iso_crc.py
#
# a class derived from iso machine, with Cutter Radius Compensation turned on.
#
# Dan Heeks, 4th May 2010
import nc
import iso
import math
################################################################################
class Creator(iso.Creator):
def __init__(self):
iso.Creator.__init__(self)
self.useCrc = True
################################################################################
nc.creator = Creator()

View File

@@ -0,0 +1,22 @@
################################################################################
# iso_modal.py
#
# a class derived from iso machine, but with XYZF G1, G2 etc modal to reduce the size of the file.
#
# Dan Heeks, 4th May 2010
import nc
import iso
import math
################################################################################
class Creator(iso.Creator):
def __init__(self):
iso.Creator.__init__(self)
self.f_modal = True
self.g0123_modal = True
self.drill_modal = True
################################################################################
nc.creator = Creator()

View File

@@ -0,0 +1,164 @@
################################################################################
# iso_read.py
#
# Simple ISO NC code parsing
#
# Hirutso Enni, 2009-01-13
import nc_read as nc
import re
import sys
################################################################################
class Parser(nc.Parser):
def __init__(self, writer):
nc.Parser.__init__(self, writer)
self.pattern_main = re.compile('([(!;].*|\s+|[a-zA-Z0-9_:](?:[+-])?\d*(?:\.\d*)?|\w\#\d+|\(.*?\)|\#\d+\=(?:[+-])?\d*(?:\.\d*)?)')
self.arc_centre_absolute = False
self.arc_centre_positive = False
self.oldx = None
self.oldy = None
self.oldz = None
#if ( or ! or ; at least one space or a letter followed by some character or not followed by a +/- followed by decimal, with a possible decimal point
# followed by a possible deimcal, or a letter followed by # with a decimal . deimcal
# add your character here > [(!;] for comments char
# then look for the 'comment' function towards the end of the file and add another elif
def ParseWord(self, word):
word == word.upper()
if (word[0] == 'A'):
self.col = "axis"
self.a = eval(word[1:])
self.move = True
elif (word[0] == 'B'):
self.col = "axis"
self.b = eval(word[1:])
self.move = True
elif (word[0] == 'C'):
self.col = "axis"
self.c = eval(word[1:])
self.move = True
elif (word[0] == 'F'):
self.col = "axis"
self.writer.feedrate(word[1:])
elif (word[0] == 'H'):
self.col = "axis"
self.h = eval(word[1:])
self.move = True
elif (word == 'G0' or word == 'G00'):
self.path_col = "rapid"
self.col = "rapid"
self.arc = 0
elif (word == 'G1' or word == 'G01'):
self.path_col = "feed"
self.col = "feed"
self.arc = 0
elif (word == 'G2' or word == 'G02' or word == 'G12'):
self.path_col = "feed"
self.col = "feed"
self.arc = -1
elif (word == 'G3' or word == 'G03' or word == 'G13'):
self.path_col = "feed"
self.col = "feed"
self.arc = +1
elif (word == 'G10'):
self.no_move = True
elif (word == 'G53'):
self.no_move = True
elif (word == 'L1'):
self.no_move = True
elif (word == 'G61.1' or word == 'G61' or word == 'G64'):
self.no_move = True
elif (word == 'G20' or word == 'G70'):
self.col = "prep"
self.writer.imperial()
elif (word == 'G21' or word == 'G71'):
self.col = "prep"
self.writer.metric()
elif (word == 'G43'):
self.height_offset = True
self.move = True
self.path_col = "rapid"
self.col = "rapid"
elif (word == 'G80'):
self.drill_off = True
elif (word == 'G81'):
self.drill = True
self.no_move = True
self.path_col = "feed"
self.col = "feed"
elif (word == 'G82'):
self.drill = True;
self.no_move = True
self.path_col = "feed"
self.col = "feed"
elif (word == 'G83'):
self.drill = True
self.no_move = True
self.path_col = "feed"
self.col = "feed"
elif (word == 'G90'):
self.absolute()
elif (word == 'G91'):
self.incremental()
elif (word == 'G98'):
self.drilling_uses_clearance = True
elif (word == 'G99'):
self.drilling_uses_clearance = False
elif (word[0] == 'G') : col = "prep"
elif (word[0] == 'I'):
self.col = "axis"
self.i = eval(word[1:])
self.move = True
elif (word[0] == 'J'):
self.col = "axis"
self.j = eval(word[1:])
self.move = True
elif (word[0] == 'K'):
self.col = "axis"
self.k = eval(word[1:])
self.move = True
elif (word[0] == 'M') : self.col = "misc"
elif (word[0] == 'N') : self.col = "blocknum"
elif (word[0] == 'O') : self.col = "program"
elif (word[0] == 'P'):
if (self.no_move != True):
self.col = "axis"
self.p = eval(word[1:])
self.move = True
elif (word[0] == 'Q'):
if (self.no_move != True):
self.col = "axis"
self.q = eval(word[1:])
self.move = True
elif (word[0] == 'R'):
self.col = "axis"
self.r = eval(word[1:])
self.move = True
elif (word[0] == 'S'):
self.col = "axis"
self.writer.spindle(word[1:], (float(word[1:]) >= 0.0))
elif (word[0] == 'T') :
self.col = "tool"
self.writer.tool_change( eval(word[1:]) )
elif (word[0] == 'X'):
self.col = "axis"
self.x = eval(word[1:])
self.move = True
elif (word[0] == 'Y'):
self.col = "axis"
self.y = eval(word[1:])
self.move = True
elif (word[0] == 'Z'):
self.col = "axis"
self.z = eval(word[1:])
self.move = True
elif (word[0] == '(') : (self.col, self.cdata) = ("comment", True)
elif (word[0] == '!') : (self.col, self.cdata) = ("comment", True)
elif (word[0] == ';') : (self.col, self.cdata) = ("comment", True)
elif (word[0] == '#') : self.col = "variable"
elif (word[0] == ':') : self.col = "blocknum"
elif (ord(word[0]) <= 32) : self.cdata = True

View File

@@ -0,0 +1,20 @@
import nc
import iso
class Creator(iso.Creator):
def init(self):
iso.Creator.init(self)
def SPACE(self): return(' ')
def program_begin(self, id, comment):
self.write( ('(' + 'GCode created using the HeeksCNC Mach3 post processor' + ')' + '\n') )
self.write( ('(' + comment + ')' + '\n') )
def tool_change(self, id):
self.write('G43H%i'% id +'\n')
self.write((self.TOOL() % id) + '\n')
self.t = id
nc.creator = Creator()

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Machine post="emc2b" reader="iso_read" suffix=".ngc" description="LinuxCNC"/>
<Machine post="siegkx1" reader="iso_read" suffix=".tap" description="Mach3 Machine Controller"/>
<Machine post="DeckelFP4Ma" reader="iso_read" suffix=".ngc" description="Deckel FP4Ma"/>
<Machine post="hpgl2d" reader="hpgl2d_read" suffix=".tap" description="HPGL2D"/>
<Machine post="hpgl2dv" reader="hpgl2dv_read" suffix=".tap" description="HPGL2DV"/>
<Machine post="hpgl3d" reader="hpgl3d_read" suffix=".tap" description="HPGL3D"/>

View File

@@ -0,0 +1,306 @@
import nc
import makerbot_codes as maker
import datetime
import iso_modal
import math
now = datetime.datetime.now()
################################################################################
class CreatorMakerbotHBP(iso_modal.CreatorIsoModal):
def __init__(self):
iso_modal.CreatorIsoModal.__init__(self)
self.absolute_flag = True
self.prev_g91 = ''
################################################################################
# program begin and end
def program_begin(self, id, name=''):
self.write((maker.codes.COMMENT(now)))
self.write((maker.codes.EXTRUDER_TEMP('220')) + (maker.codes.COMMENT('Extruder Temp')) )
self.write((maker.codes.BUILD_BED_TEMP('110'))+ (maker.codes.COMMENT('Build Bed Temp')) )
self.write((maker.codes.FAN_OFF()) + (maker.codes.COMMENT('Fan Off')) )
self.write((maker.codes.METRIC()) + (maker.codes.COMMENT('Metric units')) )
self.write((maker.codes.ABSOLUTE()) + (maker.codes.COMMENT('Absolute units')) )
self.write('G92 X0 Y0 Z0 (You are now at 0,0,0)\n')
self.write('G0 Z15 (Move up for warmup)\n')
self.write((maker.codes.EXTRUDER_SPEED_PWM('255')) + (maker.codes.COMMENT('Extruder Speed')) )
self.write('M6 T0 (Wait for tool to heat up)\n')
self.write('G04 P5000 (Wait 5 seconds)\n')
self.write((maker.codes.EXTRUDER_ON_FWD()) + (maker.codes.COMMENT('Extruder On')) )
self.write('G04 P5000 (Wait 5 seconds)\n')
self.write((maker.codes.EXTRUDER_OFF()) + (maker.codes.COMMENT('Extruder Off')) )
self.write('M01 (The heated build platform is heating up. Wait until after the lights have turned off for the first time, clear the test extrusion, and click yes.)\n')
self.write('G0 Z0 (Go back to zero.)\n')
def program_end(self):
self.write((maker.codes.COMMENT('End of the file. Begin cool-down')))
self.write((maker.codes.EXTRUDER_TEMP('0')) + (maker.codes.COMMENT('Extruder Temp')) )
self.write((maker.codes.BUILD_BED_TEMP('0')) + (maker.codes.COMMENT('Build Bed Temp')) )
self.write((maker.codes.FAN_ON()) + (maker.codes.COMMENT('Fan On')) )
self.write('G92 Z0 (zero our z axis - hack b/c skeinforge mangles gcodes in end.txt)\n')
self.write('G1 Z10 (go up 10 b/c it was zeroed earlier.)\n')
self.write('G1 X0 Y0 Z10 (go to 0,0,z)\n')
self.write((maker.codes.STEPPERS_OFF()) + (maker.codes.COMMENT('Steppers Off')) )
def program_stop(self):
self.write((maker.codes.EXTRUDER_TEMP('0')))
self.write((maker.codes.BUILD_BED_TEMP('0')))
self.write((maker.codes.STEPPERS_OFF()))
################################################################################
# general
def write_blocknum(self):
pass
def set_plane(self, plane):
pass
def workplane(self, id):
pass
def spindle(self, s, clockwise):
pass
################################################################################
# Extruder Control
def extruder_on(self):
self.write((maker.codes.EXTRUDER_ON()) + ('\n'))
def extruder_off(self):
self.write((maker.codes.EXTRUDER_OFF()) + ('\n'))
def set_extruder_flowrate(self, flowrate):
self.write((maker.codes.EXTRUDER_SPEED_PWM(flowrate)) + ('\n'))
def extruder_temp(self, temp):
self.write((maker.codes.EXTRUDER_TEMP(temp)) + ('\n'))
################################################################################
# Build Environment Control
def build_bed_temp(self, temp):
self.write((maker.codes.BUILD_BED_TEMP(temp)) + ('\n'))
def chamber_temp(self, temp):
self.write((maker.codes.CHAMBER_TEMP(temp)) + ('\n'))
################################################################################
# Fan Control
def fan_on(self):
self.write((maker.codes.FAN_ON()) + ('\n'))
def fan_off(self):
self.write((maker.codes.FAN_OFF()) + ('\n'))
################################################################################
# Custom routines
def wipe(self):
self.write(('(This would be a good place for a custom wipe routine)\n'))
################################################################################
# APT style INSERT- insert anything into program
def insert(self, text):
self.write((text + '\n'))
################################################################################
# tool info
def tool_change(self, id):
pass
# self.write_blocknum()
# self.write((maker.codes.TOOL() % id) + '\n')
# self.t = id
def tool_defn(self, id, name='', params=None):
pass
############################################################################
## Moves
def rapid(self, x=None, y=None, z=None, a=None, b=None, c=None ):
self.write_blocknum()
if self.g0123_modal:
if self.prev_g0123 != maker.codes.RAPID():
self.write(maker.codes.RAPID())
self.prev_g0123 = maker.codes.RAPID()
else:
self.write(maker.codes.RAPID())
self.write_preps()
if (x != None):
dx = x - self.x
if (self.absolute_flag ):
self.write(maker.codes.X() + (self.fmt % x))
else:
self.write(maker.codes.X() + (self.fmt % dx))
self.x = x
if (y != None):
dy = y - self.y
if (self.absolute_flag ):
self.write(maker.codes.Y() + (self.fmt % y))
else:
self.write(maker.codes.Y() + (self.fmt % dy))
self.y = y
if (z != None):
dz = z - self.z
if (self.absolute_flag ):
self.write(maker.codes.Z() + (self.fmt % z))
else:
self.write(maker.codes.Z() + (self.fmt % dz))
self.z = z
if (a != None):
da = a - self.a
if (self.absolute_flag ):
self.write(maker.codes.A() + (self.fmt % a))
else:
self.write(maker.codes.A() + (self.fmt % da))
self.a = a
if (b != None):
db = b - self.b
if (self.absolute_flag ):
self.write(maker.codes.B() + (self.fmt % b))
else:
self.write(maker.codes.B() + (self.fmt % db))
self.b = b
if (c != None):
dc = c - self.c
if (self.absolute_flag ):
self.write(maker.codes.C() + (self.fmt % c))
else:
self.write(maker.codes.C() + (self.fmt % dc))
self.c = c
self.write_spindle()
self.write_misc()
self.write('\n')
def feed(self, x=None, y=None, z=None, a = None, b = None, c = None):
if self.same_xyz(x, y, z): return
self.write_blocknum()
if self.g0123_modal:
if self.prev_g0123 != maker.codes.FEED():
self.write(maker.codes.FEED())
self.prev_g0123 = maker.codes.FEED()
else:
self.write(maker.codes.FEED())
self.write_preps()
dx = dy = dz = 0
if (x != None):
dx = x - self.x
if (self.absolute_flag ):
self.write(maker.codes.X() + (self.fmt % x))
else:
self.write(maker.codes.X() + (self.fmt % dx))
self.x = x
if (y != None):
dy = y - self.y
if (self.absolute_flag ):
self.write(maker.codes.Y() + (self.fmt % y))
else:
self.write(maker.codes.Y() + (self.fmt % dy))
self.y = y
if (z != None):
dz = z - self.z
if (self.absolute_flag ):
self.write(maker.codes.Z() + (self.fmt % z))
else:
self.write(maker.codes.Z() + (self.fmt % dz))
self.z = z
if (self.fhv) : self.calc_feedrate_hv(math.sqrt(dx*dx+dy*dy), math.fabs(dz))
self.write_feedrate()
self.write_spindle()
self.write_misc()
self.write('\n')
def same_xyz(self, x=None, y=None, z=None):
if (x != None):
if (self.fmt % x) != (self.fmt % self.x):
return False
if (y != None):
if (self.fmt % y) != (self.fmt % self.y):
return False
if (z != None):
if (self.fmt % z) != (self.fmt % self.z):
return False
return True
def arc(self, cw, x=None, y=None, z=None, i=None, j=None, k=None, r=None):
if self.same_xyz(x, y, z): return
self.write_blocknum()
arc_g_code = ''
if cw: arc_g_code = maker.codes.ARC_CW()
else: arc_g_code = maker.codes.ARC_CCW()
if self.g0123_modal:
if self.prev_g0123 != arc_g_code:
self.write(arc_g_code)
self.prev_g0123 = arc_g_code
else:
self.write(arc_g_code)
self.write_preps()
if (x != None):
dx = x - self.x
if (self.absolute_flag ):
self.write(maker.codes.X() + (self.fmt % x))
else:
self.write(maker.codes.X() + (self.fmt % dx))
self.x = x
if (y != None):
dy = y - self.y
if (self.absolute_flag ):
self.write(maker.codes.Y() + (self.fmt % y))
else:
self.write(maker.codes.Y() + (self.fmt % dy))
self.y = y
if (z != None):
dz = z - self.z
if (self.absolute_flag ):
self.write(maker.codes.Z() + (self.fmt % z))
else:
self.write(maker.codes.Z() + (self.fmt % dz))
self.z = z
if (i != None) : self.write(maker.codes.CENTRE_X() + (self.fmt % i))
if (j != None) : self.write(maker.codes.CENTRE_Y() + (self.fmt % j))
if (k != None) : self.write(maker.codes.CENTRE_Z() + (self.fmt % k))
if (r != None) : self.write(maker.codes.RADIUS() + (self.fmt % r))
# use horizontal feed rate
if (self.fhv) : self.calc_feedrate_hv(1, 0)
self.write_feedrate()
self.write_spindle()
self.write_misc()
self.write('\n')
def arc_cw(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None):
self.arc(True, x, y, z, i, j, k, r)
def arc_ccw(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None):
self.arc(False, x, y, z, i, j, k, r)
def dwell(self, t):
self.write_blocknum()
self.write_preps()
self.write(maker.codes.DWELL() + (maker.codes.TIME() % t))
self.write_misc()
self.write('\n')
def rapid_home(self, x=None, y=None, z=None, a=None, b=None, c=None):
pass
def rapid_unhome(self):
pass
def set_machine_coordinates(self):
self.write(maker.codes.MACHINE_COORDINATES())
self.prev_g0123 = ''
nc.creator = CreatorMakerbotHBP()

View File

@@ -0,0 +1,128 @@
################################################################################
# makerbot_codes.py
#
# a lot like iso_codes.py but with reprap/makerbot specific M codes.
#
# Brad Collette, 12th Sept 2010
#
# Many of these codes have nothing to do with reprap/additive machining but are left here in anticipation of future hybrid machines.
class Codes():
def SPACE(self): return(' ')
def FORMAT_FEEDRATE(self): return('%.2f')
def FORMAT_IN(self): return('%.5f')
def FORMAT_MM(self): return('%.3f')
def FORMAT_ANG(self): return('%.1f')
def FORMAT_TIME(self): return('%.2f')
def FORMAT_DWELL(self): return('P%f')
def BLOCK(self): return('N%i' + self.SPACE())
def COMMENT(self,comment): return( (' (%s)\n' % comment ) )
def VARIABLE(self): return( '#%i')
def VARIABLE_SET(self): return( '=%.3f')
def PROGRAM(self): return( 'O%i')
def PROGRAM_END(self): return( 'M02')
def SUBPROG_CALL(self): return( 'M98' + self.SPACE() + 'P%i')
def SUBPROG_END(self): return( 'M99')
def STOP_OPTIONAL(self): return('M01')
def STOP(self): return('M00')
def IMPERIAL(self): return(self.SPACE() + 'G20')
def METRIC(self): return(self.SPACE() + 'G21' + self.SPACE())
def ABSOLUTE(self): return(self.SPACE() + 'G90' + self.SPACE())
def INCREMENTAL(self): return(self.SPACE() + 'G91')
def SET_TEMPORARY_COORDINATE_SYSTEM(self): return('G92' + self.SPACE())
def REMOVE_TEMPORARY_COORDINATE_SYSTEM(self): return('G92.1' + self.SPACE())
def POLAR_ON(self): return(self.SPACE() + 'G16')
def POLAR_OFF(self): return(self.SPACE() + 'G15')
def PLANE_XY(self): return(self.SPACE() + 'G17')
def PLANE_XZ(self): return(self.SPACE() + 'G18')
def PLANE_YZ(self): return(self.SPACE() + 'G19')
def TOOL(self): return(self.SPACE() +'T%i')
def TOOL_DEFINITION(self): return('G10' + self.SPACE() + 'L1' + self.SPACE())
def WORKPLANE(self): return('G%i')
def WORKPLANE_BASE(self): return(53)
def FEEDRATE(self): return((self.SPACE() + ' F'))
def SPINDLE(self, format, speed): return(self.SPACE() + 'S' + (format % speed))
def SPINDLE_CW(self): return(self.SPACE() + 'M03')
def SPINDLE_CCW(self): return(self.SPACE() + 'M04')
def COOLANT_OFF(self): return(self.SPACE() + 'M09')
def COOLANT_MIST(self): return(self.SPACE() + 'M07')
def COOLANT_FLOOD(self): return(self.SPACE() + 'M08')
def GEAR_OFF(self): return(self.SPACE() + '?')
def GEAR(self): return('M%i')
def GEAR_BASE(self): return(37)
def RAPID(self): return('G0')
def FEED(self): return('G1')
def ARC_CW(self): return('G2')
def ARC_CCW(self): return('G3')
def DWELL(self): return('G04')
def DRILL(self): return(self.SPACE() + 'G81')
def DRILL_WITH_DWELL(self, format, dwell): return(self.SPACE() + 'G82' + (format % dwell))
def PECK_DRILL(self): return(self.SPACE() + 'G83')
def PECK_DEPTH(self, format, depth): return(self.SPACE() + 'Q' + (format % depth))
def RETRACT(self, format, height): return(self.SPACE() + 'R' + (format % height))
def END_CANNED_CYCLE(self): return(self.SPACE() + 'G80')
def X(self): return(self.SPACE() + 'X')
def Y(self): return(self.SPACE() + 'Y')
def Z(self): return(self.SPACE() + 'Z')
def A(self): return(self.SPACE() + 'A')
def B(self): return(self.SPACE() + 'B')
def C(self): return(self.SPACE() + 'C')
def CENTRE_X(self): return(self.SPACE() + 'I')
def CENTRE_Y(self): return(self.SPACE() + 'J')
def CENTRE_Z(self): return(self.SPACE() + 'K')
def RADIUS(self): return(self.SPACE() + 'R')
def TIME(self): return(self.SPACE() + 'P')
def PROBE_TOWARDS_WITH_SIGNAL(self): return('G38.2' + self.SPACE())
def PROBE_TOWARDS_WITHOUT_SIGNAL(self): return('G38.3' + self.SPACE())
def PROBE_AWAY_WITH_SIGNAL(self): return('G38.4' + self.SPACE())
def PROBE_AWAY_WITHOUT_SIGNAL(self): return('G38.5' + self.SPACE())
def MACHINE_COORDINATES(self): return('G53' + self.SPACE())
def EXTRUDER_ON (self): return('M101') #deprecated
def EXTRUDER_OFF (self): return('M103')
def EXTRUDER_TEMP (self, degree_celsius): return('M104 S' + '%s' % degree_celsius)
def EXTRUDER_TEMP_WAIT (self, degree_celsius): return('M109 S' + '%s' % degree_celsius)
def READ_EXTRUDER_TEMP (self): return('M105')
def EXTRUDER_SPEED_PWM (self, speed_in_PWM): return('M108 S' + '%s' % speed_in_PWM) #deprecated
def EXTRUDER_SPEED_RPM (self, speed_in_RPM): return('M108 P' + '%s' % speed_in_RPM) #deprecated
def STEPPERS_OFF(self): return(self.SPACE() + 'M118')
def ALL_WAIT (self): return(self.SPACE() + 'M116') # Wait for all temperature and slow-changing variables to reach set values
def FAN_ON (self): return(self.SPACE() + 'M106')
def FAN_OFF (self): return(self.SPACE() + 'M107')
def VALVE_OPEN (self, delay): return(self.SPACE() + ('M126 P' + '%' % delay) )
def VALVE_CLOSE (self, delay): return(self.SPACE() + ('M127 P' + '%' % delay) )
def BUILD_BED_TEMP (self, degree_celsius): return('M140 S' + '%s' % degree_celsius)
def BED_HOLDING_PRESSURE (self, pressure): return('M142 S' + '%s' % pressure)
def CHAMBER_TEMP (self, degree_celsius): return('M141 S' + '%s' % degree_celsius)
#The following codes are listed on the reprap wiki page at http://reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes but require more study.
#
#G28 G Y Xnnn Ynnn Znnn Move to origin (on specified axes only, if X/Y/Z parameters are present)
#M105 M N none Request current extruder and base temperatures (in Celsius)
#M110 M N none Set current line number to Nxxx value preceeding command
#M111 M N Snnn Set debug level bitfield to value of parameter (default 6)
#M112 M N none Emergency stop (stop immediately, discarding any buffered commands)
#M113 M N Snnn Set Extruder PWM (to value defined by pot, or to parameter value if present)
#M114 M N none Get Current Position (return current X, Y, Z and E values)
#M117 M N none Get Zero Position (return X, Y, Z and E values of endstop hits)
codes = Codes()

View File

@@ -0,0 +1,636 @@
################################################################################
# nc.py
#
# Base class for NC code creation
# And global functions for calling current creator
#
# Hirutso Enni, 2009-01-13
# altered by Dan Falck 2010-08-04
# added tap() arguments Michael Haberler 2010-10-07
################################################################################
ncOFF = 0
ncLEFT = -1
ncRIGHT = +1
ncCW = -1
ncCCW = +1
ncMIST = 1
ncFLOOD = 2
################################################################################
class Creator:
def __init__(self):
pass
############################################################################
## Internals
def file_open(self, name):
if name == "mem":
self.gcode = ""
else:
self.file = open(name, 'w')
self.filename = name
def file_close(self):
if self.filename != "mem":
self.file.close()
def write(self, s):
if self.filename == "mem":
self.gcode += s
else:
self.file.write(s)
def retrieve_gcode(self):
return self.gcode
############################################################################
## Programs
def program_begin(self, id, name=''):
"""Begin a program"""
pass
def add_stock(self, type_name, params):
pass
def program_stop(self, optional=False):
"""Stop the machine"""
pass
def program_end(self):
"""End the program"""
pass
def flush_nc(self):
"""Flush all pending codes"""
pass
############################################################################
## Subprograms
def sub_begin(self, id, name=''):
"""Begin a subprogram"""
pass
def sub_call(self, id):
"""Call a subprogram"""
pass
def sub_end(self):
"""Return from a subprogram"""
pass
############################################################################
## Settings
def imperial(self):
"""Set imperial units"""
pass
def metric(self):
"""Set metric units"""
pass
def absolute(self):
"""Set absolute coordinates"""
pass
def incremental(self):
"""Set incremental coordinates"""
pass
def polar(self, on=True):
"""Set polar coordinates"""
pass
def set_plane(self, plane):
"""Set plane"""
pass
def set_temporary_origin(self, x=None, y=None, z=None, a=None, b=None, c=None):
"""Set temporary origin G92"""
pass
def remove_temporary_origin(self):
"""Remote temporary origin G92.1"""
pass
############################################################################
## Tools
def tool_change(self, id):
"""Change the tool"""
pass
def tool_defn(self, id, name='', params=None):
"""Define a tool"""
pass
def offset_radius(self, id, radius=None):
"""Set tool radius offsetting"""
pass
def offset_length(self, id, length=None):
"""Set tool length offsetting"""
pass
def current_tool(self):
return None
############################################################################
## Datums
def datum_shift(self, x=None, y=None, z=None, a=None, b=None, c=None):
"""Shift the datum"""
pass
def datum_set(self, x=None, y=None, z=None, a=None, b=None, c=None):
"""Set the datum"""
pass
def workplane(self, id):
"""Set the workplane"""
pass
def clearanceplane(self,z=None):
"""set clearance plane"""
pass
############################################################################
## APT360 like Transformation Definitions
## These definitions were created while looking at Irvin Kraal's book on APT
## - Numerical Control Progamming in APT - page 211
def matrix(self,a1=None,b1=None,c1=None,a2=None,b2=None,c2=None,a3=None,b3=None,c3=None):
"""Create a matrix for transformations"""
pass
def translate(self,x=None,y=None,z=None):
"""Translate in x,y,z direction"""
pass
def rotate(self,xyrot=None,yzrot=None,zxrot=None,angle=None):
"""Rotate about a coordinate axis"""
pass
def scale(self,k=None):
"""Scale by factor k"""
pass
def matrix_product(self,matrix1=None,matrix2=None):
"""Create matrix that is the product of two other matrices"""
pass
def mirror_plane(self,plane1=None,plane2=None,plane3=None):
"""Mirror image about one or more coordinate planes"""
pass
def mirror_line(self,line=None):
"""Mirror about a line"""
pass
############################################################################
## Rates + Modes
def feedrate(self, f):
"""Set the feedrate"""
pass
def feedrate_hv(self, fh, fv):
"""Set the horizontal and vertical feedrates"""
pass
def spindle(self, s, clockwise=True):
"""Set the spindle speed"""
pass
def coolant(self, mode=0):
"""Set the coolant mode"""
pass
def gearrange(self, gear=0):
"""Set the gear range"""
pass
############################################################################
## Moves
def rapid(self, x=None, y=None, z=None):
"""Rapid move"""
pass
def feed(self, x=None, y=None, z=None):
"""Feed move"""
pass
def arc_cw(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None):
"""Clockwise arc move"""
pass
def arc_ccw(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None):
"""Counterclockwise arc move"""
pass
def dwell(self, t):
"""Dwell"""
pass
def rapid_home(self, x=None, y=None, z=None):
"""Rapid relative to home position"""
pass
def rapid_unhome(self):
"""Return from rapid home"""
pass
def set_machine_coordinates(self):
"""Set machine coordinates"""
pass
############################################################################
## Cutter radius compensation
def use_CRC(self):
"""CRC"""
return False
############################################################################
## Cycles
def pattern(self):
"""Simple pattern eg. circle, rect"""
pass
def pocket(self):
"""Pocket routine"""
pass
def profile(self):
"""Profile routine"""
pass
def drill(self, x=None, y=None, dwell=None, depthparams = None, retract_mode=None, spindle_mode=None, internal_coolant_on=None, rapid_to_clearance=None):
"""Drilling routines"""
pass
# original prototype was:
# def tap(self, x=None, y=None, z=None, zretract=None, depth=None, standoff=None, dwell_bottom=None, pitch=None, stoppos=None, spin_in=None, spin_out=None):
#
# current call is like so:
# tap(x=10, y=10, z=0, tap_mode=0, depth=12.7, standoff=6.35, direction=0, pitch=1.25)
# just add tap_mode & direction parameters
def tap(self, x=None, y=None, z=None, zretract=None, depth=None, standoff=None, dwell_bottom=None, pitch=None, stoppos=None, spin_in=None, spin_out=None, tap_mode=None, direction=None):
"""Tapping routines"""
pass
def bore(self, x=None, y=None, z=None, zretract=None, depth=None, standoff=None, dwell_bottom=None, feed_in=None, feed_out=None, stoppos=None, shift_back=None, shift_right=None, backbore=False, stop=False):
"""Boring routines"""
pass
def end_canned_cycle(self):
pass
############################################################################
## Misc
def comment(self, text):
"""Insert a comment"""
pass
def insert(self, text):
"""APT style INSERT statement"""
pass
def block_delete(self, on=False):
"""block to ignore if block delete switch is on"""
pass
def variable(self, id):
"""Insert a variable"""
pass
def variable_set(self, id, value):
"""Set a variable"""
pass
def probe_linear_centre_outside(self, x1=None, y1=None, depth=None, x2=None, y2=None ):
pass
def probe_single_point(self, point_along_edge_x=None, point_along_edge_y=None, depth=None, retracted_point_x=None, retracted_point_y=None, destination_point_x=None, destination_point_y=None, intersection_variable_x=None, intersection_variable_y=None, probe_offset_x_component=None, probe_offset_y_component=None ):
pass
def probe_downward_point(self, x=None, y=None, depth=None, intersection_variable_z=None):
pass
def report_probe_results(self, x1=None, y1=None, z1=None, x2=None, y2=None, z2=None, x3=None, y3=None, z3=None, x4=None, y4=None, z4=None, x5=None, y5=None, z5=None, x6=None, y6=None, z6=None, xml_file_name=None ):
pass
def open_log_file(self, xml_file_name=None ):
pass
def log_coordinate(self, x=None, y=None, z=None):
pass
def log_message(self, message=None):
pass
def close_log_file(self):
pass
def rapid_to_midpoint(self, x1=None, y1=None, z1=None, x2=None, y2=None, z2=None):
pass
def rapid_to_intersection(self, x1, y1, x2, y2, x3, y3, x4, y4, intersection_x, intersection_y, ua_numerator, ua_denominator, ua, ub_numerator, ub):
pass
def rapid_to_rotated_coordinate(self, x1, y1, x2, y2, ref_x, ref_y, x_current, y_current, x_final, y_final):
pass
def set_path_control_mode(self, mode, motion_blending_tolerance, naive_cam_tolerance ):
pass
################################################################################
creator = Creator()
############################################################################
## Internals
def write(s):
creator.write(s)
def output(filename):
creator.file_open(filename)
def retrieve_gcode():
return creator.retrieve_gcode()
############################################################################
## Programs
def program_begin(id, name=''):
creator.program_begin(id, name)
def add_stock(type_name, params):
creator.add_stock(type_name, params)
def program_stop(optional=False):
creator.program_stop(optional)
def program_end():
creator.program_end()
def flush_nc():
creator.flush_nc()
############################################################################
## Subprograms
def sub_begin(id, name=''):
creator.sub_begin(id, name)
def sub_call(id):
creator.sub_call(id)
def sub_end():
creator.sub_end()
############################################################################
## Settings
def imperial():
creator.imperial()
def metric():
creator.metric()
def absolute():
creator.absolute()
def incremental():
creator.incremental()
def polar(on=True):
creator.polar(on)
def set_plane(plane):
creator.set_plane(plane)
def set_temporary_origin(x=None, y=None, z=None, a=None, b=None, c=None):
creator.set_temporary_origin(x,y,z,a,b,c)
def remove_temporary_origin():
creator.remove_temporary_origin()
############################################################################
## Tools
def tool_change(id):
creator.tool_change(id)
def tool_defn(id, name='', params=None):
creator.tool_defn(id, name, params)
def offset_radius(id, radius=None):
creator.offset_radius(id, radius)
def offset_length(id, length=None):
creator.offset_length(id, length)
def current_tool(self):
return creator.current_tool()
############################################################################
## Datums
def datum_shift(x=None, y=None, z=None, a=None, b=None, c=None):
creator.datum_shift(x, y, z, a, b, c)
def datum_set(x=None, y=None, z=None, a=None, b=None, c=None):
creator.datum_set(x, y, z, a, b, c)
def workplane(id):
creator.workplane(id)
def clearanceplane(z=None):
creator.clearanceplane(z)
############################################################################
## APT360 like Transformation Definitions
## These definitions were created while looking at Irvin Kraal's book on APT
## - Numerical Control Progamming in APT - page 211
def matrix(a1=None,b1=None,c1=None,a2=None,b2=None,c2=None,a3=None,b3=None,c3=None):
creator.matrix(a1,b1,c1,a2,b2,c2,a3,b3,c3)
def translate(x=None,y=None,z=None):
creator.translate(x,y,z)
def rotate(xyrot=None,yzrot=None,zxrot=None,angle=None):
creator.rotate(xyrot,yzrot,zxrot,angle)
def scale(k=None):
creator.scale(k)
def matrix_product(matrix1=None,matrix2=None):
creator.matrix_product(matrix1,matrix2)
def mirror_plane(plane1=None,plane2=None,plane3=None):
creator.mirror_plane(plane1,plane2,plane3)
def mirror_line(line=None):
creator.mirror_line(line)
############################################################################
## Rates + Modes
def feedrate(f):
creator.feedrate(f)
def feedrate_hv(fh, fv):
creator.feedrate_hv(fh, fv)
def spindle(s, clockwise=True):
creator.spindle(s, clockwise)
def coolant(mode=0):
creator.coolant(mode)
def gearrange(gear=0):
creator.gearrange(gear)
############################################################################
## Moves
def rapid(x=None, y=None, z=None):
creator.rapid(x, y, z)
def feed(x=None, y=None, z=None):
creator.feed(x, y, z)
def arc_cw(x=None, y=None, z=None, i=None, j=None, k=None, r=None):
creator.arc_cw(x, y, z, i, j, k, r)
def arc_ccw(x=None, y=None, z=None, i=None, j=None, k=None, r=None):
creator.arc_ccw(x, y, z, i, j, k, r)
def dwell(t):
creator.dwell(t)
def rapid_home(x=None, y=None, z=None):
creator.rapid_home(x, y, z)
def rapid_unhome():
creator.rapid_unhome()
def set_machine_coordinates():
creator.set_machine_coordinates()
############################################################################
## Cutter radius compensation
def use_CRC():
return creator.use_CRC()
def CRC_nominal_path():
return creator.CRC_nominal_path()
def start_CRC(left = True, radius = 0.0):
creator.start_CRC(left, radius)
def end_CRC():
creator.end_CRC()
############################################################################
## Cycles
def pattern():
creator.pattern()
def pocket():
creator.pocket()
def profile():
creator.profile()
def drill(x=None, y=None, dwell=None, depthparams = None, retract_mode=None, spindle_mode=None, internal_coolant_on=None, rapid_to_clearance=None):
creator.drill(x, y, dwell, depthparams, retract_mode, spindle_mode, internal_coolant_on, rapid_to_clearance)
def tap(x=None, y=None, z=None, zretract=None, depth=None, standoff=None, dwell_bottom=None, pitch=None, stoppos=None, spin_in=None, spin_out=None, tap_mode=None, direction=None):
creator.tap(x, y, z, zretract, depth, standoff, dwell_bottom, pitch, stoppos, spin_in, spin_out, tap_mode, direction)
def bore(x=None, y=None, z=None, zretract=None, depth=None, standoff=None, dwell_bottom=None, feed_in=None, feed_out=None, stoppos=None, shift_back=None, shift_right=None, backbore=False, stop=False):
creator.bore(x, y, z, zretract, depth, standoff, dwell_Bottom, feed_in, feed_out, stoppos, shift_back, shift_right, backbore, stop)
def end_canned_cycle():
creator.end_canned_cycle()
def peck(count, first, last=None, step=0.0):
pecks = []
peck = first
if (last == None) : last = first
for i in range(0,count):
pecks.append(peck)
if (peck - step > last) : peck -= step
return pecks
############################################################################
## Misc
def comment(text):
creator.comment(text)
def insert(text):
creator.insert(text)
def block_delete(on=False):
creator.block_delete(on)
def variable(id):
creator.variable(id)
def variable_set(id, value):
creator.variable_set(id, value)
def probe_single_point(point_along_edge_x=None, point_along_edge_y=None, depth=None, retracted_point_x=None, retracted_point_y=None, destination_point_x=None, destination_point_y=None, intersection_variable_x=None, intersection_variable_y=None, probe_offset_x_component=None, probe_offset_y_component=None ):
creator.probe_single_point(point_along_edge_x, point_along_edge_y, depth, retracted_point_x, retracted_point_y, destination_point_x, destination_point_y, intersection_variable_x, intersection_variable_y, probe_offset_x_component, probe_offset_y_component )
def probe_downward_point(x=None, y=None, depth=None, intersection_variable_z=None):
creator.probe_downward_point(x, y, depth, intersection_variable_z)
def report_probe_results(x1=None, y1=None, z1=None, x2=None, y2=None, z2=None, x3=None, y3=None, z3=None, x4=None, y4=None, z4=None, x5=None, y5=None, z5=None, x6=None, y6=None, z6=None, xml_file_name=None ):
creator.report_probe_results(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4, x5, y5, z5, x6, y6, z6, xml_file_name)
def open_log_file(xml_file_name=None ):
creator.open_log_file(xml_file_name)
def log_coordinate(x=None, y=None, z=None):
creator.log_coordinate(x, y, z)
def log_message(message=None):
creator.log_message(message)
def close_log_file():
creator.close_log_file()
def rapid_to_midpoint(x1=None, y1=None, z1=None, x2=None, y2=None, z2=None):
creator.rapid_to_midpoint(x1, y1, z1, x2, y2, z2)
def rapid_to_intersection(x1, y1, x2, y2, x3, y3, x4, y4, intersection_x, intersection_y, ua_numerator, ua_denominator, ua, ub_numerator, ub):
creator.rapid_to_intersection(x1, y1, x2, y2, x3, y3, x4, y4, intersection_x, intersection_y, ua_numerator, ua_denominator, ua, ub_numerator, ub)
def rapid_to_rotated_coordinate(x1, y1, x2, y2, ref_x, ref_y, x_current, y_current, x_final, y_final):
creator.rapid_to_rotated_coordinate(x1, y1, x2, y2, ref_x, ref_y, x_current, y_current, x_final, y_final)
def set_path_control_mode(mode, motion_blending_tolerance, naive_cam_tolerance ):
creator.set_path_control_mode(mode, motion_blending_tolerance, naive_cam_tolerance )

View File

@@ -0,0 +1,171 @@
################################################################################
# nc_read.py
#
# Base class for NC code parsing
################################################################################
import area
import math
count = 0
class Program: # stores start and end lines of programs and subroutines
def __init__(self):
self.start_line = None
self.end_line = None
class Parser:
def __init__(self, writer):
self.writer = writer
self.currentx = None
self.currenty = None
self.currentz = None
self.absolute_flag = True
self.drillz = None
self.need_m6_for_t_change = True
def __del__(self):
self.file_in.close()
############################################################################
## Internals
def readline(self):
self.line = self.file_in.readline().rstrip()
if (len(self.line)) : return True
else : return False
def set_current_pos(self, x, y, z):
if (x != None) :
if self.absolute_flag or self.currentx == None: self.currentx = x
else: self.currentx = self.currentx + x
if (y != None) :
if self.absolute_flag or self.currenty == None: self.currenty = y
else: self.currenty = self.currenty + y
if (z != None) :
if self.absolute_flag or self.currentz == None: self.currentz = z
else: self.currentz = self.currentz + z
def incremental(self):
self.absolute_flag = False
def absolute(self):
self.absolute_flag = True
def Parse(self, name):
self.file_in = open(name, 'r')
self.path_col = None
self.f = None
self.arc = 0
self.q = None
self.r = None
self.drilling = None
self.drilling_uses_clearance = False
self.drilling_clearance_height = None
while (self.readline()):
self.a = None
self.b = None
self.c = None
self.h = None
self.i = None
self.j = None
self.k = None
self.p = None
self.s = None
self.x = None
self.y = None
self.z = None
self.t = None
self.m6 = False
self.writer.begin_ncblock()
self.move = False
self.height_offset = False
self.drill = False
self.drill_off = False
self.no_move = False
words = self.pattern_main.findall(self.line)
for word in words:
self.col = None
self.cdata = False
self.ParseWord(word)
self.writer.add_text(word, self.col, self.cdata)
if self.t != None:
if (self.m6 == True) or (self.need_m6_for_t_change == False):
self.writer.tool_change( self.t )
if self.height_offset and (self.z != None):
self.drilling_clearance_height = self.z
if self.drill:
self.drilling = True
if self.drill_off:
self.drilling = False
if self.drilling:
rapid_z = self.r
if self.drilling_uses_clearance and (self.drilling_clearance_height != None):
rapid_z = self.drilling_clearance_height
if self.z != None: self.drillz = self.z
self.writer.rapid(self.x, self.y, rapid_z)
self.writer.feed(self.x, self.y, self.drillz)
self.writer.feed(self.x, self.y, rapid_z)
else:
if (self.move and not self.no_move):
if (self.arc==0):
if self.path_col == "feed":
self.writer.feed(self.x, self.y, self.z)
else:
self.writer.rapid(self.x, self.y, self.z, self.a, self.b, self.c)
else:
i = self.i
j = self.j
k = self.k
if self.arc_centre_absolute == True:
pass
else:
if (self.arc_centre_positive == True) and (self.oldx != None) and (self.oldy != None):
x = self.oldx
if self.x != None: x = self.x
if (self.x > self.oldx) != (self.arc > 0):
j = -j
y = self.oldy
if self.y != None: y = self.y
if (self.y > self.oldy) != (self.arc < 0):
i = -i
#fix centre point
r = math.sqrt(i*i + j*j)
p0 = area.Point(self.oldx, self.oldy)
p1 = area.Point(x, y)
v = p1 - p0
l = v.length()
h = l/2
d = math.sqrt(r*r - h*h)
n = area.Point(-v.y, v.x)
n.normalize()
if self.arc == -1: d = -d
c = p0 + (v * 0.5) + (n * d)
i = c.x
j = c.y
else:
i = i + self.oldx
j = j + self.oldy
if self.arc == -1:
self.writer.arc_cw(self.x, self.y, self.z, i, j, k)
else:
self.writer.arc_ccw(self.x, self.y, self.z, i, j, k)
if self.x != None: self.oldx = self.x
if self.y != None: self.oldy = self.y
if self.z != None: self.oldz = self.z
self.writer.end_ncblock()

View File

@@ -0,0 +1,151 @@
################################################################################
# nc_read.py
#
# Base class for NC code parsing
#
# Hirutso Enni, 2009-01-13
################################################################################
class Parser:
def __init__(self):
self.currentx = 0.0
self.currenty = 0.0
self.currentz = 0.0
self.absolute_flag = True
############################################################################
## Internals
def files_open(self, name, oname=None):
if (oname == None ):
oname = (name+'.nc.xml')
self.file_in = open(name, 'r')
self.file_out = open(oname, 'w')
self.file_out.write('<?xml version="1.0" ?>\n')
self.file_out.write('<nccode>\n')
def files_close(self):
self.file_out.write('</nccode>\n')
self.file_in.close()
self.file_out.close()
def readline(self):
self.line = self.file_in.readline().rstrip()
if (len(self.line)) : return True
else : return False
def write(self, s):
self.file_out.write(s)
############################################################################
## Xml
def begin_ncblock(self):
self.file_out.write('\t<ncblock>\n')
def end_ncblock(self):
self.file_out.write('\t</ncblock>\n')
def add_text(self, s, col=None, cdata=False):
s.replace('&', '&amp;')
s.replace('"', '&quot;')
s.replace('<', '&lt;')
s.replace('>', '&gt;')
if (cdata) : (cd1, cd2) = ('<![CDATA[', ']]>')
else : (cd1, cd2) = ('', '')
if (col != None) : self.file_out.write('\t\t<text col="'+col+'">'+cd1+s+cd2+'</text>\n')
else : self.file_out.write('\t\t<text>'+cd1+s+cd2+'</text>\n')
def set_mode(self, units=None):
self.file_out.write('\t\t<mode')
if (units != None) : self.file_out.write(' units="'+str(units)+'"')
self.file_out.write(' />\n')
def set_tool(self, number=None):
self.file_out.write('\t\t<tool')
if (number != None) :
self.file_out.write(' number="'+str(number)+'"')
self.file_out.write(' />\n')
def begin_path(self, col=None):
if (col != None) : self.file_out.write('\t\t<path col="'+col+'">\n')
else : self.file_out.write('\t\t<path>\n')
def end_path(self):
self.file_out.write('\t\t</path>\n')
def add_line(self, x=None, y=None, z=None, a=None, b=None, c=None):
if (x == None and y == None and z == None and a == None and b == None and c == None) : return
self.file_out.write('\t\t\t<line')
if (x != None) :
if self.absolute_flag: self.currentx = x
else: self.currentx = self.currentx + x
self.file_out.write(' y="%.6f"' % (self.currentx/2))
if (y != None) :
if self.absolute_flag: self.currenty = y
else: self.currenty = self.currenty + y
#self.file_out.write(' y="%.6f"' % self.currenty)
if (z != None) :
if self.absolute_flag: self.currentz = z
else: self.currentz = self.currentz + z
self.file_out.write(' x="%.6f"' % self.currentz)
if (a != None) : self.file_out.write(' a="%.6f"' % a)
if (b != None) : self.file_out.write(' b="%.6f"' % b)
if (c != None) : self.file_out.write(' c="%.6f"' % c)
self.file_out.write(' />\n')
def add_lathe_increment_line(self, u=None, w=None):
# needed for representing U and W moves in lathe code- these are non modal incremental moves
# U == X and W == Z
if (u == None and w == None ) : return
self.file_out.write('\t\t\t<line')
if (u != None) :
self.currentx = self.currentx + u
self.file_out.write(' y="%.6f"' % (self.currentx/2))
if (w != None) :
self.currentz = self.currentz + w
self.file_out.write(' x="%.6f"' % self.currentz)
self.file_out.write(' />\n')
def add_arc(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None, d=None):
if (x == None and y == None and z == None and i == None and j == None and k == None and r == None and d == None) : return
self.file_out.write('\t\t\t<arc')
if (x != None) :
if self.absolute_flag: self.currentx = x
else: self.currentx = self.currentx + x
self.file_out.write(' y="%.6f"' % (self.currentx/2))
if (y != None) :
if self.absolute_flag: self.currenty = y
else: self.currenty = self.currenty + y
#self.file_out.write(' y="%.6f"' % self.currenty)
if (z != None) :
if self.absolute_flag: self.currentz = z
else: self.currentz = self.currentz + z
self.file_out.write(' x="%.6f"' % self.currentz)
#if (j != None) : self.file_out.write(' i="%.6f"' % j)
#if (i != None) : self.file_out.write(' j="%.6f"' % i)
#if (k != None) : self.file_out.write(' k="%.6f"' % k)
if (k != None) : self.file_out.write(' i="%.6f"' % k)
if (i != None) : self.file_out.write(' j="%.6f"' % i)
if (j != None) : self.file_out.write(' k="%.6f"' % j)
if (r != None) : self.file_out.write(' r="%.6f"' % r)
if (d != None) : self.file_out.write(' d="%i"' % d)
self.file_out.write(' />\n')
def incremental(self):
self.absolute_flag = False
def absolute(self):
self.absolute_flag = True

View File

@@ -0,0 +1,63 @@
import nc_read as nc
import sys
import math
# a base class for hpgl parsers, and maybe others
class NumReader(nc.Parser):
def __init__(self, writer):
nc.Parser.__init__(self, writer)
def get_number(self):
number = ''
# skip spaces and commas at start of number
while(self.line_index < self.line_length):
c = self.line[self.line_index]
if c == ' ' or c == ',':
self.parse_word += c
else:
break
self.line_index = self.line_index + 1
while(self.line_index < self.line_length):
c = self.line[self.line_index]
if c == '.' or c == '0' or c == '1' or c == '2' or c == '3' or c == '4' or c == '5' or c == '6' or c == '7' or c == '8' or c == '9' or c == '-':
number += c
else:
break
self.parse_word += c
self.line_index = self.line_index + 1
return number
def add_word(self, color):
self.writer.add_text(self.parse_word, color, None)
self.parse_word = ""
def Parse(self, name):
self.file_in = open(name, 'r')
while self.readline():
self.writer.begin_ncblock()
self.parse_word = ""
self.line_index = 0
self.line_length = len(self.line)
while self.line_index < self.line_length:
c = self.line[self.line_index]
self.parse_word += c
self.ParseFromFirstLetter(c)
self.line_index = self.line_index + 1
self.writer.add_text(self.parse_word, None, None)
self.writer.end_ncblock()
self.file_in.close()

View File

@@ -0,0 +1,53 @@
################################################################################
# printbot3d.py
#
# Dan Heeks 18th October 2010
import nc
import iso_modal
import math
################################################################################
class CreatorPrintbot(iso_modal.CreatorIsoModal):
def __init__(self):
iso_modal.CreatorIsoModal.__init__(self)
def tool_defn(self, id, name='', params=None):
pass
def write_blocknum(self):
pass
def set_plane(self, plane):
pass
def workplane(self, id):
pass
# Extruder Control
def extruder_on(self):
self.write('M101\n')
def extruder_off(self):
self.write('M103\n')
def set_extruder_flowrate(self, flowrate):
# re-use the spindle speed function
self.spindle(flowrate, True)
def extruder_temp(self, temp):
self.write((maker.codes.EXTRUDER_TEMP(temp)) + ('\n'))
# General
def rapid(x=None, y=None, z=None, a=None, b=None, c=None):
# do a G1 even for rapid moves
iso_modal.CreatorIsoModal.feed(self, x, y, z)
def feed(self, x=None, y=None, z=None, a = None, b = None, c = None):
iso_modal.CreatorIsoModal.feed(self, x, y, z)
################################################################################
nc.creator = CreatorPrintbot()

View File

@@ -0,0 +1,17 @@
import iso_read as iso
import sys
# based on the iso reader
class Parser(iso.Parser):
def __init__(self, writer):
iso.Parser.__init__(self, writer)
def ParseWord(self, word):
iso.Parser.ParseWord(self, word)
if (word == 'M103'):
self.path_col = "rapid"
self.col = "rapid"
elif (word == 'M101'):
self.path_col = "feed"
self.col = "feed"

View File

@@ -0,0 +1,300 @@
import nc
units = 1.0
class Redirector(nc.Creator):
def __init__(self, original):
nc.Creator.__init__(self)
self.original = original
self.x = None
self.y = None
self.z = None
if original.x != None: self.x = original.x * units
if original.y != None: self.y = original.y * units
if original.z != None: self.z = original.z * units
self.imperial = False
def cut_path(self):
pass
############################################################################
## Programs
def write(self, s):
self.original.write(s)
def output_fixture(self):
self.original.output_fixture()
def increment_fixture(self):
self.original.increment_fixture()
def get_fixture(self):
return self.original.get_fixture()
def set_fixture(self, fixture):
self.original.set_fixture(fixture)
def program_begin(self, id, name=''):
self.cut_path()
self.original.program_begin(id, name)
def program_stop(self, optional=False):
self.cut_path()
self.original.program_stop(optional)
def program_end(self):
self.cut_path()
self.original.program_end()
def flush_nc(self):
self.cut_path()
self.original.flush_nc()
############################################################################
## Subprograms
def sub_begin(self, id, name=None):
self.cut_path()
self.original.sub_begin(id, name)
def sub_call(self, id):
self.cut_path()
self.original.sub_call(id)
def sub_end(self):
self.cut_path()
self.original.sub_end()
def disable_output(self):
self.original.disable_output()
def enable_output(self):
self.original.enable_output()
############################################################################
## Settings
def imperial(self):
self.cut_path()
self.imperial = True
self.original.imperial()
def metric(self):
self.cut_path()
self.original.metric()
def absolute(self):
self.cut_path()
self.original.absolute()
def incremental(self):
self.cut_path()
self.original.incremental()
def polar(self, on=True):
self.cut_path()
self.original.polar(on)
def set_plane(self, plane):
self.cut_path()
self.original.set_plane(plane)
def set_temporary_origin(self, x=None, y=None, z=None, a=None, b=None, c=None):
self.cut_path()
self.original.set_temporary_origin(x,y,z,a,b,c)
def remove_temporary_origin(self):
self.cut_path()
self.original.remove_temporary_origin()
############################################################################
## Tools
def tool_change(self, id):
self.cut_path()
self.original.tool_change(id)
def tool_defn(self, id, name='', params=None):
self.cut_path()
self.original.tool_defn(id, name, params)
def offset_radius(self, id, radius=None):
self.cut_path()
self.original.offset_radius(id, radius)
def offset_length(self, id, length=None):
self.cut_path()
self.original.offset_length(id, length)
############################################################################
## Datums
def datum_shift(self, x=None, y=None, z=None, a=None, b=None, c=None):
self.cut_path()
self.original.datum_shift(x, y, z, a, b, c)
def datum_set(self, x=None, y=None, z=None, a=None, b=None, c=None):
self.cut_path()
self.original.datum_set(x, y, z, a, b, c)
def workplane(self, id):
self.cut_path()
self.original.workplane(id)
############################################################################
## Rates + Modes
def feedrate(self, f):
self.cut_path()
self.original.feedrate(f)
def feedrate_hv(self, fh, fv):
self.cut_path()
self.original.feedrate_hv(fh, fv)
def spindle(self, s, clockwise=True):
self.cut_path()
self.original.spindle(s, clockwise)
def coolant(self, mode=0):
self.cut_path()
self.original.coolant(mode)
def gearrange(self, gear=0):
self.cut_path()
self.original.gearrange(gear)
############################################################################
## Moves
def rapid(self, x=None, y=None, z=None, a=None, b=None, c=None):
self.cut_path()
self.original.rapid(x, y, z, a, b, c)
if x != None: self.x = x * units
if y != None: self.y = y * units
if z != None: self.z = z * units
def cut_path(self):
pass
def z2(self, z):
return z
def feed(self, x=None, y=None, z=None, a = None, b = None, c = None):
px = self.x
py = self.y
pz = self.z
if x != None: self.x = x * units
if y != None: self.y = y * units
if z != None: self.z = z * units
if self.x == None or self.y == None or self.z == None:
self.cut_path()
self.original.feed(x, y, z)
return
if px == self.x and py == self.y:
# z move only
self.cut_path()
self.original.feed(self.x/units, self.y/units, self.z2(self.z)/units)
return
def arc(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None, ccw = True):
if self.x == None or self.y == None or self.z == None:
raise "first attached move can't be an arc"
px = self.x
py = self.y
pz = self.z
if x != None: self.x = x * units
if y != None: self.y = y * units
if z != None: self.z = z * units
def arc_cw(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None):
self.arc(x, y, z, i, j, k, r, False)
def arc_ccw(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None):
self.arc(x, y, z, i, j, k, r, True)
def dwell(self, t):
self.cut_path()
self.original.dwell(t)
def rapid_home(self, x=None, y=None, z=None, a=None, b=None, c=None):
self.cut_path()
self.original.rapid_home(x, y, z, a, b, c)
def rapid_unhome(self):
self.cut_path()
self.original.rapid_unhome()
############################################################################
## Cutter radius compensation
def use_CRC(self):
return self.original.use_CRC()
def start_CRC(self, left = True, radius = 0.0):
self.cut_path()
self.original.start_CRC(left, radius)
def end_CRC(self):
self.cut_path()
self.original.end_CRC()
############################################################################
## Cycles
def pattern(self):
self.cut_path()
self.original.pattern()
def pattern_uses_subroutine(self):
return self.original.pattern_uses_subroutine()
def pocket(self):
self.cut_path()
self.original.pocket()
def profile(self):
self.cut_path()
self.original.profile()
def circular_pocket(self, x=None, y=None, ToolDiameter=None, HoleDiameter=None, ClearanceHeight=None, StartHeight=None, MaterialTop=None, FeedRate=None, SpindleRPM=None, HoleDepth=None, DepthOfCut=None, StepOver=None ):
self.cut_path()
self.circular_pocket(x, y, ToolDiameter, HoleDiameter, ClearanceHeight, StartHeight, MaterialTop, FeedRate, SpindleRPM, HoleDepth, DepthOfCut, StepOver)
def drill(self, x=None, y=None, dwell=None, depthparams = None, retract_mode=None, spindle_mode=None, internal_coolant_on=None, rapid_to_clearance=None):
self.cut_path()
self.original.drill(x, y, dwell, depthparams, spindle_mode, internal_coolant_on, rapid_to_clearance)
# argument list adapted for compatibility with Tapping module
# wild guess - I'm unsure about the purpose of this file and wether this works -haberlerm
def tap(self, x=None, y=None, z=None, zretract=None, depth=None, standoff=None, dwell_bottom=None, pitch=None, stoppos=None, spin_in=None, spin_out=None, tap_mode=None, direction=None):
self.cut_path()
self.original.tap( x, y, self.z2(z), self.z2(zretract), depth, standoff, dwell_bottom, pitch, stoppos, spin_in, spin_out, tap_mode, direction)
def bore(self, x=None, y=None, z=None, zretract=None, depth=None, standoff=None, dwell_bottom=None, feed_in=None, feed_out=None, stoppos=None, shift_back=None, shift_right=None, backbore=False, stop=False):
self.cut_path()
self.original.bore(x, y, self.z2(z), self.z2(zretract), depth, standoff, dwell_Bottom, feed_in, feed_out, stoppos, shift_back, shift_right, backbore, stop)
def end_canned_cycle(self):
self.original.end_canned_cycle()
############################################################################
## Misc
def comment(self, text):
self.cut_path()
self.original.comment(text)
def variable(self, id):
self.cut_path()
self.original.variable(id)
def variable_set(self, id, value):
self.cut_path()
self.original.variable_set(id, value)
def set_ocl_cutter(self, cutter):
self.original.set_ocl_cutter(cutter)

View File

@@ -0,0 +1,553 @@
# -*- coding: utf-8 -*-
################################################################################
# iso.py
#
# Simple ISO NC code creator
#
# Hirutso Enni, 2009-01-13
import nc
import math
import circular_pocket as circular
################################################################################
class Creator(nc.Creator):
def __init__(self):
nc.Creator.__init__(self)
self.a = 0
self.b = 0
self.c = 0
self.f = ''
self.fh = None
self.fv = None
self.fhv = False
self.g = ''
self.i = 0
self.j = 0
self.k = 0
self.m = []
self.n = 10
self.r = 0
self.s = ''
self.t = None
self.x = 0
self.y = 0
self.z = 500
self.x1=0
self.x2=0
self.y1=0
self.y2=0
self.SPACE=' '
self.fmt = self.FORMAT_MM()
pass
############################################################################
## Internals
def FORMAT_IN(self): return('%.5f')
def FORMAT_MM(self): return('%.3f')
def COMMENT(self,comment): return( ('(%s)' % comment ) )
def write_feedrate(self):
#self.write(self.f)
self.f = ''
def write_preps(self):
#self.write(self.g)
self.g = ''
def write_misc(self):
#if (len(self.m)) : self.write(self.m.pop())
pass
def write_blocknum(self):
#self.write(iso.BLOCK % self.n)
#self.write(iso.SPACE)
#self.n += 10
pass
def write_spindle(self):
#self.write(self.s)
#self.s = ''
pass
############################################################################
## Programs
def program_begin(self, id, name=''):
#self.write((iso.PROGRAM % id) + iso.SPACE + (iso.COMMENT % name))
#self.write("// program v jazyku"+self.SPACE+"REZ\nMA 0.0000 , 0.0000\n")
self.write("// program v jazyku"+self.SPACE+"REZ\nGO_LEFT\nMA 0.0000 , 0.0000\n")
#self.write('\n')
def program_stop(self, optional=False):
#self.write_blocknum()
#if (optional) : self.write(iso.STOP_OPTIONAL + '\n')
#else : self.write(iso.STOP + '\n')
self.write("// stop programu v jazyku REZ\n")
def program_end(self):
#self.write_blocknum()
#self.write(iso.PROGRAM_END + '\n')
self.write('PL_OFF \n')
self.write('PARK \n')
self.write('FS \n')
self.write('MA 0.0000 , 0.0000\n')
self.write("// koniec programu v jazyku REZ\n")
#self.write(iso.PROGRAM_END + '\n')
def flush_nc(self):
#self.write_blocknum()
self.write_preps()
self.write_misc()
#self.write('\n')
############################################################################
## Subprograms
def sub_begin(self, id, name=''):
#self.write((iso.PROGRAM % id) + iso.SPACE + (iso.COMMENT % name))
#self.write('\n')
pass
def sub_call(self, id):
#self.write_blocknum()
#self.write((iso.SUBPROG_CALL % id) + '\n')
#self.write('\n')
pass
def sub_end(self):
#self.write_blocknum()
#self.write(iso.SUBPROG_END + '\n')
#self.write('\n')
pass
############################################################################
## Settings
def imperial(self):
#self.g += iso.IMPERIAL
#self.fmt = iso.FORMAT_IN
#self.write('\n')
pass
def metric(self):
#self.g += iso.METRIC
#self.fmt = iso.FORMAT_MM
#self.write('\n')
pass
def absolute(self):
#self.g += iso.ABSOLUTE
#self.write('\n')
pass
def incremental(self):
#self.g += iso.INCREMENTAL
#self.write('\n')
pass
def polar(self, on=True):
#if (on) : self.g += iso.POLAR_ON
#else : self.g += iso.POLAR_OFF
#self.write('\n')
pass
def set_plane(self, plane):
#if (plane == 0) : self.g += iso.PLANE_XY
#elif (plane == 1) : self.g += iso.PLANE_XZ
#elif (plane == 2) : self.g += iso.PLANE_YZ
#self.write('\n')
pass
############################################################################
## Tools
def tool_change(self, id):
#self.write_blocknum()
#self.write((iso.TOOL % id) + '\n')
#self.write('\n')
pass
def tool_defn(self, id, name='', params=None):
pass
def offset_radius(self, id, radius=None):
pass
def offset_length(self, id, length=None):
pass
############################################################################
## Datums
def datum_shift(self, x=None, y=None, z=None, a=None, b=None, c=None):
pass
def datum_set(self, x=None, y=None, z=None, a=None, b=None, c=None):
pass
# This is the coordinate system we're using. G54->G59, G59.1, G59.2, G59.3
# These are selected by values from 1 to 9 inclusive.
def workplane(self, id):
#if ((id >= 1) and (id <= 6)):
# self.g += iso.WORKPLANE % (id + iso.WORKPLANE_BASE)
#if ((id >= 7) and (id <= 9)):
# self.g += ((iso.WORKPLANE % (6 + iso.WORKPLANE_BASE)) + ('.%i' % (id - 6)))
pass
############################################################################
## Rates + Modes
def feedrate(self, f):
#self.f = iso.FEEDRATE + (self.fmt % f)
#self.fhv = False
pass
def feedrate_hv(self, fh, fv):
#self.fh = fh
#self.fv = fv
#self.fhv = True
pass
def calc_feedrate_hv(self, h, v):
#l = math.sqrt(h*h+v*v)
#if (h == 0) : self.f = iso.FEEDRATE + (self.fmt % self.fv)
#elif (v == 0) : self.f = iso.FEEDRATE + (self.fmt % self.fh)
#else:
# self.f = iso.FEEDRATE + (self.fmt % (self.fh * l * min([1/h, 1/v])))
pass
def spindle(self, s, clockwise):
#if s < 0: clockwise = not clockwise
#s = abs(s)
#self.s = iso.SPINDLE % s
#if clockwise:
# self.s = self.s + iso.SPINDLE_CW
#else:
# self.s = self.s + iso.SPINDLE_CCW
pass
def coolant(self, mode=0):
#if (mode <= 0) : self.m.append(iso.COOLANT_OFF)
#elif (mode == 1) : self.m.append(iso.COOLANT_MIST)
#elif (mode == 2) : self.m.append(iso.COOLANT_FLOOD)
pass
def gearrange(self, gear=0):
#if (gear <= 0) : self.m.append(iso.GEAR_OFF)
#elif (gear <= 4) : self.m.append(iso.GEAR % (gear + GEAR_BASE))
pass
############################################################################
## Moves
#def rapid(self, x=None, y=None, z=None, a=None, b=None, c=None):
def rapid(self, x=0.0000, y=0.0000, z=0.0000, a=0.0000, b=0.0000, c=0.0000,how=False):
#self.write_blocknum()
if (x == None):
if (y == None):
return
print 'rychlopsuv'
print x
print y
print z
print a
print b
print c
self.write('PL_OFF\n')
self.write('PARK\n')
self.write('FS\n')
self.write('MA ')
#self.write_preps()
#if (x != None):
# dx = x - self.x
# self.write(iso.X + (self.fmt % x))
# self.x = x
#if (y != None):
# dy = y - self.y
# self.write(iso.Y + (self.fmt % y))
# self.y = y
#if (z != None):
# dz = z - self.z
# self.write(iso.Z + (self.fmt % z))
# self.z = z
#if (a != None) : self.write(iso.A + (iso.FORMAT_ANG % a))
#if (b != None) : self.write(iso.B + (iso.FORMAT_ANG % b))
#if (c != None) : self.write(iso.C + (iso.FORMAT_ANG % c))
#self.write_spindle()
#self.write_misc()
self.write((' %.4f' %x))
#self.write(('%f' %x) )
self.write(' , ')
self.write((' %.4f' %y))
self.write('\n')
self.write('SS\n')
self.write('AD_W\n')
self.write('PL_ON')
self.write('\n')
self.x=x
self.y=y
def feed(self, x=0.0000, y=0.0000, z=0.0000,how=False):
if self.same_xyz(x, y, z):
return
if (x == None):
if (y == None):
return
print 'MA rez'
print x
print y
print z
#self.write_blocknum()
#self.write(iso.FEED)
#self.write_preps()
#dx = dy = dz = 0
#if (x != None):
# dx = x - self.x
# self.write(iso.X + (self.fmt % x))
# self.x = x
#if (y != None):
# dy = y - self.y
# self.write(iso.Y + (self.fmt % y))
# self.y = y
#if (z != None):
# dz = z - self.z
# self.write(iso.Z + (self.fmt % z))
# self.z = z
#if (self.fhv) : self.calc_feedrate_hv(math.sqrt(dx*dx+dy*dy), math.fabs(dz))
#self.write_feedrate()
#self.write_spindle()
#self.write_misc()
self.write('MA ')
self.write((' %.4f' %x))
#self.write(('%f' %x) )
self.write(' , ')
self.write((' %.4f' %y))
self.write('\n')
self.x=x
self.y=y
def same_xyz(self, x=None, y=None, z=None):
if (x != None):
if (self.fmt % x) != (self.fmt % self.x):
return False
if (y != None):
if (self.fmt % y) != (self.fmt % self.y):
return False
if (z != None):
if (self.fmt % z) != (self.fmt % self.z):
return False
return True
def arc(self, cw, x=0.0000, y=0.0000, z=0.0000, i=0.0000, j=0.0000, k=0.0000, r=0.0000):
if self.same_xyz(x, y, z): return
if (x == None):
if (y == None):
return
#self.write_blocknum()
print 'ARC rez'
print x
print y
print z
print i
print j
print k
print r
self.write('C ')
# if cw: self.write(iso.ARC_CW)
# else: self.write(iso.ARC_CCW)
# self.write_preps()
#if (x != None):
# self.write(iso.X + (self.fmt % x))
# self.x = x
#if (y != None):
# self.write(iso.Y + (self.fmt % y))
# self.y = y
#if (z != None):
# self.write(iso.Z + (self.fmt % z))
# self.z = z
#if (i != None) : self.write(iso.CENTRE_X + (self.fmt % i))
#if (j != None) : self.write(iso.CENTRE_Y + (self.fmt % j))
#if (k != None) : self.write(iso.CENTRE_Z + (self.fmt % k))
#if (r != None) : self.write(iso.RADIUS + (self.fmt % r))
# use horizontal feed rate
#if (self.fhv) : self.calc_feedrate_hv(1, 0)
#self.write_feedrate()
#self.write_spindle()
#self.write_misc()
self.write((' %.4f' %(self.x + i)))
#self.write(('%f' %x) )
self.write(' , ')
self.write((' %.4f' %(self.y + j)))
self.write(' , ')
angle=0.0000
self.x1=-i
self.y1=-j
self.x2=x-(self.x+i)
self.y2=y-(self.y+j)
dx=self.x1*self.x2
dy=self.y1*self.y2
ssucin=dx+dy
r=math.sqrt((i*i)+(j*j))
#dx=i*(x-(self.x + i))
#dy=j*(y-(self.y + j))
#ssucin=dx+dy
#r=math.sqrt((i*i)+(j*j))
ratio=ssucin/(r*r)
angle= math.acos(ratio) * 180 / math.pi
print 'angle'
print angle
# while(angle>=90.0001):
# if(cw): self.write((' -90.0000\n' ))
# else: self.write((' 90.0000\n'))
#self.write(('90.0000\n' ))
# self.write('C ')
# self.write((' %.4f' %( self.x + i) ))
# self.write(' , ')
# self.write((' %.4f' %( self.y + j)))
# self.write(' , ')
# angle-=90
if(cw): self.write((' %.4f' %(-angle)))
else: self.write((' %.4f' %(angle)))
#self.write((', %.4f' % ))
self.write('\n')
self.x=x
self.y=y
self.write('// stred')
self.write((' %f' %i))
self.write(' ')
self.write( (' %f' %j))
self.write('\n')
self.write('// koniec')
self.write((' %f' %self.x))
self.write(' ')
self.write( (' %f' %self.y))
self.write('\n')
def arc_cw(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None):
self.arc(True, x, y, z, i, j, k, r)
def arc_ccw(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None):
self.arc(False, x, y, z, i, j, k, r)
def dwell(self, t):
self.write_blocknum()
self.write_preps()
self.write(iso.DWELL + (iso.TIME % t))
self.write_misc()
self.write('\n')
def rapid_home(self, x=None, y=None, z=None, a=None, b=None, c=None):
pass
def rapid_unhome(self):
pass
############################################################################
## Cycles
def pattern(self):
pass
def pocket(self):
pass
def profile(self):
pass
def circular_pocket(self, x=None, y=None, ToolDiameter=None, HoleDiameter=None, ClearanceHeight=None, StartHeight=None, MaterialTop=None, FeedRate=None, SpindleRPM=None, HoleDepth=None, DepthOfCut=None, StepOver=None ):
self.write_preps()
circular.pocket.block_number = self.n
(self.g_code, self.n) = circular.pocket.GeneratePath( x,y, ToolDiameter, HoleDiameter, ClearanceHeight, StartHeight, MaterialTop, FeedRate, SpindleRPM, HoleDepth, DepthOfCut, StepOver )
self.write(self.g_code)
# The drill routine supports drilling (G81), drilling with dwell (G82) and peck drilling (G83).
# The x,y,z values are INITIAL locations (above the hole to be made. This is in contrast to
# the Z value used in the G8[1-3] cycles where the Z value is that of the BOTTOM of the hole.
# Instead, this routine combines the Z value and the depth value to determine the bottom of
# the hole.
#
# The standoff value is the distance up from the 'z' value (normally just above the surface) where the bit retracts
# to in order to clear the swarf. This combines with 'z' to form the 'R' value in the G8[1-3] cycles.
#
# The peck_depth value is the incremental depth (Q value) that tells the peck drilling
# cycle how deep to go on each peck until the full depth is achieved.
#
# NOTE: This routine forces the mode to absolute mode so that the values passed into
# the G8[1-3] cycles make sense. I don't know how to find the mode to revert it so I won't
# revert it. I must set the mode so that I can be sure the values I'm passing in make
# sense to the end-machine.
#
def drill(self, x=None, y=None, dwell=None, depthparams = None, retract_mode=None, spindle_mode=None, internal_coolant_on=None, rapid_to_clearance=None):
if (standoff == None):
# This is a bad thing. All the drilling cycles need a retraction (and starting) height.
return
if (z == None): return # We need a Z value as well. This input parameter represents the top of the hole
self.write_blocknum()
self.write_preps()
if (peck_depth != 0):
# We're pecking. Let's find a tree.
self.write(iso.PECK_DRILL + iso.SPACE + iso.PECK_DEPTH + (self.fmt % peck_depth ))
else:
# We're either just drilling or drilling with dwell.
if (dwell == 0):
# We're just drilling.
self.write(iso.DRILL + iso.SPACE)
else:
# We're drilling with dwell.
self.write(iso.DRILL_WITH_DWELL + (iso.FORMAT_DWELL % dwell) + iso.SPACE)
# Set the retraction point to the 'standoff' distance above the starting z height.
retract_height = z + standoff
#self.write(iso.RETRACT + (self.fmt % retract_height))
if (x != None):
dx = x - self.x
self.write(iso.X + (self.fmt % x) + iso.SPACE)
self.x = x
if (y != None):
dy = y - self.y
self.write(iso.Y + (self.fmt % y) + iso.SPACE)
self.y = y
dz = (z + standoff) - self.z
# In the end, we will be standoff distance above the z value passed in.
self.write(iso.Z + (self.fmt % (z - depth)) + iso.SPACE) # This is the 'z' value for the bottom of the hole.
self.z = (z + standoff) # We want to remember where z is at the end (at the top of the hole)
self.write(iso.RETRACT + (self.fmt % retract_height))
self.write_spindle()
self.write_misc()
self.write('\n')
# def tap(self, x=None, y=None, z=None, zretract=None, depth=None, standoff=None, dwell_bottom=None, pitch=None, stoppos=None, spin_in=None, spin_out=None):
# pass
# argument list adapted for compatibility with Tapping module
def tap(self, x=None, y=None, z=None, zretract=None, depth=None, standoff=None, dwell_bottom=None, pitch=None, stoppos=None, spin_in=None, spin_out=None, tap_mode=None, direction=None):
pass
def bore(self, x=None, y=None, z=None, zretract=None, depth=None, standoff=None, dwell_bottom=None, feed_in=None, feed_out=None, stoppos=None, shift_back=None, shift_right=None, backbore=False, stop=False):
pass
############################################################################
## Misc
def comment(self, text):
self.write('// ' + (self.COMMENT( text)) + '\n')
def variable(self, id):
return (iso.VARIABLE % id)
def variable_set(self, id, value):
self.write_blocknum()
self.write((iso.VARIABLE % id) + (iso.VARIABLE_SET % value) + '\n')
################################################################################
nc.creator = Creator()

View File

@@ -0,0 +1,291 @@
# -*- coding: utf-8 -*-
################################################################################
# iso_.py
#
import nc_read as nc
import re
import sys
import math
################################################################################
class Parser(nc.Parser):
def __init__(self, writer):
nc.Parser.__init__(self, writer)
#self.pattern_main = re.compile('(\s+|\w(?:[+])?\d*(?:\.\d*)?|\w\#\d+|\(.*?\)|\#\d+\=(?:[+])?\d*(?:\.\d*)?)')
#rada
self.pattern_main = re.compile(r'(\s+|,|-?\w\+?\d*(?:\.\d*)?|\w#\d+|\(.*?\)|#\d+=\+?\d*(?:\.\d*)?)')
#self.pattern_main = re.compile('\s+\w')
#self.pattern_main = re.compile('(\s+|\w(?:[+])?[+-\w]\d*(?:\.\d*)?|\w\#[+-\w]\d+|\(.*?\)|[\#[+-\w]\d+\=(?:[+])?[+-\w]\d*(?:\.\d*)?)')
#self.pattern_main = re.compile('\s\w[\S]\w,\w[+-\w]\d*\w,\w[+-\w]\d*\w,\w[+-\w]\d*')
#self.pattern_main = re.compile('(\s|\w(?:)?\d*(?:\.\d*)?|\w\#\d+|\(.*?\)|\#\d+\=(?:)?\d*(?:\.\d*)?)')
#self.pattern_main = re.compile(' ')
self.a = 0
self.b = 0
self.c = 0
self.f = 0
self.i = 0
self.j = 0
self.k = 0
self.p = 0
self.q = 0
self.r = 0
self.s = 0
self.x = 0
self.y = 0
self.z = 500
self.FS = 1
self.endx=0
self.endy=0
self.startx=0
self.starty=0
self.x1=0
self.y1=0
self.dy=0
self.dx=0
self.angle=0
self.SPACE = ' '
def add_text(self, s, col=None):
s.replace('&', '&amp;')
s.replace('"', '&quot;')
s.replace('<', '&lt;')
s.replace('>', '&gt;')
s+=self.SPACE+'\n'
if (col != None) : self.file_out.write('\t\t<text col="'+col+'">'+s+' </text>\n')
else : self.file_out.write('\t\t<text>'+s+' </text>\n')
#def add_text(self, s, col=None):
# if (col != None) : self.file_out.write('\t\t<text col="'+col+'">'+s+'</text>\n')
# else : self.file_out.write('\t\t<text>'+s+'</text>\n')
def Parse(self, name, oname=None):
self.files_open(name,oname)
while (self.readline()):
self.begin_ncblock()
move = False;
arc = 0;
path_col = None
col=None
if(self.line[0]=='C'): col = "axis"
if(self.line[0]=='M' and self.line[1]=='A'): col = "feed"
if (self.line[0] == "/" and self.line[1] == "/") : col = "comment"
if (self.FS==1 and not (self.line[0]=='S' and self.line[1]=='S') and col=="feed" ): col="rapid"
self.add_text(self.line, col)
#words = self.pattern_main.findall(self.line)
words=self.line.split()
#print self.line
#print ' AAAA '
words[0]=words[0]+self.SPACE
print words
for word in words:
col = None
#if (word[0] == 'A' or word[0] == 'a'):
# col = "axis"
# self.a = eval(word[1:])
# move = True
#elif (word[0] == 'B' or word[0] == 'b'):
# col = "axis"
# self.b = eval(word[1:])
# move = True
if (word == ('C'+self.SPACE)):
#print words
col = "axis"
self.startx=self.x
self.starty=self.y
words[0]=words[0]+self.SPACE
words[2]=self.SPACE+words[2]+self.SPACE
words[4]=self.SPACE+words[4]+self.SPACE
#print 'x,y'
#print self.x
#print self.y
#self.x1=self.x-eval(words[1])
self.x1=self.x-eval(words[1])
#j=self.y-eval(words[5])
#self.y1=self.y-eval(words[3])
self.y1=self.y-eval(words[3])
#self.c = eval(word[1:])
#print 'self x,y'
#print self.x1
#print self.y1
self.dx=(self.x1)*1
self.dy=(self.y1)*0
#print 'x1'
#print self.x1
#print 'y1'
#print self.y1
ssucin=self.dx+self.dy
r=math.sqrt(((self.x1)*(self.x1))+((self.y1)*(self.y1)))
#print 'skalarny sucin'
#print ssucin
#print 'r'
#print r
if (ssucin!=0):
ratio=ssucin/(r*1)
#print 'ratio'
#print ratio
angle= (math.acos(ratio) * 180 / math.pi)
if(self.y1<0):angle=360-angle
elif (self.y1>0): angle=+90
elif (self.y1<0): angle=-90
else: angle=0
#print words[8]
#print 'angles'
#print angle
#if (i<0 and j<0): angle=180+angle
#if (i<0 and j>0): angle=180-angle
#if (j>0): angle=-angle
#print ('reverzacia')
#angle= angle+ eval(words[8])
#print angle
self.angle=+ angle+ eval(words[5])
#print self.angle
#if(angle>180): angle=360-angle
angle=self.angle*math.pi/180
#print eval(words[8])
self.endx=eval(words[1])+(r*math.cos(angle))
#j=eval(words[5])+(r*math.sin(angle))
self.endy=eval(words[3])+(r*math.sin(angle))
self.x=self.endx
self.y=self.endy
path_col = "feed"
#arc=-eval(words[8])/math.fabs(eval(words[8]))
arc=eval(words[5])/math.fabs(eval(words[5]))
#if(arc==-1): arc=0
#arc=-1
#col = "feed"
move = True
elif (word == 'P' and words[1]=='L' and words[4]=='F'):
self.FS=1
elif (word == 'P' and words[1]=='L' and words[4]=='N'):
self.FS=0
elif (word == ('FS'+self.SPACE)):
self.FS=1
elif (word == ('SS'+self.SPACE)):
self.FS=0
elif (word == ('MA'+self.SPACE)):
words[2]=self.SPACE+words[2]+self.SPACE
if (self.FS==1):
path_col = "rapid"
col = "rapid"
else:
path_col = "feed"
col = "feed"
self.x=eval(words[1])
#self.y=eval(words[6])
self.y=eval(words[3])
move=True
#elif (word == 'G1' or word == 'G01' or word == 'g1' or word == 'g01'):
# path_col = "feed"
# col = "feed"
#elif (word == 'G2' or word == 'G02' or word == 'g2' or word == 'g02' or word == 'G12' or word == 'g12'):
# path_col = "feed"
# col = "feed"
# arc = -1
#elif (word == 'G3' or word == 'G03' or word == 'g3' or word == 'g03' or word == 'G13' or word == 'g13'):
# path_col = "feed"
# col = "feed"
# arc = +1
#elif (word == 'G10' or word == 'g10'):
# move = False
#elif (word == 'L1' or word == 'l1'):
# move = False
#elif (word == 'G20'):
# col = "prep"
# self.set_mode(units=25.4)
#elif (word == 'G21'):
# col = "prep"
# self.set_mode(units=1.0)
#elif (word == 'G81' or word == 'g81'):
# path_col = "feed"
# col = "feed"
#elif (word == 'G82' or word == 'g82'):
# path_col = "feed"
# col = "feed"
#elif (word == 'G83' or word == 'g83'):
# path_col = "feed"
# col = "feed"
#elif (word[0] == 'G') : col = "prep"
#elif (word[0] == 'I' or word[0] == 'i'):
# col = "axis"
# self.i = eval(word[1:])
# move = True
#elif (word[0] == 'J' or word[0] == 'j'):
# col = "axis"
# self.j = eval(word[1:])
# move = True
#elif (word[0] == 'K' or word[0] == 'k'):
# col = "axis"
# self.k = eval(word[1:])
# move = True
#elif (word[0] == 'M') : col = "misc"
#elif (word[0] == 'N') : col = "blocknum"
#elif (word[0] == 'O') : col = "program"
#elif (word[0] == 'P' or word[0] == 'p'):
# col = "axis"
# self.p = eval(word[1:])
# move = True
#elif (word[0] == 'Q' or word[0] == 'q'):
# col = "axis"
# self.q = eval(word[1:])
# move = True
#elif (word[0] == 'R' or word[0] == 'r'):
# col = "axis"
# self.r = eval(word[1:])
# move = True
#elif (word[0] == 'S' or word[0zypp] == 's'):
# col = "axis"
# self.s = eval(word[1:])
# move = True
#elif (word[0] == 'T') : col = "tool"
#elif (word[0] == 'X' or word[0] == 'x'):
# col = "axis"
# = eval(word[1:])
# move = True
#elif (word[0] == 'Y' or word[0] == 'y'):
# col = "axis"
# self.y = eval(word[1:])
# move = True
#elif (word[0] == 'Z' or word[0] == 'z'):
# col = "axis"
# self.z = eval(word[1:])
# move = True
elif (word[0] == '(') : col = "comment"
elif (word[0] == '#') : col = "variable"
elif (words[0] == ("//"+self.SPACE)) : col = "comment"
elif (words[0] == ("/*"+self.SPACE)) : col = "comment"
#self.add_text(word, col)
if (move):
self.begin_path(path_col)
if (arc) :
#self.add_arc(self.x, self.y, 0.0000, self.i, self.j, 0.0000, arc)
#self.add_arc(self.i, self.j, 0.0000, eval(words[2])-self.x, eval(words[5])-self.y, 0.0000, arc)
#print ''
#print eval(words[2])-self.startx
#print eval(words[6])-self.starty
#self.add_arc(self.endx, self.endy, 0.0000, eval(words[1])-self.startx, eval(words[3])-self.starty, 0.0000, arc)
print arc
self.add_arc(self.endx, self.endy, 0.0000,eval(words[1])-self.startx, eval(words[3])-self.starty, 0.0000,0.0000, arc)
#self.add_arc(self.x, self.y, 0.0000, self.i, self.j, 0.0000, arc)
#self.x=self.i
#self.y=self.j
else :
self.add_line(self.x, self.y)
self.end_path()
self.end_ncblock()
self.files_close()

View File

@@ -0,0 +1,31 @@
import nc
import iso_modal
import math
################################################################################
class Creator(iso_modal.Creator):
def __init__(self):
iso_modal.Creator.__init__(self)
self.arc_centre_positive = True
self.drillExpanded = True
self.can_do_helical_arcs = False
self.fmt.number_of_decimal_places = 2
def tool_defn(self, id, name='', params=None):
pass
def dwell(self, t):
# to do, find out what dwell is on this machine
pass
def metric(self):
iso_modal.Creator.metric(self)
self.fmt.number_of_decimal_places = 2
def SPACE(self):
return('')
################################################################################
nc.creator = Creator()

View File

@@ -0,0 +1,9 @@
import iso_read as iso
import sys
# use the iso reader, but with i_and_j_always_positive
class Parser(iso.Parser):
def __init__(self, writer):
iso.Parser.__init__(self, writer)
self.arc_centre_positive = True

View File

@@ -0,0 +1,22 @@
################################################################################
# siegkx1.py
#
# Post Processor for the Sieg KX1 machine
# It is just an ISO machine, but I don't want the tool definition lines
#
# Dan Heeks, 5th March 2009
import nc
import iso_modal
import math
################################################################################
class Creator(iso_modal.Creator):
def __init__(self):
iso_modal.Creator.__init__(self)
self.output_tool_definitions = False
################################################################################
nc.creator = Creator()

View File

@@ -0,0 +1,54 @@
################################################################################
# attach.py
#
# NC code creator for attaching Z coordinates to a surface
#
import recreator
import nc
swap = False
PUT_Y_VALUE_IN_A = 1
################################################################################
class Creator(recreator.Redirector):
def __init__(self, original, type, factor):
recreator.Redirector.__init__(self, original)
self.factor = factor
self.type = type
def feed(self, x=None, y=None, z=None, a=None, b=None, c=None):
if self.type == PUT_Y_VALUE_IN_A:
a = None
if y != None: a = y * self.factor
self.original.feed(x, None, z, a, b, c)
def rapid(self, x=None, y=None, z=None, a=None, b=None, c=None):
if self.type == PUT_Y_VALUE_IN_A:
a = None
if y != None: a = y * self.factor
self.original.rapid(x, None, z, a, b, c)
def arc(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None, ccw = True):
# to do
pass
################################################################################
def use_a_for_y(radius):
cancel_swap()
if radius < 0.001:
return
global swap
radians_factor = 1 / radius
factor = radians_factor * 180 / 3.1415926535897932384
nc.creator = Creator(nc.creator, PUT_Y_VALUE_IN_A, factor)
swap = True
def cancel_swap():
global swap
if swap:
nc.creator = nc.creator.original
swap = False

View File

@@ -0,0 +1,90 @@
################################################################################
# tnc151.py
#
# Post Processor for the Heidenhain TNC151 machine
#
import nc
import iso_modal
import math
################################################################################
class Creator(iso_modal.Creator):
def __init__(self):
iso_modal.Creator.__init__(self)
self.fmt.add_plus = True
self.fmt.add_trailing_zeros = True
self.f.fmt.add_plus = True
self.s.fmt.add_plus = True
self.n = 1
self.waiting_t = None
self.waiting_for_program_begin = False
######## Codes
def SPACE(self): return(' ')
def TOOL(self): return('T%i')
######## Overridden functions
def write_blocknum(self):
self.write(self.BLOCK() % self.n)
self.n += 1
def program_begin(self, id, name=''):
self.waiting_for_program_begin = True
def write_waiting_program_begin(self):
if self.waiting_for_program_begin == True:
self.write('% 123')
self.waiting_for_program_begin = False
def imperial(self):
self.write_waiting_program_begin()
self.write(' G70\n')
self.fmt.number_of_decimal_places = 4
def metric(self):
self.write_waiting_program_begin()
self.write(' G71\n')
self.fmt.number_of_decimal_places = 3
# no tool definition lines wanted
def tool_defn(self, id, name='', params=None):
pass
# no comments wanted
def comment(self, text):
pass
def spindle(self, s, clockwise):
iso_modal.Creator.spindle(self, s, clockwise)
self.write_waiting_tool_change()
def tool_change(self, id):
self.waiting_t = id
def write_waiting_tool_change(self):
if self.waiting_t:
if len(self.g_list) > 0:
self.write_blocknum()
for g in self.g_list:
self.write(self.SPACE() + g)
self.g_list = []
self.write('\n')
self.write_blocknum()
self.write(self.SPACE() + (self.TOOL() % self.waiting_t))
self.write_preps()
self.write_spindle()
self.write_misc()
self.write('\n')
self.t = self.waiting_t
self.waiting_t = None
def workplane(self, id):
pass
################################################################################
nc.creator = Creator()

View File

@@ -0,0 +1,270 @@
################################################################################
# transform.py
#
# NC code creator for attaching Z coordinates to a surface
#
import nc
import area
import recreator
transformed = False
class FeedXY:
def __init__(self, x, y):
self.x = x
self.y = y
def Do(self, original, matrix):
x,y,z = matrix.TransformedPoint(self.x, self.y, 0)
original.feed(x, y)
class FeedZ:
def __init__(self, z):
self.z = z
def Do(self, original, matrix):
original.feed(z = self.z)
class FeedXYZ:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def Do(self, original, matrix):
x,y,z = matrix.TransformedPoint(self.x, self.y, self.z)
original.feed(x,y,z)
class RapidXY:
def __init__(self, x, y):
self.x = x
self.y = y
def Do(self, original, matrix):
x,y,z = matrix.TransformedPoint(self.x, self.y, 0)
original.rapid(x, y)
class RapidZ:
def __init__(self, z):
self.z = z
def Do(self, original, matrix):
original.rapid(z = self.z)
class RapidXYZ:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def Do(self, original, matrix):
x,y,z = matrix.TransformedPoint(self.x, self.y, self.z)
original.rapid(x,y,z)
class Feedrate:
def __init__(self, h, v):
self.h = h
self.v = v
def Do(self, original, matrix):
original.feedrate_hv(self.h, self.v)
class Arc:
def __init__(self, x, y, z, i, j, ccw):
self.x = x
self.y = y
self.z = z
self.i = i
self.j = j
self.ccw = ccw
def Do(self, original, matrix):
x,y,z = matrix.TransformedPoint(self.x, self.y, self.z)
cx,cy,cz = matrix.TransformedPoint(original.x + self.i, original.y + self.j, self.z)
i = cx - original.x
j = cy - original.y
if self.ccw:
original.arc_ccw(x, y, z, i, j)
else:
original.arc_cw(x, y, z, i, j)
class Drill:
def __init__(self, x, y, dwell, depthparams, retract_mode, spindle_mode, internal_coolant_on, rapid_to_clearance):
self.x = x
self.y = y
self.dwell = dwell
self.depthparams = depthparams
self.retract_mode = retract_mode
self.spindle_mode = spindle_mode
self.internal_coolant_on = internal_coolant_on
self.rapid_to_clearance = rapid_to_clearance
def Do(self, original, matrix):
x,y,z = matrix.TransformedPoint(self.x, self.y, 0.0)
original.drill(x, y, self.dwell, self.depthparams, self.retract_mode, self.spindle_mode, self.internal_coolant_on, self.rapid_to_clearance)
class Absolute:
def __init__(self):
pass
def Do(self, original, matrix):
original.absolute()
class Incremental:
def __init__(self):
pass
def Do(self, original, matrix):
original.incremental()
class EndCannedCycle:
def __init__(self):
pass
def Do(self, original, matrix):
original.end_canned_cycle()
class Comment:
def __init__(self, text):
self.text = text
def Do(self, original, matrix):
original.comment(self.text)
################################################################################
matrix_fixtures = {}
class Creator(recreator.Redirector):
def __init__(self, original, matrix_list):
recreator.Redirector.__init__(self, original)
self.matrix_list = matrix_list
self.commands = []
# allocate fixtures to pattern positions
if self.pattern_uses_subroutine() == True:
save_fixture = self.get_fixture()
for matrix in self.matrix_list:
global matrix_fixtures
if (matrix in matrix_fixtures) == False:
matrix_fixtures[matrix] = self.get_fixture()
self.increment_fixture()
self.set_fixture(save_fixture)
def DoAllCommands(self):
subroutine_written = False
for matrix in self.matrix_list:
if len(self.commands) > 0:
if self.pattern_uses_subroutine() == True:
# set fixture
global matrix_fixtures
self.set_fixture(matrix_fixtures[matrix])
# rapid to the pattern point in x and y
x,y,z = matrix.TransformedPoint(0.0, 0.0, 0.0)
self.original.rapid(x, y)
subroutine_started = False
output_disabled = False
for command in self.commands:
if (output_disabled == False) and (self.pattern_uses_subroutine() == True):
# in main program do commands up to the first z move
cname = command.__class__.__name__
if cname == 'FeedZ' or cname == 'Drill':
if subroutine_written:
self.sub_call(None)
self.disable_output() # ignore all the other commands
output_disabled = True
else:
if subroutine_started == False:
self.sub_begin(None)
subroutine_started = True
self.incremental()
command.Do(self.original, matrix)
self.enable_output()
output_disabled = False
if subroutine_started:
self.absolute()
self.flush_nc()
self.sub_end()
subroutine_written = True
self.sub_call(None)
def tool_change(self, id):
if id != self.original.current_tool():
self.DoAllCommands()
self.commands = []
self.original.tool_change(id)
def feedrate(self, f):
self.commands.append(Feedrate(f, f))
def feedrate_hv(self, fh, fv):
self.commands.append(Feedrate(fh, fv))
def rapid(self, x=None, y=None, z=None, a=None, b=None, c=None):
if x != None: self.x = x
if y != None: self.y = y
if z != None: self.z = z
if self.x == None and self.y == None and self.z == None:
return
if z == None:
self.commands.append(RapidXY(self.x, self.y))
elif x == None and y == None:
self.commands.append(RapidZ(self.z))
else:
self.commands.append(RapidXYZ(self.x, self.y, self.z))
def feed(self, x=None, y=None, z=None, a = None, b = None, c = None):
if x != None: self.x = x
if y != None: self.y = y
if z != None: self.z = z
if self.x == None and self.y == None and self.z == None:
return
if z == None:
self.commands.append(FeedXY(self.x, self.y))
elif x == None and y == None:
self.commands.append(FeedZ(self.z))
else:
self.commands.append(FeedXYZ(self.x, self.y, self.z))
def arc(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None, ccw = True):
if x != None: self.x = x
if y != None: self.y = y
if z != None: self.z = z
if self.x == None and self.y == None and self.z == None:
return
self.commands.append(Arc(self.x, self.y, self.z, i, j, ccw))
def drill(self, x=None, y=None, dwell=None, depthparams = None, retract_mode=None, spindle_mode=None, internal_coolant_on=None, rapid_to_clearance=None):
self.commands.append(Drill(x, y, dwell, depthparams, retract_mode, spindle_mode, internal_coolant_on, rapid_to_clearance))
def end_canned_cycle(self):
self.commands.append(EndCannedCycle())
# def absolute(self):
# self.commands.append(Absolute())
# def incremental(self):
# self.commands.append(Incremental())
def comment(self, text):
self.commands.append(Comment(text))
################################################################################
def transform_begin(matrix_list):
global transformed
if transformed == True:
transform_end()
nc.creator = Creator(nc.creator, matrix_list)
transformed = True
def transform_end():
global transformed
nc.creator.DoAllCommands()
nc.creator = nc.creator.original
transformed = False