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-Shape.svg</file>
<file>icons/Path-Profile.svg</file>
<file>icons/Path-Contour.svg</file>
<file>icons/Path-Pocket.svg</file>
<file>icons/Path-Drilling.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>
</layout>
</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">
<property name="geometry">
<rect>

View File

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

View File

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

View File

@ -67,13 +67,14 @@ class PathWorkbench (Workbench):
from PathScripts import PathRemote
from PathScripts import PathSanity
from PathScripts import DragknifeDressup
from PathScripts import PathContour
# 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"]
prepcmdlist = ["Path_Plane", "Path_Fixture", "Path_ToolLenOffset", "Path_Comment",
"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"]
modcmdlist = ["Path_Copy", "Path_CompoundExtended", "Path_Array",
"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", "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::PropertyFloat", "DwellTime", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","The time to dwell between peck cycles"))
# Tool Properties
obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber", "Tool", QtCore.QT_TRANSLATE_NOOP("App::Property","The tool number in use"))
obj.ToolNumber = (0, 0, 1000, 1)
@ -90,15 +90,21 @@ class ObjectDrilling:
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)
self.radius = tool.Diameter/2
if tool.Diameter == 0:
self.radius = 0.25
else:
self.radius = tool.Diameter/2
obj.ToolNumber = toolLoad.ToolNumber
obj.ToolDescription = toolLoad.Name
@ -111,7 +117,9 @@ class ObjectDrilling:
output = "(Begin Drilling)\n"
if obj.Base:
for loc in obj.Base:
#print loc
for sub in loc[1]:
#locations.append(self._findDrillingVector(loc))
if "Face" in sub or "Edge" in sub:
s = getattr(loc[0].Shape, sub)
@ -136,23 +144,27 @@ class ObjectDrilling:
output += "G90 G98\n"
# 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:
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
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:
cmd = "G83"
qword = " Q" + fmt(obj.PeckDepth.Value)
elif obj.DwellTime > 0:
cmd = "G82"
pword = " P" + fmt(obj.DwellTime)
else:
cmd = "G81"
qword = ""
for p in locations:
output += cmd + \
" X" + fmt(p.x) + \
" Y" + fmt(p.y) + \
" Z" + fmt(obj.FinalDepth.Value) + qword + \
" Z" + fmt(obj.FinalDepth.Value) + qword + pword + \
" R" + str(obj.RetractHeight.Value) + \
" F" + str(self.vertFeed) + "\n" \
@ -174,20 +186,22 @@ class ObjectDrilling:
def checkdrillable(self, obj, sub):
print "in checkdrillable"
drillable = False
if obj.ShapeType == 'Vertex':
drillable = True
elif obj.ShapeType == 'Solid':
if sub[0:4] == 'Face':
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>":
drillable = True
if len(subobj.Edges[0].Vertexes) > 1:
drillable = False
if sub[0:4] == 'Edge':
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
@ -213,16 +227,38 @@ class ObjectDrilling:
obj.ClearanceHeight = 10.0
obj.SafeHeight = 8.0
obj.RetractHeight = 6.0
if self.checkdrillable(ss.Shape,sub):
if item in baselist:
FreeCAD.Console.PrintWarning("Drillable location already in the list" + "\n")
else:
baselist.append(item)
if not self.checkdrillable(ss.Shape,sub):
FreeCAD.Console.PrintError("Selected element is not a drillable location" + "\n")
return
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
self.execute(obj)
class _ViewProviderDrill:
def __init__(self, obj):
obj.Proxy = self

View File

@ -91,29 +91,36 @@ class ObjectPathEngrave:
if obj.Comment != "":
output += '(' + str(obj.Comment)+')\n'
myJob = PathUtils.findMyJob(obj)
if myJob is not None:
controllers = myJob.Proxy.getToolControllers(myJob)
if len(controllers) >= 1:
mlist = []
for c in controllers:
mlist.append(c.Name)
else:
mlist = ["None"]
obj.ToolController = mlist
# myJob = PathUtils.findParentJob(obj)
# if myJob is not None:
# controllers = myJob.Proxy.getToolControllers(myJob)
# if len(controllers) >= 1:
# mlist = []
# for c in controllers:
# mlist.append(c.Name)
# else:
# mlist = ["None"]
# obj.ToolController = mlist
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)
self.radius = tool.Diameter/2
if tool.Diameter == 0:
self.radius = 0.25
else:
self.radius = tool.Diameter/2
obj.ToolNumber = toolLoad.ToolNumber
obj.ToolDescription = toolLoad.Name
@ -123,7 +130,7 @@ class ObjectPathEngrave:
obj.Label = obj.UserLabel + " :" + obj.ToolDescription
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 = []
for o in obj.Base:
@ -135,7 +142,7 @@ class ObjectPathEngrave:
if obj.Algorithm == "OCC Native":
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
@ -173,7 +180,7 @@ class ObjectPathEngrave:
if not last:
# we set the first move to our first 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
if isinstance(edge.Curve, Part.Circle):
point = edge.Vertexes[-1].Point
@ -294,6 +301,9 @@ class TaskPanel:
def __init__(self):
self.form = FreeCADGui.PySideUic.loadUi(":/panels/EngraveEdit.ui")
def __del__(self):
FreeCADGui.Selection.removeObserver(self.s)
def accept(self):
self.getFields()

