Drilling handles multiple locations

Jog rates started
Automatically create default tool in new job.
This commit is contained in:
sliptonic 2016-08-16 08:53:33 -05:00 committed by Yorik van Havre
parent e790963a45
commit 2f04ea9586
20 changed files with 1941 additions and 224 deletions

View File

@ -5,6 +5,7 @@
<file>icons/Path-Compound.svg</file> <file>icons/Path-Compound.svg</file>
<file>icons/Path-Shape.svg</file> <file>icons/Path-Shape.svg</file>
<file>icons/Path-Profile.svg</file> <file>icons/Path-Profile.svg</file>
<file>icons/Path-Contour.svg</file>
<file>icons/Path-Pocket.svg</file> <file>icons/Path-Pocket.svg</file>
<file>icons/Path-Drilling.svg</file> <file>icons/Path-Drilling.svg</file>
<file>icons/Path-Job.svg</file> <file>icons/Path-Job.svg</file>

View File

@ -0,0 +1,565 @@
<?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 r13725"
sodipodi:docname="Path-Profile.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,41.188465,-8.5177184)"
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.7781745"
inkscape:cx="34.742778"
inkscape:cy="31.569873"
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="1920"
inkscape:window-height="1053"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<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 />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#008b00;stroke-width:7.83772373;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="M 47.244934,13.041648 38.27355,11.532207 c -1.462847,-0.245405 -3.091123,-0.08644 -4.656553,0.377436 -2.609051,0.77312 -5.06659,2.419881 -6.488655,4.518817 L 7.215204,45.770884 c -2.275305,3.358296 -0.955689,6.602055 2.945235,7.256469"
id="rect3083-0-3-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccsccc" />
<path
style="fill:#001748;fill-rule:nonzero;stroke:#000000;stroke-width:2.69342875;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker:none;filter-blend-mode:normal;filter-gaussianBlur-deviation:0;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 41.878715,34.330654 0.575831,27.30571 16.090909,-24.545455 0.363637,-25.545455 z"
id="path4899"
inkscape:connector-curvature="0" />
<path
style="fill:#001748;fill-rule:nonzero;stroke:#000000;stroke-width:2.69342875;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker:none;filter-blend-mode:normal;filter-gaussianBlur-deviation:0;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 18.515689,30.416682 -0.333871,31.219682 24.272728,0 -0.575831,-27.30571 z"
id="path4892"
inkscape:connector-curvature="0" />
<path
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#008b00;stroke-width:7.83772373;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 10.160439,53.027353 15.662892,2.766775 14.351542,2.41586 c 3.900924,0.654414 8.869902,-1.537955 11.145208,-4.896251 l 6.006956,-8.880001"
id="rect3083-0-3"
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.82336974;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 33.872593,7.732496 18.515689,30.416682 41.878715,34.330654 52.152296,19.197791 49.663299,10.388809 33.872593,7.732496 Z"
id="rect3083"
inkscape:connector-curvature="0" />
<path
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#008b00;stroke-width:7.83772373;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="M 26.439693,2.779375 6.5265548,32.121799 C 4.25125,35.480095 5.5708656,38.723854 9.4717895,39.378268 l 28.7030835,4.83172 c 3.900924,0.654414 8.869902,-1.537955 11.145208,-4.896251 l 6.006956,-8.880001"
id="rect3083-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
style="color:#000000;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-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 44.892106,2.9767791 0,17.4659099 c 0,0 0,1.310757 0,8.59375 l 17.34375,-8.59375 0,-1.90625 0,-15.5596599 z m 17.34375,22.5596599 -17.34375,8.5625 0,7.03125 17.34375,-8.59375 z m 0,12.09375 -14.5625,7.21875 5.9375,3.90625 8.625,-5.71875 z"
id="rect4417"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -106,30 +106,6 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="Tool">
<attribute name="icon">
<iconset resource="../Path.qrc">
<normaloff>:/icons/Path-LoadTool.svg</normaloff>:/icons/Path-LoadTool.svg</iconset>
</attribute>
<attribute name="label">
<string>Tool Settings</string>
</attribute>
<widget class="QWidget" name="widget" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>10</y>
<width>301</width>
<height>41</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QComboBox" name="cboToolController"/>
</item>
</layout>
</widget>
</widget>
<widget class="QWidget" name="Depths"> <widget class="QWidget" name="Depths">
<property name="geometry"> <property name="geometry">
<rect> <rect>

View File

@ -6,12 +6,12 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>398</width> <width>396</width>
<height>534</height> <height>517</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding"> <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
@ -19,7 +19,7 @@
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>0</width> <width>0</width>
<height>533</height> <height>400</height>
</size> </size>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -42,8 +42,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>380</width> <width>378</width>
<height>426</height> <height>409</height>
</rect> </rect>
</property> </property>
<attribute name="icon"> <attribute name="icon">
@ -56,6 +56,12 @@
<layout class="QGridLayout" name="gridLayout_4"> <layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QWidget" name="widget_2" native="true"> <widget class="QWidget" name="widget_2" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QFormLayout" name="formLayout"> <layout class="QFormLayout" name="formLayout">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_5"> <widget class="QLabel" name="label_5">
@ -110,7 +116,7 @@
<item row="6" column="0" colspan="2"> <item row="6" column="0" colspan="2">
<widget class="QListWidget" name="PathsList"> <widget class="QListWidget" name="PathsList">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
@ -132,11 +138,6 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="1" column="0">
<widget class="QWidget" name="widget" native="true">
<layout class="QGridLayout" name="gridLayout_2"/>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="Stock"> <widget class="QWidget" name="Stock">
@ -144,8 +145,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>380</width> <width>451</width>
<height>426</height> <height>349</height>
</rect> </rect>
</property> </property>
<attribute name="icon"> <attribute name="icon">
@ -214,8 +215,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>380</width> <width>451</width>
<height>426</height> <height>349</height>
</rect> </rect>
</property> </property>
<attribute name="icon"> <attribute name="icon">

View File

@ -6,22 +6,22 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>320</width> <width>308</width>
<height>503</height> <height>389</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Tool Control</string> <string>Tool Control</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QVBoxLayout" name="verticalLayout">
<item row="0" column="0"> <item>
<widget class="QLineEdit" name="tcoName"> <widget class="QLineEdit" name="tcoName">
<property name="readOnly"> <property name="readOnly">
<bool>true</bool> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item>
<widget class="QFrame" name="frame_2"> <widget class="QFrame" name="frame_2">
<property name="frameShape"> <property name="frameShape">
<enum>QFrame::StyledPanel</enum> <enum>QFrame::StyledPanel</enum>
@ -57,7 +57,7 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item>
<widget class="QFrame" name="frame"> <widget class="QFrame" name="frame">
<property name="frameShape"> <property name="frameShape">
<enum>QFrame::StyledPanel</enum> <enum>QFrame::StyledPanel</enum>
@ -86,10 +86,38 @@
<item row="1" column="1"> <item row="1" column="1">
<widget class="QLineEdit" name="vertFeed"/> <widget class="QLineEdit" name="vertFeed"/>
</item> </item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Horiz Rapid</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="horizRapid">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Vert Rapid</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="vertRapid">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item>
<widget class="QFrame" name="frame_3"> <widget class="QFrame" name="frame_3">
<property name="frameShape"> <property name="frameShape">
<enum>QFrame::StyledPanel</enum> <enum>QFrame::StyledPanel</enum>

View File

@ -67,13 +67,14 @@ class PathWorkbench (Workbench):
from PathScripts import PathRemote from PathScripts import PathRemote
from PathScripts import PathSanity from PathScripts import PathSanity
from PathScripts import DragknifeDressup from PathScripts import DragknifeDressup
from PathScripts import PathContour
# build commands list # build commands list
projcmdlist = ["Path_Job", "Path_Post", "Path_Inspect", "Path_Sanity"] projcmdlist = ["Path_Job", "Path_Post","Separator", "Path_Inspect", "Path_Sanity"]
toolcmdlist = ["Path_ToolLibraryEdit", "Path_LoadTool"] toolcmdlist = ["Path_ToolLibraryEdit", "Path_LoadTool"]
prepcmdlist = ["Path_Plane", "Path_Fixture", "Path_ToolLenOffset", "Path_Comment", prepcmdlist = ["Path_Plane", "Path_Fixture", "Path_ToolLenOffset", "Path_Comment",
"Path_Stop", "Path_FaceProfile", "Path_FacePocket", "Path_Custom", "Path_FromShape"] "Path_Stop", "Path_FaceProfile", "Path_FacePocket", "Path_Custom", "Path_FromShape"]
opcmdlist = ["Path_Profile", "Path_Pocket", opcmdlist = ["Path_Contour", "Path_Profile", "Path_Pocket",
"Path_Drilling", "Path_Engrave", "Path_Surfacing"] "Path_Drilling", "Path_Engrave", "Path_Surfacing"]
modcmdlist = ["Path_Copy", "Path_CompoundExtended", "Path_Array", modcmdlist = ["Path_Copy", "Path_CompoundExtended", "Path_Array",
"Path_SimpleCopy" ] "Path_SimpleCopy" ]

View File