View File

@ -27,7 +27,7 @@ import Path
from PySide import QtCore, QtGui
import os
import glob
import PathLoadTool
#import PathLoadTool
import Draft
@ -123,14 +123,14 @@ class ObjectPathJob:
obj.Y_Min = current_post.CORNER_MIN['y']
obj.Z_Min = current_post.CORNER_MIN['z']
def getToolControllers(self, obj):
'''returns a list of ToolControllers for the current job'''
controllers = []
for o in obj.Group:
if "Proxy" in o.PropertiesList:
if isinstance(o.Proxy, PathLoadTool.LoadTool):
controllers.append (o.Name)
return controllers
# def getToolControllers(self, obj):
# '''returns a list of ToolControllers for the current job'''
# controllers = []
# for o in obj.Group:
# if "Proxy" in o.PropertiesList:
# if isinstance(o.Proxy, PathLoadTool.LoadTool):
# controllers.append (o.Name)
# return controllers
def execute(self, obj):
@ -204,19 +204,23 @@ class CommandJob:
FreeCAD.ActiveDocument.openTransaction(translate("Path_Job", "Create Job"))
FreeCADGui.addModule('PathScripts.PathUtils')
FreeCADGui.addModule('PathScripts.PathLoadTool')
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeatureCompoundPython", "Job")')
FreeCADGui.doCommand('PathScripts.PathJob.ObjectPathJob(obj)')
FreeCADGui.doCommand('PathScripts.PathLoadTool.CommandPathLoadTool.Create(obj.Name)')
FreeCADGui.doCommand('obj.ViewObject.startEditing()')
# FreeCADGui.doCommand('tool = Path.Tool()')
# FreeCADGui.doCommand('tool')
# FreeCADGui.doCommand('tool.Diameter = 5.0')
# FreeCADGui.doCommand('tool.Name = "Default Tool"')
# FreeCADGui.doCommand('tool.cuttingEdgeHeight = 15.0')
# FreeCADGui.doCommand('tool.ToolType = "EndMill"')
# FreeCADGui.doCommand('tool.Material = "HighSpeedSteel"')
# FreeCADGui.doCommand('obj.ToolTable.addTools(tool)')
snippet = '''
import PathScripts.PathLoadTool as PathLoadTool
obj = FreeCAD.ActiveDocument.addObject("Path::FeatureCompoundPython", "Job")
PathScripts.PathJob.ObjectPathJob(obj)
PathLoadTool.CommandPathLoadTool.Create(obj.Name)
tl = obj.Group[0]
obj.ViewObject.startEditing()
tool = Path.Tool()
tool.Diameter = 5.0
tool.Name = "Default Tool"
tool.CuttingEdgeHeight = 15.0
tool.ToolType = "EndMill"
tool.Material = "HighSpeedSteel"
obj.Tooltable.addTools(tool)
tl.ToolNumber = 1
'''
FreeCADGui.doCommand(snippet)
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 += "G0 Z" + str(clearance) + "\n"
print "in profile: 151"
offset_curve = area.Curve(curve)
if offset_curve.getNumVertices() <= 1:
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,
horizfeed=0.0, offset_extra=0.0, roll_radius=2.0,
roll_on=None, roll_off=None, depthparams=None,
horizfeed=0.0, vertrapid=0.0, horizrapid=0.0, offset_extra=0.0,
roll_radius=2.0, roll_on=None, roll_off=None, depthparams=None,
extend_at_start=0.0, extend_at_end=0.0, lead_in_line_len=0.0,
lead_out_line_len=0.0):
# print "direction: " + str(direction)
# print "radius: " + str(radius)
# print "vertfeed: " + str(vertfeed)
# print "horizfeed: " + str(horizfeed)
# print "offset_extra: " + str(offset_extra)
# print "roll_radius: " + str(roll_radius)
# print "roll_on: " + str(roll_on)
# print "roll_off: " + str(roll_off)
# print "depthparams: " + str(depthparams)
# print "extend_at_start: " + str(extend_at_start)
# print "extend_at_end: " + str(extend_at_end)
# print "lead_in_line_len: " + str(lead_in_line_len)
# print "lead_out_line_len: " + str(lead_out_line_len)
print "direction: " + str(direction)
print "radius: " + str(radius)
print "vertfeed: " + str(vertfeed)
print "horizfeed: " + str(horizfeed)
print "offset_extra: " + str(offset_extra)
print "roll_radius: " + str(roll_radius)
print "roll_on: " + str(roll_on)
print "roll_off: " + str(roll_off)
print "depthparams: " + str(depthparams)
print "extend_at_start: " + str(extend_at_start)
print "extend_at_end: " + str(extend_at_end)
print "lead_in_line_len: " + str(lead_in_line_len)
print "lead_out_line_len: " + str(lead_out_line_len)
print "in profile2: 318"
global tags
direction = direction.lower()
offset_curve = area.Curve(curve)
print "curve: " , str(curve)
print "result curve: ", offset_curve.__dict__
if direction == "on":
use_CRC() == False
@ -340,8 +344,10 @@ def profile2(curve, direction="on", radius=1.0, vertfeed=0.0,
using_area_for_offset = True
a = area.Area()
a.append(curve)
print "curve, offset: " , str(curve), str(offset)
a.Offset(-offset)
for curve in a.getCurves():
print "result curve: ", curve
curve_cw = curve.IsClockwise()
if cw != curve_cw:
curve.Reverse()
@ -424,15 +430,17 @@ def profile2(curve, direction="on", radius=1.0, vertfeed=0.0,
# start point
if (endpoint is None) or (endpoint != s):
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:
rapid(s.x, s.y)
rapid(s.x, s.y) #+ "F " + str(horizrapid) + "\n"
# rapid down to just above the material
if endpoint is None:
rapid(z=mat_depth + depthparams.rapid_safety_space)
rapid(z=mat_depth + depthparams.rapid_safety_space) #+ "F " + vertrapid + "\n"
else:
rapid(z=mat_depth)
rapid(z=mat_depth) #+ "F " + str(vertrapid) + "\n"
# feed down to 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,
radius, direction, crc_end_point, lead_out_line_len)
if direction == "on":
rapid(z=depthparams.clearance_height)
rapid(z=depthparams.clearance_height) #+ "F " + vertrapid + "\n"
else:
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:
# rapid up to the clearance height
rapid(z=depthparams.clearance_height)
rapid(z=depthparams.clearance_height)# + "F " + vertrapid + "\n"
prev_depth = depth
rapid(z=depthparams.clearance_height)
rapid(z=depthparams.clearance_height)# + "F " + vertrapid + "\n"
del offset_curve

View File

@ -50,7 +50,8 @@ class LoadTool():
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", "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
mode = 2
obj.setEditorMode('Placement', mode)
@ -211,12 +212,17 @@ class TaskPanel:
def getFields(self):
if self.obj:
if hasattr(self.obj, "VertFeed"):
if hasattr(self.obj, "Label"):
self.obj.Label = self.form.tcoName.text()
if hasattr(self.obj, "VertFeed"):
self.obj.VertFeed = self.form.vertFeed.text()
if hasattr(self.obj, "HorizFeed"):
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"):
self.obj.SpindleSpeed = self.form.spindleSpeed.value()
if hasattr(self.obj, "SpindleDir"):
@ -229,6 +235,9 @@ class TaskPanel:
self.form.vertFeed.setText(str(self.obj.VertFeed.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.tcoName.setText(str(self.obj.Label))

View File

@ -230,7 +230,7 @@ class ObjectPocket:
output = ""
if obj.Comment != "":
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 = []
nextradius = self.radius + extraoffset
@ -318,9 +318,9 @@ class ObjectPocket:
else:
print "WARNING: Straight-plunging... probably not good, but we didn't find a place to helix or ramp"
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) +\
" Z" + fmt(obj.ClearanceHeight.Value) + "\n"
" Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.horizRapid) + "\n"
first = False
# then move slow down to our starting point for our profile
last = edge.Vertexes[0].Point
@ -349,7 +349,7 @@ class ObjectPocket:
last = point
# 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
# 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:
self.vertFeed = 100
self.horizFeed = 100
self.vertRapid = 100
self.horiRrapid = 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

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.Algorithm = ['OCC Native', 'libarea']
obj.addProperty("App::PropertyLink", "ActiveTC", "Tool", QtCore.QT_TRANSLATE_NOOP("App::Property","The tool controler in use"))
obj.addProperty("App::PropertyEnumeration", "ToolControllers", QtCore.QT_TRANSLATE_NOOP("App::Property","The tool controller to use"))
obj.Toolcontrollers = []
# 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 onlyt
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 onlyt
# Depth Properties
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.lengths = lengths
obj.heights = heights
obj.ToolDescription = "UNDEFINED"
#obj.ToolDescription = "UNDEFINED"
obj.Proxy = self
@ -188,7 +184,8 @@ class ObjectProfile:
wire, obj.Side, self.radius, clockwise,
obj.ClearanceHeight.Value, obj.StepDown, obj.StartDepth.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
@ -214,7 +211,7 @@ class ObjectProfile:
PathKurveUtils.feedrate_hv(self.horizFeed, self.vertFeed)
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)
'''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'''
# 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
thoroughly optimized and improved but it'll take a smarter mind than mine to do it. -sliptonic Feb16'''
roll_radius = 2.0
@ -255,10 +253,10 @@ print "y - " + str(point.y)
obj.FinalDepth.Value, None)
PathKurveUtils.profile2(
curve, obj.Side, self.radius, self.vertFeed,
self.horizFeed, obj.OffsetExtra.Value, roll_radius, None, None,
depthparams, extend_at_start, extend_at_end, lead_in_line_len,
lead_out_line_len)
curve, obj.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
@ -267,17 +265,23 @@ print "y - " + str(point.y)
import Part # math #DraftGeomUtils
output = ""
#toolLoad = PathUtils.getLastToolLoad(obj)
toolLoad = obj.activeTC
toolLoad = PathUtils.getLastToolLoad(obj)
# obj.ToolController = PathUtils.getToolControllers(obj)
# toolLoad = PathUtils.getToolLoad(obj, obj.ToolController)
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
@ -485,6 +489,7 @@ class CommandPathProfile:
FreeCADGui.doCommand('obj.Direction = "CW"')
FreeCADGui.doCommand('obj.UseComp = False')
FreeCADGui.doCommand('obj.PlungeAngle = 90.0')
#FreeCADGui.doCommand('obj.ActiveTC = None')
FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)')
FreeCAD.ActiveDocument.commitTransaction()

View File

@ -174,6 +174,13 @@ class POCKETGate:
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():
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:
p = loop[0]
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" + \
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"
for p in loop[1:]:
loopstring += "G1 X" + \
@ -239,8 +239,8 @@ class ObjectSurface:
# generate the path commands
output = ""
output += "G0 Z" + str(obj.ClearanceHeight.Value) + "\n"
output += "G0 X" + str(clp[0].x) + " Y" + str(clp[0].y) + "\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) + "F " + PathUtils.fmt(self.horizRapid) + "\n"
output += "G1 Z" + str(clp[0].z) + " F" + str(self.vertFeed) + "\n"
for c in clp:
@ -261,14 +261,21 @@ class ObjectSurface:
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)
self.radius = tool.Diameter/2
if tool.Diameter == 0:
self.radius = 0.25
else:
self.radius = tool.Diameter/2
obj.ToolNumber = toolLoad.ToolNumber
obj.ToolDescription = toolLoad.Name

View File

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

View File

@ -26,14 +26,15 @@ import FreeCAD
import FreeCADGui
import Part
import math
import Draft
import Path
import TechDraw
from DraftGeomUtils import geomType
from DraftGeomUtils import findWires
import DraftVecUtils
import PathScripts
from PathScripts import PathJob
import itertools
from PySide import QtGui
def cleanedges(splines, precision):
'''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
def fmt(val): return format(val, '.4f')
def silhouette(obj):
w = TechDraw.findOuterWire(obj.Shape.Edges)
return w
def isSameEdge(e1, e2):
"""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
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):
'''
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
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 '''
offset = SortPath(wire, Side, radius, clockwise, firstedge, SegLen=SegLen)
if len(offset.Edges) == 0:
@ -404,9 +430,9 @@ def MakePath(wire, Side, radius, clockwise, ZClearance, StepDown, ZStart, ZFinal
toolpath = offset.Edges[:]
paths = ""
paths += "G0 Z" + str(ZClearance) + "\n"
paths += "G0 Z" + str(ZClearance) + "F " + fmt(VertJog) + "\n"
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
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,
vf=VertFeed, hf=HorizFeed)
if not PathClosed:
paths += "G0 Z" + str(ZClearance)
paths += "G0 Z" + str(ZClearance) + "F " + fmt(VertJog)
paths += "G0 X" + str(fmt(first.x)) + "Y" + \
str(fmt(first.y)) + "\n"
str(fmt(first.y)) + "F " + fmt(HorizJog) + "\n"
Zprevious = ZCurrent
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,
vf=VertFeed, hf=HorizFeed)
paths += "G0 Z" + str(ZClearance)
paths += "G0 Z" + str(ZClearance) + "F " + fmt(VertJog) + "\n"
return paths
# the next two functions are for automatically populating tool
@ -456,13 +482,6 @@ def changeTool(obj, job):
if g == obj:
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):
# This walks up the hierarchy and tries to find the closest preceding
@ -507,6 +526,22 @@ def getLastToolLoad(obj):
continue
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):
"retrieves a tool from a hosting object with a tooltable, if any"
for o in obj.InList:

View File

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