@ -0,0 +1,635 @@
# -*- 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
import Path
import numpy
from FreeCAD import Vector
from PathScripts import PathUtils
from PathScripts.PathUtils import depth_params
if FreeCAD.GuiUp:
import FreeCADGui
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)
else:
def translate(ctxt, txt):
return txt
__title__ = "Path Contour Operation"
__author__ = "sliptonic (Brad Collette)"
__url__ = "http://www.freecadweb.org"
"""Path Contour object and FreeCAD command"""
class ObjectContour:
def __init__(self, obj):
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 Contour")
obj.addProperty("App::PropertyString", "UserLabel", "Path", "User Assigned Label")
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
obj.addProperty("App::PropertyString", "ToolDescription", "Tool", "The description of the tool ")
obj.setEditorMode('ToolDescription', 1) # make this read only
# Depth Properties
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", "The height needed to clear clamps and obstructions")
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", "Rapid Safety Height between locations.")
obj.addProperty("App::PropertyFloatConstraint", "StepDown", "Depth", "Incremental Step Down of Tool")
obj.StepDown = (1, 0.01, 1000, 0.5)
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")
# 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")
# 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")
# Contour Properties
obj.addProperty("App::PropertyEnumeration", "Direction", "Contour", "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 Contour runs
obj.addProperty("App::PropertyBool", "UseComp", "Contour", "make True, if using Cutter Radius Compensation")
obj.addProperty("App::PropertyDistance", "RollRadius", "Contour", "Radius at start and end")
obj.addProperty("App::PropertyDistance", "OffsetExtra", "Contour", "Extra value to stay away from final Contour- good for roughing toolpath")
obj.addProperty("App::PropertyLength", "SegLen", "Contour", "Tesselation value for tool paths made from beziers, bsplines, and ellipses")
obj.addProperty("App::PropertyAngle", "PlungeAngle", "Contour", "Plunge angle with which the tool enters the work piece. Straight down is 90 degrees, if set small enough or zero the tool will descent exactly one layer depth down per turn")
obj.addProperty("App::PropertyVectorList", "locs", "Tags", "List of holding tag locations")
obj.addProperty("App::PropertyFloatList", "angles", "Tags", "List of angles for the holding tags")
obj.addProperty("App::PropertyFloatList", "heights", "Tags", "List of angles for the holding tags")
obj.addProperty("App::PropertyFloatList", "lengths", "Tags", "List of angles for the holding tags")
locations = []
angles = []
lengths = []
heights = []
obj.locs = locations
obj.angles = angles
obj.lengths = lengths
obj.heights = heights
obj.Proxy = self
def __getstate__(self):
return None
def __setstate__(self, state):
return None
def onChanged(self, obj, prop):
if prop == "UserLabel":
obj.Label = obj.UserLabel + " :" + obj.ToolDescription
def setDepths(proxy, obj):
parentJob = PathUtils.findParentJob(obj)
if parentJob is None:
return
baseobject = parentJob.Base
if baseobject is None:
return
try:
bb = baseobject.Shape.BoundBox # parent boundbox
obj.StartDepth = bb.ZMax
obj.ClearanceHeight = bb.ZMax + 5.0
obj.SafeHeight = bb.ZMax + 3.0
except:
obj.StartDepth = 5.0
obj.ClearanceHeight = 10.0
obj.SafeHeight = 8.0
def _buildPathLibarea(self, obj, edgelist):
import PathScripts.PathKurveUtils as PathKurveUtils
import math
import area
output = ""
if obj.Comment != "":
output += '(' + str(obj.Comment)+')\n'
if obj.StartPoint and obj.UseStartPoint:
startpoint = obj.StartPoint
else:
startpoint = None
if obj.EndPoint and obj.UseEndPoint:
endpoint = obj.EndPoint
else:
endpoint = None
PathKurveUtils.output('mem')
PathKurveUtils.feedrate_hv(self.horizFeed, self.vertFeed)
output = ""
output += "G0 Z" + str(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
curve = PathKurveUtils.makeAreaCurve(edgelist, obj.Direction, startpoint, endpoint)
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
if obj.UseComp is False:
side = 'On'
else:
if obj.Direction == 'CW':
side = 'Left'
else:
side = 'Right'
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)
depthparams = depth_params(
obj.ClearanceHeight.Value,
obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, 0.0,
obj.FinalDepth.Value, None)
PathKurveUtils.profile2(
curve, side, self.radius, self.vertFeed, self.horizFeed,
self.vertRapid, self.horizRapid, obj.OffsetExtra.Value, roll_radius,
None, None, depthparams, extend_at_start, extend_at_end,
lead_in_line_len, lead_out_line_len)
output += PathKurveUtils.retrieve_gcode()
return output
def execute(self, obj):
import Part # math #DraftGeomUtils
output = ""
toolLoad = PathUtils.getLastToolLoad(obj)
if toolLoad is None or toolLoad.ToolNumber == 0:
self.vertFeed = 100
self.horizFeed = 100
self.vertRapid = 100
self.horizRapid = 100
self.radius = 0.25
obj.ToolNumber = 0
obj.ToolDescription = "UNDEFINED"
else:
self.vertFeed = toolLoad.VertFeed.Value
self.horizFeed = toolLoad.HorizFeed.Value
self.vertRapid = toolLoad.VertRapid.Value
self.horizRapid = toolLoad.HorizRapid.Value
tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
if tool.Diameter == 0:
self.radius = 0.25
else:
self.radius = tool.Diameter/2
obj.ToolNumber = toolLoad.ToolNumber
obj.ToolDescription = toolLoad.Name
if obj.UserLabel == "":
obj.Label = obj.Name + " :" + obj.ToolDescription
else:
obj.Label = obj.UserLabel + " :" + obj.ToolDescription
output += "(" + obj.Label + ")"
if not obj.UseComp:
output += "(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")"
else:
output += "(Uncompensated Tool Path)"
parentJob = PathUtils.findParentJob(obj)
if parentJob is None:
return
baseobject = parentJob.Base
if baseobject is None:
return
print "base object: " + baseobject.Name
contourwire = PathUtils.silhouette(baseobject)
edgelist = contourwire.Edges
edgelist = Part.__sortEdges__(edgelist)
output += self._buildPathLibarea(obj, edgelist)
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 _ViewProviderContour:
def __init__(self, vobj):
vobj.Proxy = self
def attach(self, vobj):
self.Object = vobj.Object
return
def setEdit(self, vobj, mode=0):
FreeCADGui.Control.closeDialog()
taskd = TaskPanel()
taskd.obj = vobj.Object
FreeCADGui.Control.showDialog(taskd)
taskd.setupUi()
return True
def getIcon(self):
return ":/icons/Path-Contour.svg"
def __getstate__(self):
return None
def __setstate__(self, state):
return None
class _CommandAddTag:
def GetResources(self):
return {'Pixmap': 'Path-Holding',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Contour", "Add Holding Tag"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Contour", "Add Holding Tag")}
def IsActive(self):
return FreeCAD.ActiveDocument is not None
def setpoint(self, point, o):
obj = FreeCADGui.Selection.getSelection()[0]
obj.StartPoint.x = point.x
obj.StartPoint.y = point.y
loc = obj.locs
h = obj.heights
l = obj.lengths
a = obj.angles
x = point.x
y = point.y
z = float(0.0)
loc.append(Vector(x, y, z))
h.append(4.0)
l.append(5.0)
a.append(45.0)
obj.locs = loc
obj.heights = h
obj.lengths = l
obj.angles = a
def Activated(self):
FreeCADGui.Snapper.getPoint(callback=self.setpoint)
class _CommandSetStartPoint:
def GetResources(self):
return {'Pixmap': 'Path-Holding',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Contour", "Pick Start Point"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Contour", "Pick Start Point")}
def IsActive(self):
return FreeCAD.ActiveDocument is not None
def setpoint(self, point, o):
obj = FreeCADGui.Selection.getSelection()[0]
obj.StartPoint.x = point.x
obj.StartPoint.y = point.y
def Activated(self):
FreeCADGui.Snapper.getPoint(callback=self.setpoint)
class _CommandSetEndPoint:
def GetResources(self):
return {'Pixmap': 'Path-Holding',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Contour", "Pick End Point"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Contour", "Pick End Point")}
def IsActive(self):
return FreeCAD.ActiveDocument is not None
def setpoint(self, point, o):
obj = FreeCADGui.Selection.getSelection()[0]
obj.EndPoint.x = point.x
obj.EndPoint.y = point.y
def Activated(self):
FreeCADGui.Snapper.getPoint(callback=self.setpoint)
class CommandPathContour:
def GetResources(self):
return {'Pixmap': 'Path-Contour',
'MenuText': QtCore.QT_TRANSLATE_NOOP("PathContour", "Contour"),
'Accel': "P, P",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathContour", "Creates a Path Contour object from selected faces")}
def IsActive(self):
if FreeCAD.ActiveDocument is not None:
for o in FreeCAD.ActiveDocument.Objects:
if o.Name[:3] == "Job":
return True
return False
def Activated(self):
ztop = 10.0
zbottom = 0.0
FreeCAD.ActiveDocument.openTransaction(translate("Path", "Create a Contour"))
FreeCADGui.addModule("PathScripts.PathContour")
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", "Contour")')
FreeCADGui.doCommand('PathScripts.PathContour.ObjectContour(obj)')
FreeCADGui.doCommand('PathScripts.PathContour._ViewProviderContour(obj.ViewObject)')
FreeCADGui.doCommand('obj.Active = True')
FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(ztop + 10.0))
FreeCADGui.doCommand('obj.StepDown = 1.0')
FreeCADGui.doCommand('obj.StartDepth= ' + str(ztop))
FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom))
FreeCADGui.doCommand('obj.SafeHeight = ' + str(ztop + 2.0))
FreeCADGui.doCommand('obj.OffsetExtra = 0.0')
FreeCADGui.doCommand('obj.Direction = "CW"')
FreeCADGui.doCommand('obj.UseComp = True')
FreeCADGui.doCommand('obj.PlungeAngle = 90.0')
FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)')
FreeCADGui.doCommand('PathScripts.PathContour.ObjectContour.setDepths(obj.Proxy, obj)')
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
FreeCADGui.doCommand('obj.ViewObject.startEditing()')
class TaskPanel:
def __init__(self):
#self.form = FreeCADGui.PySideUic.loadUi(":/panels/ContourEdit.ui")
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/ContourEdit.ui")
self.updating = False
def accept(self):
self.getFields()
FreeCADGui.ActiveDocument.resetEdit()
FreeCADGui.Control.closeDialog()
FreeCAD.ActiveDocument.recompute()
FreeCADGui.Selection.removeObserver(self.s)
def reject(self):
FreeCADGui.Control.closeDialog()
FreeCAD.ActiveDocument.recompute()
FreeCADGui.Selection.removeObserver(self.s)
def getFields(self):
if self.obj:
if hasattr(self.obj, "StartDepth"):
self.obj.StartDepth = self.form.startDepth.text()
if hasattr(self.obj, "FinalDepth"):
self.obj.FinalDepth = self.form.finalDepth.text()
if hasattr(self.obj, "SafeHeight"):
self.obj.SafeHeight = self.form.safeHeight.text()
if hasattr(self.obj, "ClearanceHeight"):
self.obj.ClearanceHeight = self.form.clearanceHeight.text()
if hasattr(self.obj, "StepDown"):
self.obj.StepDown = self.form.stepDown.value()
if hasattr(self.obj, "OffsetExtra"):
self.obj.OffsetExtra = self.form.extraOffset.value()
if hasattr(self.obj, "SegLen"):
self.obj.SegLen = self.form.segLen.value()
if hasattr(self.obj, "RollRadius"):
self.obj.RollRadius = self.form.rollRadius.value()
if hasattr(self.obj, "PlungeAngle"):
self.obj.PlungeAngle = str(self.form.plungeAngle.value())
if hasattr(self.obj, "UseComp"):
self.obj.UseComp = self.form.useCompensation.isChecked()
if hasattr(self.obj, "UseStartPoint"):
self.obj.UseStartPoint = self.form.useStartPoint.isChecked()
if hasattr(self.obj, "UseEndPoint"):
self.obj.UseEndPoint = self.form.useEndPoint.isChecked()
if hasattr(self.obj, "Direction"):
self.obj.Direction = str(self.form.direction.currentText())
self.obj.Proxy.execute(self.obj)
def setFields(self):
self.form.startDepth.setText(str(self.obj.StartDepth.Value))
self.form.finalDepth.setText(str(self.obj.FinalDepth.Value))
self.form.safeHeight.setText(str(self.obj.SafeHeight.Value))
self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value))
self.form.stepDown.setValue(self.obj.StepDown)
self.form.extraOffset.setValue(self.obj.OffsetExtra.Value)
self.form.segLen.setValue(self.obj.SegLen.Value)
self.form.rollRadius.setValue(self.obj.RollRadius.Value)
self.form.plungeAngle.setValue(self.obj.PlungeAngle.Value)
self.form.useCompensation.setChecked(self.obj.UseComp)
self.form.useStartPoint.setChecked(self.obj.UseStartPoint)
self.form.useEndPoint.setChecked(self.obj.UseEndPoint)
index = self.form.direction.findText(
self.obj.Direction, QtCore.Qt.MatchFixedString)
if index >= 0:
self.form.direction.setCurrentIndex(index)
for i in range(len(self.obj.locs)):
item = QtGui.QTreeWidgetItem(self.form.tagTree)
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)
def open(self):
self.s = SelObserver()
# install the function mode resident
FreeCADGui.Selection.addObserver(self.s)
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Ok)
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 = []
for i in range(self.form.tagTree.topLevelItemCount()):
it = self.form.tagTree.findItems(
str(i+1), QtCore.Qt.MatchExactly, 0)[0]
if (remove is 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))
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)
self.obj.locs = loc
self.obj.heights = h
self.obj.lengths = l
self.obj.angles = a
self.obj.touch()
FreeCAD.ActiveDocument.recompute()
def addElement(self):
self.updating = True
item = QtGui.QTreeWidgetItem(self.form.tagTree)
item.setText(0, str(self.form.tagTree.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.form.tagTree.currentItem()
if it:
nr = int(it.text(0))-1
self.resetObject(remove=nr)
self.update()
def update(self):
'fills the treewidget'
self.updating = True
self.form.tagTree.clear()
if self.obj:
for i in range(len(self.obj.locs)):
item = QtGui.QTreeWidgetItem(self.form.tagTree)
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.updating = False
return
def setupUi(self):
# Connect Signals and Slots
# Depths
self.form.startDepth.editingFinished.connect(self.getFields)
self.form.finalDepth.editingFinished.connect(self.getFields)
self.form.stepDown.editingFinished.connect(self.getFields)
# Heights
self.form.safeHeight.editingFinished.connect(self.getFields)
self.form.clearanceHeight.editingFinished.connect(self.getFields)
# operation
self.form.direction.currentIndexChanged.connect(self.getFields)
self.form.useCompensation.clicked.connect(self.getFields)
self.form.useStartPoint.clicked.connect(self.getFields)
self.form.useEndPoint.clicked.connect(self.getFields)
self.form.extraOffset.editingFinished.connect(self.getFields)
self.form.segLen.editingFinished.connect(self.getFields)
self.form.rollRadius.editingFinished.connect(self.getFields)
# Tag Form
QtCore.QObject.connect(
self.form.tagTree,
QtCore.SIGNAL("itemChanged(QTreeWidgetItem *, int)"),
self.edit)
self.form.addTag.clicked.connect(self.addElement)
self.form.deleteTag.clicked.connect(self.removeElement)
self.setFields()
class SelObserver:
def __init__(self):
import PathScripts.PathSelection as PST
PST.contourselect()
def __del__(self):
import PathScripts.PathSelection as PST
PST.clear()
def addSelection(self, doc, obj, sub, pnt):
FreeCADGui.doCommand('Gui.Selection.addSelection(FreeCAD.ActiveDocument.' + obj + ')')
FreeCADGui.updateGui()
if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_Contour', CommandPathContour())
FreeCADGui.addCommand('Add_Tag', _CommandAddTag())
FreeCADGui.addCommand('Set_StartPoint', _CommandSetStartPoint())
FreeCADGui.addCommand('Set_EndPoint', _CommandSetEndPoint())
FreeCAD.Console.PrintLog("Loading PathContour... done\n")

View File

@ -60,7 +60,7 @@ class ObjectDrilling:
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Final Depth of Tool- lowest value in Z")) obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Final Depth of Tool- lowest value in Z"))
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Height to clear top of materil")) obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Height to clear top of materil"))
obj.addProperty("App::PropertyDistance", "RetractHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","The height where feed starts and height during retract tool when path is finished")) obj.addProperty("App::PropertyDistance", "RetractHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","The height where feed starts and height during retract tool when path is finished"))
obj.addProperty("App::PropertyFloat", "DwellTime", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","The time to dwell between peck cycles"))
# Tool Properties # Tool Properties
obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber", "Tool", QtCore.QT_TRANSLATE_NOOP("App::Property","The tool number in use")) obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber", "Tool", QtCore.QT_TRANSLATE_NOOP("App::Property","The tool number in use"))
obj.ToolNumber = (0, 0, 1000, 1) obj.ToolNumber = (0, 0, 1000, 1)
@ -90,15 +90,21 @@ class ObjectDrilling:
if toolLoad is None or toolLoad.ToolNumber == 0: if toolLoad is None or toolLoad.ToolNumber == 0:
self.vertFeed = 100 self.vertFeed = 100
self.horizFeed = 100 self.horizFeed = 100
self.vertRapid = 100
self.horizRapid = 100
self.radius = 0.25 self.radius = 0.25
obj.ToolNumber = 0 obj.ToolNumber = 0
obj.ToolDescription = "UNDEFINED" obj.ToolDescription = "UNDEFINED"
else: else:
self.vertFeed = toolLoad.VertFeed.Value self.vertFeed = toolLoad.VertFeed.Value
self.horizFeed = toolLoad.HorizFeed.Value self.horizFeed = toolLoad.HorizFeed.Value
self.vertRapid = toolLoad.VertRapid.Value
self.horizRapid = toolLoad.HorizRapid.Value
tool = PathUtils.getTool(obj, toolLoad.ToolNumber) tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
self.radius = tool.Diameter/2 if tool.Diameter == 0:
self.radius = 0.25
else:
self.radius = tool.Diameter/2
obj.ToolNumber = toolLoad.ToolNumber obj.ToolNumber = toolLoad.ToolNumber
obj.ToolDescription = toolLoad.Name obj.ToolDescription = toolLoad.Name
@ -111,7 +117,9 @@ class ObjectDrilling:
output = "(Begin Drilling)\n" output = "(Begin Drilling)\n"
if obj.Base: if obj.Base:
for loc in obj.Base: for loc in obj.Base:
#print loc
for sub in loc[1]: for sub in loc[1]:
#locations.append(self._findDrillingVector(loc))
if "Face" in sub or "Edge" in sub: if "Face" in sub or "Edge" in sub:
s = getattr(loc[0].Shape, sub) s = getattr(loc[0].Shape, sub)
@ -136,23 +144,27 @@ class ObjectDrilling:
output += "G90 G98\n" output += "G90 G98\n"
# rapid to clearance height # rapid to clearance height
output += "G0 Z" + str(obj.ClearanceHeight.Value) output += "G0 Z" + str(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
# rapid to first hole location, with spindle still retracted: # rapid to first hole location, with spindle still retracted:
p0 = locations[0] p0 = locations[0]
output += "G0 X" + fmt(p0.x) + " Y" + fmt(p0.y) + "\n" output += "G0 X" + fmt(p0.x) + " Y" + fmt(p0.y) + "F " + PathUtils.fmt(self.horizRapid) + "\n"
# move tool to clearance plane # move tool to clearance plane
output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "\n" output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
pword = ""
qword = ""
if obj.PeckDepth.Value > 0: if obj.PeckDepth.Value > 0:
cmd = "G83" cmd = "G83"
qword = " Q" + fmt(obj.PeckDepth.Value) qword = " Q" + fmt(obj.PeckDepth.Value)
elif obj.DwellTime > 0:
cmd = "G82"
pword = " P" + fmt(obj.DwellTime)
else: else:
cmd = "G81" cmd = "G81"
qword = ""
for p in locations: for p in locations:
output += cmd + \ output += cmd + \
" X" + fmt(p.x) + \ " X" + fmt(p.x) + \
" Y" + fmt(p.y) + \ " Y" + fmt(p.y) + \
" Z" + fmt(obj.FinalDepth.Value) + qword + \ " Z" + fmt(obj.FinalDepth.Value) + qword + pword + \
" R" + str(obj.RetractHeight.Value) + \ " R" + str(obj.RetractHeight.Value) + \
" F" + str(self.vertFeed) + "\n" \ " F" + str(self.vertFeed) + "\n" \
@ -174,20 +186,22 @@ class ObjectDrilling:
def checkdrillable(self, obj, sub): def checkdrillable(self, obj, sub):
print "in checkdrillable"
drillable = False drillable = False
if obj.ShapeType == 'Vertex': if obj.ShapeType == 'Vertex':
drillable = True drillable = True
elif obj.ShapeType == 'Solid': elif obj.ShapeType == 'Solid':
if sub[0:4] == 'Face': if sub[0:4] == 'Face':
subobj = obj.getElement(sub) subobj = obj.getElement(sub)
drillable = isinstance(subobj.Edges[0].Curve, Part.Circle) if isinstance(subobj.Edges[0].Curve, Part.Circle):
drillable = True
if str(subobj.Surface) == "<Cylinder object>": if str(subobj.Surface) == "<Cylinder object>":
drillable = True drillable = True
if len(subobj.Edges[0].Vertexes) > 1:
drillable = False
if sub[0:4] == 'Edge': if sub[0:4] == 'Edge':
o = obj.getElement(sub) o = obj.getElement(sub)
drillable = isinstance(o.Curve, Part.Circle) if isinstance(o.Curve, Part.Circle) and len(o.Vertexes) == 1:
drillable = True
return drillable return drillable
@ -213,16 +227,38 @@ class ObjectDrilling:
obj.ClearanceHeight = 10.0 obj.ClearanceHeight = 10.0
obj.SafeHeight = 8.0 obj.SafeHeight = 8.0
obj.RetractHeight = 6.0 obj.RetractHeight = 6.0
if self.checkdrillable(ss.Shape,sub):
if item in baselist: if not self.checkdrillable(ss.Shape,sub):
FreeCAD.Console.PrintWarning("Drillable location already in the list" + "\n") FreeCAD.Console.PrintError("Selected element is not a drillable location" + "\n")
else: return
baselist.append(item)
if sub[0:4] == 'Face':
# Check for other drillable faces and give user the option
drillableFaces = []
for i in range(len(ss.Shape.Faces)):
if self.checkdrillable(ss.Shape, "Face" + str(i+1)):
drillableFaces.append("Face" + str(i+1))
if len(drillableFaces) > 1:
reply = QtGui.QMessageBox.question(None,"","Multiple drillable faces found. Drill them all?",
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
if reply == QtGui.QMessageBox.Yes:
for i in drillableFaces:
if i in baselist:
FreeCAD.Console.PrintWarning("Drillable location already in the list" + "\n")
continue
else:
newitem = (ss, i)
baselist.append(newitem)
else:
if item in baselist:
FreeCAD.Console.PrintWarning("Drillable location already in the list" + "\n")
else:
baselist.append(item)
print baselist
obj.Base = baselist obj.Base = baselist
self.execute(obj) self.execute(obj)
class _ViewProviderDrill: class _ViewProviderDrill:
def __init__(self, obj): def __init__(self, obj):
obj.Proxy = self obj.Proxy = self

View File

@ -91,29 +91,36 @@ class ObjectPathEngrave:
if obj.Comment != "": if obj.Comment != "":
output += '(' + str(obj.Comment)+')\n' output += '(' + str(obj.Comment)+')\n'
myJob = PathUtils.findMyJob(obj) # myJob = PathUtils.findParentJob(obj)
if myJob is not None: # if myJob is not None:
controllers = myJob.Proxy.getToolControllers(myJob) # controllers = myJob.Proxy.getToolControllers(myJob)
if len(controllers) >= 1: # if len(controllers) >= 1:
mlist = [] # mlist = []
for c in controllers: # for c in controllers:
mlist.append(c.Name) # mlist.append(c.Name)
else: # else:
mlist = ["None"] # mlist = ["None"]
obj.ToolController = mlist # obj.ToolController = mlist
toolLoad = PathUtils.getLastToolLoad(obj) toolLoad = PathUtils.getLastToolLoad(obj)
if toolLoad is None or toolLoad.ToolNumber == 0: if toolLoad is None or toolLoad.ToolNumber == 0:
self.vertFeed = 100 self.vertFeed = 100
self.horizFeed = 100 self.horizFeed = 100
self.vertRapid = 100
self.horizRapid = 100
self.radius = 0.25 self.radius = 0.25
obj.ToolNumber = 0 obj.ToolNumber = 0
obj.ToolDescription = "UNDEFINED" obj.ToolDescription = "UNDEFINED"
else: else:
self.vertFeed = toolLoad.VertFeed.Value self.vertFeed = toolLoad.VertFeed.Value
self.horizFeed = toolLoad.HorizFeed.Value self.horizFeed = toolLoad.HorizFeed.Value
self.vertRapid = toolLoad.VertRapid.Value
self.horizRapid = toolLoad.HorizRapid.Value
tool = PathUtils.getTool(obj, toolLoad.ToolNumber) tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
self.radius = tool.Diameter/2 if tool.Diameter == 0:
self.radius = 0.25
else:
self.radius = tool.Diameter/2
obj.ToolNumber = toolLoad.ToolNumber obj.ToolNumber = toolLoad.ToolNumber
obj.ToolDescription = toolLoad.Name obj.ToolDescription = toolLoad.Name
@ -123,7 +130,7 @@ class ObjectPathEngrave:
obj.Label = obj.UserLabel + " :" + obj.ToolDescription obj.Label = obj.UserLabel + " :" + obj.ToolDescription
if obj.Base: if obj.Base:
output += "G0 Z" + PathUtils.fmt(obj.ClearanceHeight.Value)+"\n" output += "G0 Z" + PathUtils.fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
wires = [] wires = []
for o in obj.Base: for o in obj.Base:
@ -135,7 +142,7 @@ class ObjectPathEngrave:
if obj.Algorithm == "OCC Native": if obj.Algorithm == "OCC Native":
output += self.buildpathocc(obj, wires) output += self.buildpathocc(obj, wires)
output += "G0 Z" + PathUtils.fmt(obj.ClearanceHeight.Value)+"\n" output += "G0 Z" + PathUtils.fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) +"\n"
# print output # print output
@ -173,7 +180,7 @@ class ObjectPathEngrave:
if not last: if not last:
# we set the first move to our first point # we set the first move to our first point
last = edge.Vertexes[0].Point last = edge.Vertexes[0].Point
output += "G0" + " X" + PathUtils.fmt(last.x) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt(obj.SafeHeight.Value) # Rapid sto starting position output += "G0" + " X" + PathUtils.fmt(last.x) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt(obj.SafeHeight.Value) + "F " + PathUtils.fmt(self.horizRapid) # Rapid sto starting position
output += "G1" + " X" + PathUtils.fmt(last.x) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt(obj.FinalDepth.Value) + "F " + PathUtils.fmt(self.vertFeed) + "\n" # Vertical feed to depth output += "G1" + " X" + PathUtils.fmt(last.x) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt(obj.FinalDepth.Value) + "F " + PathUtils.fmt(self.vertFeed) + "\n" # Vertical feed to depth
if isinstance(edge.Curve, Part.Circle): if isinstance(edge.Curve, Part.Circle):
point = edge.Vertexes[-1].Point point = edge.Vertexes[-1].Point
@ -294,6 +301,9 @@ class TaskPanel:
def __init__(self): def __init__(self):
self.form = FreeCADGui.PySideUic.loadUi(":/panels/EngraveEdit.ui") self.form = FreeCADGui.PySideUic.loadUi(":/panels/EngraveEdit.ui")
def __del__(self):
FreeCADGui.Selection.removeObserver(self.s)
def accept(self): def accept(self):
self.getFields() self.getFields()

View File

@ -27,7 +27,7 @@ import Path
from PySide import QtCore, QtGui from PySide import QtCore, QtGui
import os import os
import glob import glob
import PathLoadTool #import PathLoadTool
import Draft import Draft
@ -123,14 +123,14 @@ class ObjectPathJob:
obj.Y_Min = current_post.CORNER_MIN['y'] obj.Y_Min = current_post.CORNER_MIN['y']
obj.Z_Min = current_post.CORNER_MIN['z'] obj.Z_Min = current_post.CORNER_MIN['z']
def getToolControllers(self, obj): # def getToolControllers(self, obj):
'''returns a list of ToolControllers for the current job''' # '''returns a list of ToolControllers for the current job'''
controllers = [] # controllers = []
for o in obj.Group: # for o in obj.Group:
if "Proxy" in o.PropertiesList: # if "Proxy" in o.PropertiesList:
if isinstance(o.Proxy, PathLoadTool.LoadTool): # if isinstance(o.Proxy, PathLoadTool.LoadTool):
controllers.append (o.Name) # controllers.append (o.Name)
return controllers # return controllers
def execute(self, obj): def execute(self, obj):
@ -204,19 +204,23 @@ class CommandJob:
FreeCAD.ActiveDocument.openTransaction(translate("Path_Job", "Create Job")) FreeCAD.ActiveDocument.openTransaction(translate("Path_Job", "Create Job"))
FreeCADGui.addModule('PathScripts.PathUtils') FreeCADGui.addModule('PathScripts.PathUtils')
FreeCADGui.addModule('PathScripts.PathLoadTool') FreeCADGui.addModule('PathScripts.PathLoadTool')
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeatureCompoundPython", "Job")') snippet = '''
FreeCADGui.doCommand('PathScripts.PathJob.ObjectPathJob(obj)') import PathScripts.PathLoadTool as PathLoadTool
FreeCADGui.doCommand('PathScripts.PathLoadTool.CommandPathLoadTool.Create(obj.Name)') obj = FreeCAD.ActiveDocument.addObject("Path::FeatureCompoundPython", "Job")
FreeCADGui.doCommand('obj.ViewObject.startEditing()') PathScripts.PathJob.ObjectPathJob(obj)
# FreeCADGui.doCommand('tool = Path.Tool()') PathLoadTool.CommandPathLoadTool.Create(obj.Name)
# FreeCADGui.doCommand('tool') tl = obj.Group[0]
# FreeCADGui.doCommand('tool.Diameter = 5.0') obj.ViewObject.startEditing()
# FreeCADGui.doCommand('tool.Name = "Default Tool"') tool = Path.Tool()
# FreeCADGui.doCommand('tool.cuttingEdgeHeight = 15.0') tool.Diameter = 5.0
# FreeCADGui.doCommand('tool.ToolType = "EndMill"') tool.Name = "Default Tool"
# FreeCADGui.doCommand('tool.Material = "HighSpeedSteel"') tool.CuttingEdgeHeight = 15.0
# FreeCADGui.doCommand('obj.ToolTable.addTools(tool)') tool.ToolType = "EndMill"
tool.Material = "HighSpeedSteel"
obj.Tooltable.addTools(tool)
tl.ToolNumber = 1
'''
FreeCADGui.doCommand(snippet)
FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.commitTransaction()

View File

@ -148,7 +148,7 @@ def profile(curve, side_of_line, radius=1.0, vertfeed=0.0, horizfeed=0.0, offset
output = "" output = ""
output += "G0 Z" + str(clearance) + "\n" output += "G0 Z" + str(clearance) + "\n"
print "in profile: 151"
offset_curve = area.Curve(curve) offset_curve = area.Curve(curve)
if offset_curve.getNumVertices() <= 1: if offset_curve.getNumVertices() <= 1:
raise Exception, "Sketch has no elements!" raise Exception, "Sketch has no elements!"
@ -297,28 +297,32 @@ and have not been throughly optimized, understood, or tested for FreeCAD.'''
def profile2(curve, direction="on", radius=1.0, vertfeed=0.0, def profile2(curve, direction="on", radius=1.0, vertfeed=0.0,
horizfeed=0.0, offset_extra=0.0, roll_radius=2.0, horizfeed=0.0, vertrapid=0.0, horizrapid=0.0, offset_extra=0.0,
roll_on=None, roll_off=None, depthparams=None, 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, extend_at_start=0.0, extend_at_end=0.0, lead_in_line_len=0.0,
lead_out_line_len=0.0): lead_out_line_len=0.0):
# print "direction: " + str(direction) print "direction: " + str(direction)
# print "radius: " + str(radius) print "radius: " + str(radius)
# print "vertfeed: " + str(vertfeed) print "vertfeed: " + str(vertfeed)
# print "horizfeed: " + str(horizfeed) print "horizfeed: " + str(horizfeed)
# print "offset_extra: " + str(offset_extra) print "offset_extra: " + str(offset_extra)
# print "roll_radius: " + str(roll_radius) print "roll_radius: " + str(roll_radius)
# print "roll_on: " + str(roll_on) print "roll_on: " + str(roll_on)
# print "roll_off: " + str(roll_off) print "roll_off: " + str(roll_off)
# print "depthparams: " + str(depthparams) print "depthparams: " + str(depthparams)
# print "extend_at_start: " + str(extend_at_start) print "extend_at_start: " + str(extend_at_start)
# print "extend_at_end: " + str(extend_at_end) print "extend_at_end: " + str(extend_at_end)
# print "lead_in_line_len: " + str(lead_in_line_len) print "lead_in_line_len: " + str(lead_in_line_len)
# print "lead_out_line_len: " + str(lead_out_line_len) print "lead_out_line_len: " + str(lead_out_line_len)
print "in profile2: 318"
global tags global tags
direction = direction.lower() direction = direction.lower()
offset_curve = area.Curve(curve) offset_curve = area.Curve(curve)
print "curve: " , str(curve)
print "result curve: ", offset_curve.__dict__
if direction == "on": if direction == "on":
use_CRC() == False use_CRC() == False
@ -340,8 +344,10 @@ def profile2(curve, direction="on", radius=1.0, vertfeed=0.0,
using_area_for_offset = True using_area_for_offset = True
a = area.Area() a = area.Area()
a.append(curve) a.append(curve)
print "curve, offset: " , str(curve), str(offset)
a.Offset(-offset) a.Offset(-offset)
for curve in a.getCurves(): for curve in a.getCurves():
print "result curve: ", curve
curve_cw = curve.IsClockwise() curve_cw = curve.IsClockwise()
if cw != curve_cw: if cw != curve_cw:
curve.Reverse() curve.Reverse()
@ -424,15 +430,17 @@ def profile2(curve, direction="on", radius=1.0, vertfeed=0.0,
# start point # start point
if (endpoint is None) or (endpoint != s): if (endpoint is None) or (endpoint != s):
if use_CRC(): if use_CRC():
rapid(crc_start_point.x, crc_start_point.y) rapid(crc_start_point.x, crc_start_point.y) + "F " + horizrapid + "\n"
else: else:
rapid(s.x, s.y) rapid(s.x, s.y) #+ "F " + str(horizrapid) + "\n"
# rapid down to just above the material # rapid down to just above the material
if endpoint is None: if endpoint is None:
rapid(z=mat_depth + depthparams.rapid_safety_space) rapid(z=mat_depth + depthparams.rapid_safety_space) #+ "F " + vertrapid + "\n"
else: else:
rapid(z=mat_depth) rapid(z=mat_depth) #+ "F " + str(vertrapid) + "\n"
# feed down to depth # feed down to depth
mat_depth = depth mat_depth = depth
@ -481,7 +489,7 @@ def profile2(curve, direction="on", radius=1.0, vertfeed=0.0,
add_CRC_end_line(offset_curve, roll_on_curve, roll_off_curve, add_CRC_end_line(offset_curve, roll_on_curve, roll_off_curve,
radius, direction, crc_end_point, lead_out_line_len) radius, direction, crc_end_point, lead_out_line_len)
if direction == "on": if direction == "on":
rapid(z=depthparams.clearance_height) rapid(z=depthparams.clearance_height) #+ "F " + vertrapid + "\n"
else: else:
feed(crc_end_point.x, crc_end_point.y) feed(crc_end_point.x, crc_end_point.y)
@ -493,11 +501,11 @@ def profile2(curve, direction="on", radius=1.0, vertfeed=0.0,
if endpoint != s: if endpoint != s:
# rapid up to the clearance height # rapid up to the clearance height
rapid(z=depthparams.clearance_height) rapid(z=depthparams.clearance_height)# + "F " + vertrapid + "\n"
prev_depth = depth prev_depth = depth
rapid(z=depthparams.clearance_height) rapid(z=depthparams.clearance_height)# + "F " + vertrapid + "\n"
del offset_curve del offset_curve

View File

@ -50,7 +50,8 @@ class LoadTool():
obj.SpindleDir = ['Forward', 'Reverse'] obj.SpindleDir = ['Forward', 'Reverse']
obj.addProperty("App::PropertySpeed", "VertFeed", "Feed", QtCore.QT_TRANSLATE_NOOP("App::Property","Feed rate for vertical moves in Z")) obj.addProperty("App::PropertySpeed", "VertFeed", "Feed", QtCore.QT_TRANSLATE_NOOP("App::Property","Feed rate for vertical moves in Z"))
obj.addProperty("App::PropertySpeed", "HorizFeed", "Feed", QtCore.QT_TRANSLATE_NOOP("App::Property","Feed rate for horizontal moves")) obj.addProperty("App::PropertySpeed", "HorizFeed", "Feed", QtCore.QT_TRANSLATE_NOOP("App::Property","Feed rate for horizontal moves"))
obj.addProperty("App::PropertySpeed", "VertRapid", "Rapid", QtCore.QT_TRANSLATE_NOOP("App::Property", "Rapid rate for vertical moves in Z"))
obj.addProperty("App::PropertySpeed", "HorizRapid", "Rapid", QtCore.QT_TRANSLATE_NOOP("App::Property", "Rapid rate for horizontal moves"))
obj.Proxy = self obj.Proxy = self
mode = 2 mode = 2
obj.setEditorMode('Placement', mode) obj.setEditorMode('Placement', mode)
@ -211,12 +212,17 @@ class TaskPanel:
def getFields(self): def getFields(self):
if self.obj: if self.obj:
if hasattr(self.obj, "VertFeed"): if hasattr(self.obj, "Label"):
self.obj.Label = self.form.tcoName.text() self.obj.Label = self.form.tcoName.text()
if hasattr(self.obj, "VertFeed"): if hasattr(self.obj, "VertFeed"):
self.obj.VertFeed = self.form.vertFeed.text() self.obj.VertFeed = self.form.vertFeed.text()
if hasattr(self.obj, "HorizFeed"): if hasattr(self.obj, "HorizFeed"):
self.obj.HorizFeed = self.form.horizFeed.text() self.obj.HorizFeed = self.form.horizFeed.text()
if hasattr(self.obj, "VertRapid"):
self.obj.VertRapid = self.form.vertRapid.text()
if hasattr(self.obj, "HorizRapid"):
self.obj.HorizRapid = self.form.horizRapid.text()
if hasattr(self.obj, "SpindleSpeed"): if hasattr(self.obj, "SpindleSpeed"):
self.obj.SpindleSpeed = self.form.spindleSpeed.value() self.obj.SpindleSpeed = self.form.spindleSpeed.value()
if hasattr(self.obj, "SpindleDir"): if hasattr(self.obj, "SpindleDir"):
@ -229,6 +235,9 @@ class TaskPanel:
self.form.vertFeed.setText(str(self.obj.VertFeed.Value)) self.form.vertFeed.setText(str(self.obj.VertFeed.Value))
self.form.horizFeed.setText(str(self.obj.HorizFeed.Value)) self.form.horizFeed.setText(str(self.obj.HorizFeed.Value))
self.form.vertRapid.setText(str(self.obj.VertRapid.Value))
self.form.horizRapid.setText(str(self.obj.HorizRapid.Value))
self.form.spindleSpeed.setValue(self.obj.SpindleSpeed) self.form.spindleSpeed.setValue(self.obj.SpindleSpeed)
self.form.tcoName.setText(str(self.obj.Label)) self.form.tcoName.setText(str(self.obj.Label))

View File

@ -230,7 +230,7 @@ class ObjectPocket:
output = "" output = ""
if obj.Comment != "": if obj.Comment != "":
output += '(' + str(obj.Comment)+')\n' output += '(' + str(obj.Comment)+')\n'
output += 'G0 Z' + fmt(obj.ClearanceHeight.Value) + "\n" output += 'G0 Z' + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
offsets = [] offsets = []
nextradius = self.radius + extraoffset nextradius = self.radius + extraoffset
@ -318,9 +318,9 @@ class ObjectPocket:
else: else:
print "WARNING: Straight-plunging... probably not good, but we didn't find a place to helix or ramp" print "WARNING: Straight-plunging... probably not good, but we didn't find a place to helix or ramp"
startPoint = edge.Vertexes[0].Point startPoint = edge.Vertexes[0].Point
output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "\n" output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
output += "G0 X" + fmt(startPoint.x) + " Y" + fmt(startPoint.y) +\ output += "G0 X" + fmt(startPoint.x) + " Y" + fmt(startPoint.y) +\
" Z" + fmt(obj.ClearanceHeight.Value) + "\n" " Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.horizRapid) + "\n"
first = False first = False
# then move slow down to our starting point for our profile # then move slow down to our starting point for our profile
last = edge.Vertexes[0].Point last = edge.Vertexes[0].Point
@ -349,7 +349,7 @@ class ObjectPocket:
last = point last = point
# move back up # move back up
output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "\n" output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
return output return output
# To reload this from FreeCAD, use: import PathScripts.PathPocket; reload(PathScripts.PathPocket) # To reload this from FreeCAD, use: import PathScripts.PathPocket; reload(PathScripts.PathPocket)
@ -359,12 +359,16 @@ class ObjectPocket:
if toolLoad is None or toolLoad.ToolNumber == 0: if toolLoad is None or toolLoad.ToolNumber == 0:
self.vertFeed = 100 self.vertFeed = 100
self.horizFeed = 100 self.horizFeed = 100
self.vertRapid = 100
self.horiRrapid = 100
self.radius = 0.25 self.radius = 0.25
obj.ToolNumber = 0 obj.ToolNumber = 0
obj.ToolDescription = "UNDEFINED" obj.ToolDescription = "UNDEFINED"
else: else:
self.vertFeed = toolLoad.VertFeed.Value self.vertFeed = toolLoad.VertFeed.Value
self.horizFeed = toolLoad.HorizFeed.Value self.horizFeed = toolLoad.HorizFeed.Value
self.vertRapid = toolLoad.VertRapid.Value
self.horizRapid = toolLoad.HorizRapid.Value
tool = PathUtils.getTool(obj, toolLoad.ToolNumber) tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
if tool.Diameter == 0: if tool.Diameter == 0:
self.radius = 0.25 self.radius = 0.25

View File

@ -61,15 +61,11 @@ class ObjectProfile:
obj.addProperty("App::PropertyEnumeration", "Algorithm", "Algorithm", QtCore.QT_TRANSLATE_NOOP("App::Property","The library or algorithm used to generate the path")) obj.addProperty("App::PropertyEnumeration", "Algorithm", "Algorithm", QtCore.QT_TRANSLATE_NOOP("App::Property","The library or algorithm used to generate the path"))
obj.Algorithm = ['OCC Native', 'libarea'] obj.Algorithm = ['OCC Native', 'libarea']
obj.addProperty("App::PropertyLink", "ActiveTC", "Tool", QtCore.QT_TRANSLATE_NOOP("App::Property","The tool controler in use")) obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber", "Tool", "The tool number in use")
obj.addProperty("App::PropertyEnumeration", "ToolControllers", QtCore.QT_TRANSLATE_NOOP("App::Property","The tool controller to use")) obj.ToolNumber = (0, 0, 1000, 1)
obj.Toolcontrollers = [] obj.setEditorMode('ToolNumber', 1) # make this read only
obj.addProperty("App::PropertyString", "ToolDescription", "Tool", "The description of the tool ")
# obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber", "Tool", "The tool number in use") obj.setEditorMode('ToolDescription', 1) # make this read onlyt
# obj.ToolNumber = (0, 0, 1000, 1)
# obj.setEditorMode('ToolNumber', 1) # make this read only
# obj.addProperty("App::PropertyString", "ToolDescription", "Tool", "The description of the tool ")
# obj.setEditorMode('ToolDescription', 1) # make this read onlyt
# Depth Properties # Depth Properties
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","The height needed to clear clamps and obstructions")) obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","The height needed to clear clamps and obstructions"))
@ -117,7 +113,7 @@ class ObjectProfile:
obj.angles = angles obj.angles = angles
obj.lengths = lengths obj.lengths = lengths
obj.heights = heights obj.heights = heights
obj.ToolDescription = "UNDEFINED" #obj.ToolDescription = "UNDEFINED"
obj.Proxy = self obj.Proxy = self
@ -188,7 +184,8 @@ class ObjectProfile:
wire, obj.Side, self.radius, clockwise, wire, obj.Side, self.radius, clockwise,
obj.ClearanceHeight.Value, obj.StepDown, obj.StartDepth.Value, obj.ClearanceHeight.Value, obj.StepDown, obj.StartDepth.Value,
obj.FinalDepth.Value, FirstEdge, PathClosed, obj.SegLen.Value, obj.FinalDepth.Value, FirstEdge, PathClosed, obj.SegLen.Value,
self.vertFeed, self.horizFeed, PlungeAngle=obj.PlungeAngle.Value) self.vertFeed, self.horizFeed, self.vertRapid, self.horizRapid,
PlungeAngle=obj.PlungeAngle.Value)
return output return output
@ -214,7 +211,7 @@ class ObjectProfile:
PathKurveUtils.feedrate_hv(self.horizFeed, self.vertFeed) PathKurveUtils.feedrate_hv(self.horizFeed, self.vertFeed)
output = "" output = ""
output += "G0 Z" + str(obj.ClearanceHeight.Value) output += "G0 Z" + str(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
curve = PathKurveUtils.makeAreaCurve(edgelist, obj.Direction, startpoint, endpoint) curve = PathKurveUtils.makeAreaCurve(edgelist, obj.Direction, startpoint, endpoint)
'''The following line uses a profile function written for use with FreeCAD. It's clean but incomplete. It doesn't handle '''The following line uses a profile function written for use with FreeCAD. It's clean but incomplete. It doesn't handle
@ -226,7 +223,8 @@ print "y - " + str(point.y)
or probably other features in heekscnc''' 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) # 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. '''The following calls the original procedure from h
toolLoad = obj.activeTCeekscnc 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 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''' thoroughly optimized and improved but it'll take a smarter mind than mine to do it. -sliptonic Feb16'''
roll_radius = 2.0 roll_radius = 2.0
@ -255,10 +253,10 @@ print "y - " + str(point.y)
obj.FinalDepth.Value, None) obj.FinalDepth.Value, None)
PathKurveUtils.profile2( PathKurveUtils.profile2(
curve, obj.Side, self.radius, self.vertFeed, curve, obj.Side, self.radius, self.vertFeed, self.horizFeed,
self.horizFeed, obj.OffsetExtra.Value, roll_radius, None, None, self.vertRapid, self.horizRapid, obj.OffsetExtra.Value, roll_radius,
depthparams, extend_at_start, extend_at_end, lead_in_line_len, None, None, depthparams, extend_at_start, extend_at_end,
lead_out_line_len) lead_in_line_len, lead_out_line_len)
output += PathKurveUtils.retrieve_gcode() output += PathKurveUtils.retrieve_gcode()
return output return output
@ -267,17 +265,23 @@ print "y - " + str(point.y)
import Part # math #DraftGeomUtils import Part # math #DraftGeomUtils
output = "" output = ""
#toolLoad = PathUtils.getLastToolLoad(obj) toolLoad = PathUtils.getLastToolLoad(obj)
toolLoad = obj.activeTC # obj.ToolController = PathUtils.getToolControllers(obj)
# toolLoad = PathUtils.getToolLoad(obj, obj.ToolController)
if toolLoad is None or toolLoad.ToolNumber == 0: if toolLoad is None or toolLoad.ToolNumber == 0:
self.vertFeed = 100 self.vertFeed = 100
self.horizFeed = 100 self.horizFeed = 100
self.vertRapid = 100
self.horizRapid = 100
self.radius = 0.25 self.radius = 0.25
obj.ToolNumber = 0 obj.ToolNumber = 0
obj.ToolDescription = "UNDEFINED" obj.ToolDescription = "UNDEFINED"
else: else:
self.vertFeed = toolLoad.VertFeed.Value self.vertFeed = toolLoad.VertFeed.Value
self.horizFeed = toolLoad.HorizFeed.Value self.horizFeed = toolLoad.HorizFeed.Value
self.vertRapid = toolLoad.VertRapid.Value
self.horizRapid = toolLoad.HorizRapid.Value
tool = PathUtils.getTool(obj, toolLoad.ToolNumber) tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
if tool.Diameter == 0: if tool.Diameter == 0:
self.radius = 0.25 self.radius = 0.25
@ -485,6 +489,7 @@ class CommandPathProfile:
FreeCADGui.doCommand('obj.Direction = "CW"') FreeCADGui.doCommand('obj.Direction = "CW"')
FreeCADGui.doCommand('obj.UseComp = False') FreeCADGui.doCommand('obj.UseComp = False')
FreeCADGui.doCommand('obj.PlungeAngle = 90.0') FreeCADGui.doCommand('obj.PlungeAngle = 90.0')
#FreeCADGui.doCommand('obj.ActiveTC = None')
FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)') FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)')
FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.commitTransaction()

View File

@ -174,6 +174,13 @@ class POCKETGate:
return pocketable return pocketable
class CONTOURGate:
def allow(self, doc, obj, sub):
pass
def contourselect():
FreeCADGui.Selection.addSelectionGate(CONTOURGate())
FreeCAD.Console.PrintWarning("Contour Select Mode\n")
def fselect(): def fselect():
FreeCADGui.Selection.addSelectionGate(FGate()) FreeCADGui.Selection.addSelectionGate(FGate())

View File

@ -0,0 +1,401 @@
# -*- 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
import Path
from PathScripts import PathUtils
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore, QtGui
__title__ = "Path Surface Operation"
__author__ = "sliptonic (Brad Collette)"
__url__ = "http://www.freecadweb.org"
"""Path surface 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 ObjectStrategy:
def __init__(self, obj):
obj.addProperty("App::PropertyLinkSubList", "Base", "Path", "The base geometry of this toolpath")
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::PropertyString", "UserLabel", "Path", "User Assigned Label")
obj.addProperty("App::PropertyEnumeration", "Algorithm", "Algorithm", "The library to use to generate the path")
obj.Algorithm = ['OCL Dropcutter', 'OCL Waterline']
# Tool Properties
obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber", "Tool", "The tool number in use")
obj.ToolNumber = (0, 0, 1000, 0)
obj.setEditorMode('ToolNumber', 1) # make this read only
obj.addProperty("App::PropertyString", "ToolDescription", "Tool", "The description of the tool ")
obj.setEditorMode('ToolDescription', 1) # make this read onlyt
# Depth Properties
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", "The height needed to clear clamps and obstructions")
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", "Rapid Safety Height between locations.")
obj.addProperty("App::PropertyFloatConstraint", "StepDown", "Depth", "Incremental Step Down of Tool")
obj.StepDown = (0.0, 0.01, 100.0, 0.5)
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", "FinishDepth", "Depth", "Maximum material removed on final pass.")
obj.Proxy = self
def addbase(self, obj, ss, sub=""):
baselist = obj.Base
if len(baselist) == 0: # When adding the first base object, guess at heights
try:
bb = ss.Shape.BoundBox # parent boundbox
subobj = ss.Shape.getElement(sub)
fbb = subobj.BoundBox # feature boundbox
obj.StartDepth = bb.ZMax
obj.ClearanceHeight = bb.ZMax + 5.0
obj.SafeHeight = bb.ZMax + 3.0
if fbb.ZMax < bb.ZMax:
obj.FinalDepth = fbb.ZMax
else:
obj.FinalDepth = bb.ZMin
except:
obj.StartDepth = 5.0
obj.ClearanceHeight = 10.0
obj.SafeHeight = 8.0
item = (ss, sub)
if item in baselist:
FreeCAD.Console.PrintWarning(
"this object already in the list" + "\n")
else:
baselist.append(item)
obj.Base = baselist
self.execute(obj)
def __getstate__(self):
return None
def __setstate__(self, state):
return None
def onChanged(self, obj, prop):
return None
def execute(self, obj):
output = ""
toolLoad = PathUtils.getLastToolLoad(obj)
if toolLoad is None or toolLoad.ToolNumber == 0:
self.vertFeed = 100
self.horizFeed = 100
self.vertRapid = 100
self.horizRapid = 100
self.radius = 0.25
obj.ToolNumber = 0
obj.ToolDescription = "UNDEFINED"
else:
self.vertFeed = toolLoad.VertFeed.Value
self.horizFeed = toolLoad.HorizFeed.Value
self.vertRapid = toolLoad.VertRapid.Value
self.horizRapid = toolLoad.HorizRapid.Value
tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
if tool.Diameter == 0:
self.radius = 0.25
else:
self.radius = tool.Diameter/2
obj.ToolNumber = toolLoad.ToolNumber
obj.ToolDescription = toolLoad.Name
output += "(" + obj.Label + ")"
output += "(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")"
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 ViewProviderStrategy:
def __init__(self, obj): # mandatory
# obj.addProperty("App::PropertyFloat","SomePropertyName","PropertyGroup","Description of this property")
obj.Proxy = self
def __getstate__(self): # mandatory
return None
def __setstate__(self, state): # mandatory
return None
def getIcon(self): # optional
return ":/icons/Path-Surfacing.svg"
def onChanged(self, obj, prop): # optional
# this is executed when a property of the VIEW PROVIDER changes
pass
def updateData(self, obj, prop): # optional
# this is executed when a property of the APP OBJECT changes
pass
def setEdit(self, vobj, mode=0):
FreeCADGui.Control.closeDialog()
taskd = TaskPanel()
taskd.obj = vobj.Object
FreeCADGui.Control.showDialog(taskd)
taskd.setupUi()
return True
def unsetEdit(self, vobj, mode): # optional
# this is executed when the user cancels or terminates edit mode
pass
class CommandPathStrategy:
def GetResources(self):
return {'Pixmap': 'Path-3DSurface',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Strategy", "Strategy"),
'Accel': "P, D",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Strategy", "Creates a Path Strategy object")}
def IsActive(self):
if FreeCAD.ActiveDocument is not None:
for o in FreeCAD.ActiveDocument.Objects:
if o.Name[:3] == "Job":
return True
return False
def Activated(self):
ztop = 10
zbottom = 0
FreeCAD.ActiveDocument.openTransaction(translate("Path_Strategy", "Create Strategy"))
FreeCADGui.addModule("PathScripts.PathStrategy")
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Strategy")')
FreeCADGui.doCommand('PathScripts.PathStrategy.ObjectStrategy(obj)')
FreeCADGui.doCommand('obj.Active = True')
FreeCADGui.doCommand('PathScripts.PathStrategy.ViewProviderStrategy(obj.ViewObject)')
FreeCADGui.doCommand('from PathScripts import PathUtils')
FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(ztop + 2))
FreeCADGui.doCommand('obj.StartDepth = ' + str(ztop))
FreeCADGui.doCommand('obj.SafeHeight = ' + str(ztop + 2))
FreeCADGui.doCommand('obj.StepDown = ' + str((ztop - zbottom) / 8))
FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom))
FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)')
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
FreeCADGui.doCommand('obj.ViewObject.startEditing()')
class TaskPanel:
def __init__(self):
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/StrategyEdit.ui")
#self.form = FreeCADGui.PySideUic.loadUi(":/panels/SurfaceEdit.ui")
def accept(self):
self.getFields()
FreeCADGui.ActiveDocument.resetEdit()
FreeCADGui.Control.closeDialog()
FreeCAD.ActiveDocument.recompute()
FreeCADGui.Selection.removeObserver(self.s)
def reject(self):
FreeCADGui.Control.closeDialog()
FreeCAD.ActiveDocument.recompute()
FreeCADGui.Selection.removeObserver(self.s)
def getFields(self):
if self.obj:
if hasattr(self.obj, "StartDepth"):
self.obj.StartDepth = self.form.startDepth.text()
if hasattr(self.obj, "FinalDepth"):
self.obj.FinalDepth = self.form.finalDepth.text()
if hasattr(self.obj, "FinishDepth"):
self.obj.FinishDepth = self.form.finishDepth.text()
if hasattr(self.obj, "StepDown"):
self.obj.StepDown = self.form.stepDown.value()
if hasattr(self.obj, "SafeHeight"):
self.obj.SafeHeight = self.form.safeHeight.text()
if hasattr(self.obj, "ClearanceHeight"):
self.obj.ClearanceHeight = self.form.clearanceHeight.text()
self.obj.Proxy.execute(self.obj)
def setFields(self):
self.form.startDepth.setText(str(self.obj.StartDepth.Value))
self.form.finalDepth.setText(str(self.obj.FinalDepth.Value))
self.form.finishDepth.setText(str(self.obj.FinishDepth.Value))
self.form.stepDown.setValue(self.obj.StepDown)
self.form.safeHeight.setText(str(self.obj.SafeHeight.Value))
self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value))
for i in self.obj.Base:
self.form.baseList.addItem(i[0].Name)
def open(self):
self.s = SelObserver()
# install the function mode resident
FreeCADGui.Selection.addObserver(self.s)
def addBase(self):
# check that the selection contains exactly what we want
selection = FreeCADGui.Selection.getSelectionEx()
if len(selection) != 1:
FreeCAD.Console.PrintError(translate(
"PathSurface", "Please select a single solid object from the project tree\n"))
return
if not len(selection[0].SubObjects) == 0:
FreeCAD.Console.PrintError(translate(
"PathSurface", "Please select a single solid object from the project tree\n"))
return
sel = selection[0].Object
# get type of object
# if sel.TypeId.startswith('Mesh'):
# # it is a mesh already
# print 'was already mesh'
# elif sel.TypeId.startswith('Part') and \
# (sel.Shape.BoundBox.XLength > 0) and \
# (sel.Shape.BoundBox.YLength > 0) and \
# (sel.Shape.BoundBox.ZLength > 0):
# print 'this is a solid Part object'
# else:
# FreeCAD.Console.PrintError(
# translate("PathSurface", "Cannot work with this object\n"))
# return
self.obj.Proxy.addbase(self.obj, sel)
self.setFields() # defaults may have changed. Reload.
self.form.baseList.clear()
for i in self.obj.Base:
self.form.baseList.addItem(i[0].Name)
def deleteBase(self):
dlist = self.form.baseList.selectedItems()
for d in dlist:
newlist = []
for i in self.obj.Base:
if not i[0].Name == d.text():
newlist.append(i)
self.obj.Base = newlist
self.form.baseList.takeItem(self.form.baseList.row(d))
self.obj.Proxy.execute(self.obj)
FreeCAD.ActiveDocument.recompute()
def itemActivated(self):
FreeCADGui.Selection.clearSelection()
slist = self.form.baseList.selectedItems()
for i in slist:
o = FreeCAD.ActiveDocument.getObject(i.text())
FreeCADGui.Selection.addSelection(o)
FreeCADGui.updateGui()
def reorderBase(self):
newlist = []
for i in range(self.form.baseList.count()):
s = self.form.baseList.item(i).text()
obj = FreeCAD.ActiveDocument.getObject(s)
newlist.append(obj)
self.obj.Base = newlist
self.obj.Proxy.execute(self.obj)
FreeCAD.ActiveDocument.recompute()
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Ok)
def setupUi(self):
# Connect Signals and Slots
#Base Geometry
self.form.addBase.clicked.connect(self.addBase)
self.form.deleteBase.clicked.connect(self.deleteBase)
self.form.reorderBase.clicked.connect(self.reorderBase)
self.form.baseList.itemSelectionChanged.connect(self.itemActivated)
# Depths
self.form.startDepth.editingFinished.connect(self.getFields)
self.form.finalDepth.editingFinished.connect(self.getFields)
self.form.finishDepth.editingFinished.connect(self.getFields)
self.form.stepDown.editingFinished.connect(self.getFields)
# Heights
self.form.safeHeight.editingFinished.connect(self.getFields)
self.form.clearanceHeight.editingFinished.connect(self.getFields)
sel = FreeCADGui.Selection.getSelectionEx()
self.setFields()
if len(sel) != 0:
self.addBase()
class SelObserver:
def __init__(self):
import PathScripts.PathSelection as PST
PST.surfaceselect()
def __del__(self):
import PathScripts.PathSelection as PST
PST.clear()
def addSelection(self, doc, obj, sub, pnt): # Selection object
FreeCADGui.doCommand(
'Gui.Selection.addSelection(FreeCAD.ActiveDocument.' + obj + ')')
FreeCADGui.updateGui()
if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_Strategy', CommandPathStrategy())
FreeCAD.Console.PrintLog("Loading PathStrategy... done\n")

View File

@ -131,9 +131,9 @@ class ObjectSurface:
for loop in loops: for loop in loops:
p = loop[0] p = loop[0]
loopstring = "(loop begin)" + "\n" loopstring = "(loop begin)" + "\n"
loopstring += "G0 Z" + str(obj.SafeHeight.Value) + "\n" loopstring += "G0 Z" + str(obj.SafeHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
loopstring += "G0 X" + \ loopstring += "G0 X" + \
str(fmt(p.x)) + " Y" + str(fmt(p.y)) + "\n" str(fmt(p.x)) + " Y" + str(fmt(p.y)) + "F " + PathUtils.fmt(self.horizRapid) + "\n"
loopstring += "G1 Z" + str(fmt(p.z)) + "\n" loopstring += "G1 Z" + str(fmt(p.z)) + "\n"
for p in loop[1:]: for p in loop[1:]:
loopstring += "G1 X" + \ loopstring += "G1 X" + \
@ -239,8 +239,8 @@ class ObjectSurface:
# generate the path commands # generate the path commands
output = "" output = ""
output += "G0 Z" + str(obj.ClearanceHeight.Value) + "\n" output += "G0 Z" + str(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
output += "G0 X" + str(clp[0].x) + " Y" + str(clp[0].y) + "\n" output += "G0 X" + str(clp[0].x) + " Y" + str(clp[0].y) + "F " + PathUtils.fmt(self.horizRapid) + "\n"
output += "G1 Z" + str(clp[0].z) + " F" + str(self.vertFeed) + "\n" output += "G1 Z" + str(clp[0].z) + " F" + str(self.vertFeed) + "\n"
for c in clp: for c in clp:
@ -261,14 +261,21 @@ class ObjectSurface:
if toolLoad is None or toolLoad.ToolNumber == 0: if toolLoad is None or toolLoad.ToolNumber == 0:
self.vertFeed = 100 self.vertFeed = 100
self.horizFeed = 100 self.horizFeed = 100
self.vertRapid = 100
self.horizRapid = 100
self.radius = 0.25 self.radius = 0.25
obj.ToolNumber = 0 obj.ToolNumber = 0
obj.ToolDescription = "UNDEFINED" obj.ToolDescription = "UNDEFINED"
else: else:
self.vertFeed = toolLoad.VertFeed.Value self.vertFeed = toolLoad.VertFeed.Value
self.horizFeed = toolLoad.HorizFeed.Value self.horizFeed = toolLoad.HorizFeed.Value
self.vertRapid = toolLoad.VertRapid.Value
self.horizRapid = toolLoad.HorizRapid.Value
tool = PathUtils.getTool(obj, toolLoad.ToolNumber) tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
self.radius = tool.Diameter/2 if tool.Diameter == 0:
self.radius = 0.25
else:
self.radius = tool.Diameter/2
obj.ToolNumber = toolLoad.ToolNumber obj.ToolNumber = toolLoad.ToolNumber
obj.ToolDescription = toolLoad.Name obj.ToolDescription = toolLoad.Name

View File

@ -1,79 +1,62 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# *************************************************************************** #***************************************************************************
# * * #* *
# * Copyright (c) 2015 Dan Falck <ddfalck@gmail.com> * #* Copyright (c) 2015 Dan Falck <ddfalck@gmail.com> *
# * * #* *
# * This program is free software; you can redistribute it and/or modify * #* This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) * #* it under the terms of the GNU Lesser General Public License (LGPL) *
# * as published by the Free Software Foundation; either version 2 of * #* as published by the Free Software Foundation; either version 2 of *
# * the License, or (at your option) any later version. * #* the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. * #* for detail see the LICENCE text file. *
# * * #* *
# * This program is distributed in the hope that it will be useful, * #* This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of * #* but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. * #* GNU Library General Public License for more details. *
# * * #* *
# * You should have received a copy of the GNU Library General Public * #* You should have received a copy of the GNU Library General Public *
# * License along with this program; if not, write to the Free Software * #* License along with this program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * #* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA * #* USA *
# * * #* *
# *************************************************************************** #***************************************************************************
import FreeCAD import FreeCAD,FreeCADGui
import FreeCADGui from PySide import QtCore,QtGui
from PySide import QtCore, QtGui
# Qt tanslation handling # Qt tanslation handling
try: try:
_encoding = QtGui.QApplication.UnicodeUTF8 _encoding = QtGui.QApplication.UnicodeUTF8
def translate(context, text, disambig=None): def translate(context, text, disambig=None):
return QtGui.QApplication.translate(context, text, disambig, _encoding) return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError: except AttributeError:
def translate(context, text, disambig=None): def translate(context, text, disambig=None):
return QtGui.QApplication.translate(context, text, disambig) return QtGui.QApplication.translate(context, text, disambig)
class CommandPathToolTableEdit: class CommandPathToolTableEdit:
def GetResources(self): def GetResources(self):
return {'Pixmap': 'Path-ToolTable', return {'Pixmap' : 'Path-ToolTable',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_ToolTableEdit", "EditToolTable"), 'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_ToolTableEdit","EditToolTable"),
'Accel': "P, T", 'Accel': "P, T",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_ToolTableEdit", "Edits a Tool Table in a selected Project")} 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_ToolTableEdit","Edits a Tool Table in a selected Project")}
def IsActive(self): def IsActive(self):
return FreeCAD.ActiveDocument is not None return not FreeCAD.ActiveDocument is None
def Activated(self): def Activated(self):
FreeCAD.ActiveDocument.openTransaction( FreeCAD.ActiveDocument.openTransaction(translate("Path_ToolTableEdit","Edits a Tool Table in a selected Project"))
translate("Path_ToolTableEdit", "Edits a Tool Table in a selected Project")) FreeCADGui.doCommand("from PathScripts import TooltableEditor")
snippet = ''' FreeCADGui.doCommand("from PathScripts import PathUtils")
from PathScripts import TooltableEditor FreeCADGui.doCommand('machine = PathUtils.findMachine()')
from PathScripts import PathUtils FreeCADGui.doCommand('TooltableEditor.edit(machine.Name)')
sel = Gui.Selection.getSelectionEx()[0]
obj=sel.Object
if "Tooltable" in obj.PropertiesList:
TooltableEditor.edit(obj.Name)
'''
FreeCADGui.doCommand(snippet)
# FreeCADGui.doCommand("from PathScripts import TooltableEditor")
# FreeCADGui.doCommand("from PathScripts import PathUtils")
# FreeCADGui.doCommand("sel = Gui.Selection.getSelectionEx()[0]")
# FreeCADGui.doCommand("obj=sel.Object")
# FreeCADGui.doCommand('job = PathUtils.findParentJob(obj)')
# FreeCADGui.doCommand('TooltableEditor.edit(job.Name)')
FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute() FreeCAD.ActiveDocument.recompute()
if FreeCAD.GuiUp:
if FreeCAD.GuiUp:
# register the FreeCAD command # register the FreeCAD command
FreeCADGui.addCommand('Path_ToolTableEdit', CommandPathToolTableEdit()) FreeCADGui.addCommand('Path_ToolTableEdit',CommandPathToolTableEdit())
FreeCAD.Console.PrintLog("Loading PathToolTableEdit... done\n") FreeCAD.Console.PrintLog("Loading PathToolTableEdit... done\n")

View File

@ -26,14 +26,15 @@ import FreeCAD
import FreeCADGui import FreeCADGui
import Part import Part
import math import math
import Draft
import Path import Path
import TechDraw
from DraftGeomUtils import geomType from DraftGeomUtils import geomType
from DraftGeomUtils import findWires from DraftGeomUtils import findWires
import DraftVecUtils import DraftVecUtils
import PathScripts import PathScripts
from PathScripts import PathJob from PathScripts import PathJob
import itertools import itertools
from PySide import QtGui
def cleanedges(splines, precision): def cleanedges(splines, precision):
'''cleanedges([splines],precision). Convert BSpline curves, Beziers, to arcs that can be used for cnc paths. '''cleanedges([splines],precision). Convert BSpline curves, Beziers, to arcs that can be used for cnc paths.
@ -83,6 +84,9 @@ def curvetowire(obj, steps):
# fixme set at 4 decimal places for testing # fixme set at 4 decimal places for testing
def fmt(val): return format(val, '.4f') def fmt(val): return format(val, '.4f')
def silhouette(obj):
w = TechDraw.findOuterWire(obj.Shape.Edges)
return w
def isSameEdge(e1, e2): def isSameEdge(e1, e2):
"""isSameEdge(e1,e2): return True if the 2 edges are both lines or arcs/circles and have the same """isSameEdge(e1,e2): return True if the 2 edges are both lines or arcs/circles and have the same
@ -147,6 +151,26 @@ def is_clockwise(obj):
return sum >= 0 return sum >= 0
def loopdetect(obj, edge1, edge2):
'''
Returns a loop wire that includes the two edges.
Useful for detecting boundaries of negative space features ie 'holes'
If a unique loop is not found, returns None
'''
candidates = []
for wire in obj.Shape.Wires:
for e in wire.Edges:
if e.hashCode() == edge1.hashCode():
candidates.append((wire.hashCode(),wire))
if e.hashCode() == edge2.hashCode():
candidates.append((wire.hashCode(),wire))
loop = set([x for x in candidates if candidates.count(x) > 1]) #return the duplicate item
if len(loop) != 1:
return None
loopwire = next(x for x in loop)[1]
return loopwire
def check_clockwise(poly): def check_clockwise(poly):
''' '''
check_clockwise(poly) a function for returning a boolean if the selected wire is clockwise or counter clockwise check_clockwise(poly) a function for returning a boolean if the selected wire is clockwise or counter clockwise
@ -396,7 +420,9 @@ def SortPath(wire, Side, radius, clockwise, firstedge=None, SegLen=0.5):
return offset return offset
def MakePath(wire, Side, radius, clockwise, ZClearance, StepDown, ZStart, ZFinalDepth, firstedge=None, PathClosed=True, SegLen=0.5, VertFeed=1.0, HorizFeed=2.0, PlungeAngle=90.0): def MakePath(wire, Side, radius, clockwise, ZClearance, StepDown, ZStart,
ZFinalDepth, firstedge=None, PathClosed=True, SegLen=0.5,
VertFeed=1.0, HorizFeed=2.0, VertJog=1.0, HorizJog = 2.0, PlungeAngle=90.0):
''' makes the path - just a simple profile for now ''' ''' makes the path - just a simple profile for now '''
offset = SortPath(wire, Side, radius, clockwise, firstedge, SegLen=SegLen) offset = SortPath(wire, Side, radius, clockwise, firstedge, SegLen=SegLen)
if len(offset.Edges) == 0: if len(offset.Edges) == 0:
@ -404,9 +430,9 @@ def MakePath(wire, Side, radius, clockwise, ZClearance, StepDown, ZStart, ZFinal
toolpath = offset.Edges[:] toolpath = offset.Edges[:]
paths = "" paths = ""
paths += "G0 Z" + str(ZClearance) + "\n" paths += "G0 Z" + str(ZClearance) + "F " + fmt(VertJog) + "\n"
first = toolpath[0].Vertexes[0].Point first = toolpath[0].Vertexes[0].Point
paths += "G0 X" + str(fmt(first.x)) + "Y" + str(fmt(first.y)) + "\n" paths += "G0 X" + str(fmt(first.x)) + "Y" + str(fmt(first.y)) + "F " + fmt(HorizJog) + "\n"
Zprevious = ZStart Zprevious = ZStart
ZCurrent = ZStart - StepDown ZCurrent = ZStart - StepDown
@ -414,9 +440,9 @@ def MakePath(wire, Side, radius, clockwise, ZClearance, StepDown, ZStart, ZFinal
paths += convert(toolpath, Z=ZCurrent, Zprevious=Zprevious, PlungeAngle=PlungeAngle, paths += convert(toolpath, Z=ZCurrent, Zprevious=Zprevious, PlungeAngle=PlungeAngle,
vf=VertFeed, hf=HorizFeed) vf=VertFeed, hf=HorizFeed)
if not PathClosed: if not PathClosed:
paths += "G0 Z" + str(ZClearance) paths += "G0 Z" + str(ZClearance) + "F " + fmt(VertJog)
paths += "G0 X" + str(fmt(first.x)) + "Y" + \ paths += "G0 X" + str(fmt(first.x)) + "Y" + \
str(fmt(first.y)) + "\n" str(fmt(first.y)) + "F " + fmt(HorizJog) + "\n"
Zprevious = ZCurrent Zprevious = ZCurrent
ZCurrent = ZCurrent - abs(StepDown) ZCurrent = ZCurrent - abs(StepDown)
@ -434,7 +460,7 @@ def MakePath(wire, Side, radius, clockwise, ZClearance, StepDown, ZStart, ZFinal
paths += convert(toolpath, Z=ZFinalDepth, Zprevious=Zprevious, StopLength=StopLength, paths += convert(toolpath, Z=ZFinalDepth, Zprevious=Zprevious, StopLength=StopLength,
vf=VertFeed, hf=HorizFeed) vf=VertFeed, hf=HorizFeed)
paths += "G0 Z" + str(ZClearance) paths += "G0 Z" + str(ZClearance) + "F " + fmt(VertJog) + "\n"
return paths return paths
# the next two functions are for automatically populating tool # the next two functions are for automatically populating tool
@ -456,13 +482,6 @@ def changeTool(obj, job):
if g == obj: if g == obj:
return tlnum return tlnum
def getLastTool(obj):
toolNum = obj.ToolNumber
if obj.ToolNumber == 0:
# find tool from previous toolchange
job = findJob()
toolNum = changeTool(obj, job)
return getTool(obj, toolNum)
def getLastToolLoad(obj): def getLastToolLoad(obj):
# This walks up the hierarchy and tries to find the closest preceding # This walks up the hierarchy and tries to find the closest preceding
@ -507,6 +526,22 @@ def getLastToolLoad(obj):
continue continue
return tc return tc
def getToolControllers(obj):
controllers = []
try:
parent = obj.InList[0]
except:
parent = None
if parent is not None:
sibs = parent.Group
for g in sibs:
if isinstance(g.Proxy, PathScripts.PathLoadTool.LoadTool):
controllers.append(g.Name)
return controllers
def getTool(obj, number=0): def getTool(obj, number=0):
"retrieves a tool from a hosting object with a tooltable, if any" "retrieves a tool from a hosting object with a tooltable, if any"
for o in obj.InList: for o in obj.InList:

View File

@ -207,8 +207,9 @@ def parse(pathobj):
for param in params: for param in params:
if param in c.Parameters: if param in c.Parameters:
if param == 'F': if param == 'F':
outstring.append( if c.Name not in ["G0", "G00"]: #linuxcnc doesn't use rapid speeds
param + format(c.Parameters['F'], '.2f')) outstring.append(
param + format(c.Parameters['F'], '.2f'))
elif param == 'T': elif param == 'T':
outstring.append(param + str(c.Parameters['T'])) outstring.append(param + str(c.Parameters['T']))
else: else: