Path adaptive operation added
This commit is contained in:
@@ -105,6 +105,8 @@ SET(PathScripts_SRCS
|
||||
PathScripts/PathUtils.py
|
||||
PathScripts/PathSimulatorGui.py
|
||||
PathScripts/PostUtils.py
|
||||
PathScripts/PathAdaptiveGui.py
|
||||
PathScripts/PathAdaptive.py
|
||||
PathScripts/__init__.py
|
||||
)
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
<file>icons/edge-join-round.svg</file>
|
||||
<file>icons/edge-join-round-not.svg</file>
|
||||
<file>icons/preferences-path.svg</file>
|
||||
<file>icons/Path-Adaptive.svg</file>
|
||||
<file>panels/DlgJobChooser.ui</file>
|
||||
<file>panels/DlgJobCreate.ui</file>
|
||||
<file>panels/DlgJobModelSelect.ui</file>
|
||||
|
||||
636
src/Mod/Path/Gui/Resources/icons/Path-Adaptive.svg
Normal file
636
src/Mod/Path/Gui/Resources/icons/Path-Adaptive.svg
Normal file
@@ -0,0 +1,636 @@
|
||||
<?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-Adaptive.svg">
|
||||
<defs
|
||||
id="defs2818">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4066">
|
||||
<stop
|
||||
style="stop-color:#4e9a06;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop4068" />
|
||||
<stop
|
||||
style="stop-color:#8ae234;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop4070" />
|
||||
</linearGradient>
|
||||
<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,64.952609,-7.0541574)"
|
||||
cx="32.151962"
|
||||
cy="27.950663"
|
||||
fx="32.151962"
|
||||
fy="27.950663"
|
||||
r="23.634638" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4066"
|
||||
id="linearGradient4072"
|
||||
x1="41.610756"
|
||||
y1="59.853931"
|
||||
x2="32.101425"
|
||||
y2="10.99928"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4031"
|
||||
id="linearGradient4055"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(71.494719,-3.1982556)"
|
||||
x1="30.000002"
|
||||
y1="14"
|
||||
x2="36"
|
||||
y2="54.227272" />
|
||||
<linearGradient
|
||||
id="linearGradient4031">
|
||||
<stop
|
||||
id="stop4033"
|
||||
offset="0"
|
||||
style="stop-color:#d3d7cf;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop4035"
|
||||
offset="1"
|
||||
style="stop-color:#888a85;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4513"
|
||||
id="linearGradient4233"
|
||||
x1="19"
|
||||
y1="33"
|
||||
x2="49.566406"
|
||||
y2="33"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11"
|
||||
inkscape:cx="-5.6052856"
|
||||
inkscape:cy="28.449344"
|
||||
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="1013"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="1050"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-global="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3234"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2821">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
<dc:title>Path-FaceProfile</dc:title>
|
||||
<dc:date>2016-01-19</dc:date>
|
||||
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Path/Gui/Resources/icons/Path-</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:#172a04;stroke-width:8;stroke-linecap:round;stroke-linejoin:miter;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 50,13 39,11 c -4,-1 -5.171573,-1.4142136 -8,0 -2,1 -3,2 -5,5 L 7,46 c -3,4 -1,7 3,8 l 28,4 c 5,1 9,-2 12,-6 l 4,-5"
|
||||
id="rect3083-0"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccscccccc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:url(#linearGradient4072);stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;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 50,13 39,11 c -4,-1 -5.171573,-1.414214 -8,0 -2,1 -3,2 -5,5 L 7,46 c -3,4 -1,7 3,8 l 28,4 c 5,1 9,-2 12,-6 l 4,-5"
|
||||
id="rect3083-0-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccscccccc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:#8ae234;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;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 50.064283,12 38.517882,9.919647 c -4,-1.0000001 -5.171573,-1.4142141 -8,0 -2,1 -3,2 -5,5 l -19.0000003,30 c -2.9999999,4 -1,7 2.9999998,8 l 28.0000005,4 c 5,1 9,-2 12,-6 L 53,46"
|
||||
id="rect3083-0-6-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccscccccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient4233);fill-opacity:1.0;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
x="18.804688"
|
||||
y="47.580078"
|
||||
id="text4223"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4225"
|
||||
x="18.804688"
|
||||
y="47.580078"
|
||||
style="fill-opacity:1.0;fill:url(#linearGradient4233);stroke:#000000;stroke-opacity:1;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none">A</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 22 KiB |
@@ -102,13 +102,14 @@ class PathWorkbench (Workbench):
|
||||
from PathScripts import PathToolController
|
||||
from PathScripts import PathToolLibraryManager
|
||||
from PathScripts import PathSimulatorGui
|
||||
from PathScripts import PathAdaptiveGui
|
||||
import PathCommands
|
||||
|
||||
# build commands list
|
||||
projcmdlist = ["Path_Job", "Path_Post"]
|
||||
toolcmdlist = ["Path_Inspect", "Path_Simulator", "Path_ToolLibraryEdit", "Path_SelectLoop"]
|
||||
prepcmdlist = ["Path_Fixture", "Path_Comment", "Path_Stop", "Path_Custom"]
|
||||
twodopcmdlist = ["Path_Contour", "Path_Profile_Faces", "Path_Profile_Edges", "Path_Pocket_Shape", "Path_Drilling", "Path_MillFace", "Path_Helix"]
|
||||
twodopcmdlist = ["Path_Contour", "Path_Profile_Faces", "Path_Profile_Edges", "Path_Pocket_Shape", "Path_Drilling", "Path_MillFace", "Path_Helix", "Path_Adaptive"]
|
||||
threedopcmdlist = ["Path_Pocket_3D"]
|
||||
engravecmdlist = ["Path_Engrave"]
|
||||
modcmdlist = ["Path_OperationCopy", "Path_Array", "Path_SimpleCopy" ]
|
||||
|
||||
421
src/Mod/Path/PathScripts/PathAdaptive.py
Normal file
421
src/Mod/Path/PathScripts/PathAdaptive.py
Normal file
@@ -0,0 +1,421 @@
|
||||
import PathScripts.PathOp as PathOp
|
||||
import Path
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
from FreeCAD import Console
|
||||
import time
|
||||
import json
|
||||
import math
|
||||
import area
|
||||
from pivy import coin
|
||||
|
||||
__doc__ = "Class and implementation of the Adaptive path operation."
|
||||
|
||||
def discretize(edge, flipDirection=False):
|
||||
pts=edge.discretize(Deflection=0.01)
|
||||
if flipDirection: pts.reverse()
|
||||
return pts
|
||||
|
||||
def IsEqualInXYPlane(e1, e2):
|
||||
return math.sqrt((e2.x-e1.x)*(e2.x-e1.x) +
|
||||
(e2.y - e1.y) * (e2.y - e1.y))<0.01
|
||||
|
||||
def connectEdges(edges):
|
||||
''' Makes the list of connected discretized paths '''
|
||||
# find edge
|
||||
lastPoint=None
|
||||
remaining = []
|
||||
pathArray = []
|
||||
combined = []
|
||||
#print "Input edges , remove duplicate projections to xy plane"
|
||||
for edge in edges:
|
||||
p1 = edge.valueAt(edge.FirstParameter)
|
||||
p2 = edge.valueAt(edge.LastParameter)
|
||||
duplicate = False
|
||||
for ex in remaining:
|
||||
exp1 = ex.valueAt(ex.FirstParameter)
|
||||
exp2 = ex.valueAt(ex.LastParameter)
|
||||
if IsEqualInXYPlane(exp1, p1) and IsEqualInXYPlane(exp2, p2):
|
||||
duplicate = True
|
||||
if IsEqualInXYPlane(exp1, p2) and IsEqualInXYPlane(exp2, p1):
|
||||
duplicate = True
|
||||
if not duplicate:
|
||||
remaining.append(edge)
|
||||
#print "remaining:", remaining
|
||||
|
||||
newPath=True
|
||||
while len(remaining)>0:
|
||||
if newPath:
|
||||
#print "new iteration"
|
||||
edge=remaining[0]
|
||||
p1 = edge.valueAt(edge.FirstParameter)
|
||||
p2 = edge.valueAt(edge.LastParameter)
|
||||
#print edge, p1, p2
|
||||
if len(combined)>0: pathArray.append(combined)
|
||||
combined = []
|
||||
combined.append(discretize(edge))
|
||||
remaining.remove(edge)
|
||||
lastPoint=p2
|
||||
newPath=False
|
||||
|
||||
anyMatch=False
|
||||
for e in remaining:
|
||||
p1 = e.valueAt(e.FirstParameter)
|
||||
p2 = e.valueAt(e.LastParameter)
|
||||
#print "chk",e, p1, p2
|
||||
if IsEqualInXYPlane(lastPoint,p1):
|
||||
#print "last Point equal p1"
|
||||
combined.append(discretize(e))
|
||||
remaining.remove(e)
|
||||
lastPoint=p2
|
||||
anyMatch=True
|
||||
break
|
||||
elif IsEqualInXYPlane(lastPoint,p2):
|
||||
#print "reversed"
|
||||
combined.append(discretize(e,True))
|
||||
remaining.remove(e)
|
||||
lastPoint=p1
|
||||
anyMatch=True
|
||||
break
|
||||
if not anyMatch:
|
||||
newPath=True
|
||||
|
||||
|
||||
#make sure last path is appended
|
||||
if len(combined)>0: pathArray.append(combined)
|
||||
combined = []
|
||||
return pathArray
|
||||
|
||||
def convertTo2d(pathArray):
|
||||
output = []
|
||||
for path in pathArray:
|
||||
pth2 = []
|
||||
for edge in path:
|
||||
for pt in edge:
|
||||
pth2.append([pt[0],pt[1]])
|
||||
output.append(pth2)
|
||||
return output
|
||||
|
||||
|
||||
sceneGraph = None
|
||||
scenePathNodes = [] #for scene cleanup aftewards
|
||||
topZ = 10
|
||||
|
||||
def sceneDrawPath(path, color=(0, 0, 1)):
|
||||
global sceneGraph
|
||||
global scenePathNodes
|
||||
coPoint = coin.SoCoordinate3()
|
||||
pts = []
|
||||
for pt in path:
|
||||
pts.append([pt[0], pt[1], topZ])
|
||||
|
||||
coPoint.point.setValues(0, len(pts), pts)
|
||||
ma = coin.SoBaseColor()
|
||||
ma.rgb = color
|
||||
li = coin.SoLineSet()
|
||||
li.numVertices.setValue(len(pts))
|
||||
pathNode = coin.SoSeparator()
|
||||
pathNode.addChild(coPoint)
|
||||
pathNode.addChild(ma)
|
||||
pathNode.addChild(li)
|
||||
sceneGraph.addChild(pathNode)
|
||||
scenePathNodes.append(pathNode) #for scene cleanup afterwards
|
||||
|
||||
def sceneClean():
|
||||
global scenePathNodes
|
||||
for n in scenePathNodes:
|
||||
sceneGraph.removeChild(n)
|
||||
del scenePathNodes[:]
|
||||
|
||||
def GenerateGCode(op,obj,adaptiveResults, helixDiameter):
|
||||
if len(adaptiveResults)==0 or len(adaptiveResults[0]["AdaptivePaths"])==0:
|
||||
return
|
||||
|
||||
minLiftDistance = op.tool.Diameter
|
||||
p1 = adaptiveResults[0]["HelixCenterPoint"]
|
||||
p2 = adaptiveResults[0]["StartPoint"]
|
||||
helixRadius =math.sqrt((p1[0]-p2[0]) * (p1[0]-p2[0]) + (p1[1]-p2[1]) * (p1[1]-p2[1]))
|
||||
stepDown = obj.StepDown.Value
|
||||
passStartDepth=obj.StartDepth.Value
|
||||
if stepDown<0.1 : stepDown=0.1
|
||||
length = 2*math.pi * helixRadius
|
||||
if obj.HelixAngle<1: obj.HelixAngle=1
|
||||
helixAngleRad = math.pi * obj.HelixAngle/180.0
|
||||
depthPerOneCircle=length * math.tan(helixAngleRad)
|
||||
stepUp = obj.LiftDistance.Value
|
||||
if stepUp<0:
|
||||
stepUp=0
|
||||
|
||||
lx=adaptiveResults[0]["HelixCenterPoint"][0]
|
||||
ly=adaptiveResults[0]["HelixCenterPoint"][1]
|
||||
|
||||
step=0
|
||||
while passStartDepth>obj.FinalDepth.Value and step<1000:
|
||||
step=step+1
|
||||
passEndDepth=passStartDepth-stepDown
|
||||
if passEndDepth<obj.FinalDepth.Value: passEndDepth=obj.FinalDepth.Value
|
||||
|
||||
for region in adaptiveResults:
|
||||
startAngle = math.atan2(region["StartPoint"][1] - region["HelixCenterPoint"][1], region["StartPoint"][0] - region["HelixCenterPoint"][0])
|
||||
|
||||
lx=region["HelixCenterPoint"][0]
|
||||
ly=region["HelixCenterPoint"][1]
|
||||
|
||||
r = helixRadius - 0.01
|
||||
#helix ramp
|
||||
passDepth = (passStartDepth - passEndDepth)
|
||||
maxfi = passDepth / depthPerOneCircle * 2 * math.pi
|
||||
fi = 0
|
||||
offsetFi =-maxfi + startAngle-math.pi/16
|
||||
|
||||
helixStart = [region["HelixCenterPoint"][0] + r * math.cos(offsetFi), region["HelixCenterPoint"][1] + r * math.sin(offsetFi)]
|
||||
|
||||
op.commandlist.append(Path.Command("(helix to depth: %f)"%passEndDepth))
|
||||
#if step == 1:
|
||||
#rapid move to start point
|
||||
op.commandlist.append(Path.Command(
|
||||
"G0", {"X": helixStart[0], "Y": helixStart[1], "Z": obj.ClearanceHeight.Value}))
|
||||
#rapid move to safe height
|
||||
op.commandlist.append(Path.Command(
|
||||
"G0", {"X": helixStart[0], "Y": helixStart[1], "Z": obj.SafeHeight.Value}))
|
||||
|
||||
op.commandlist.append(Path.Command("G1", {
|
||||
"X": helixStart[0], "Y": helixStart[1], "Z": passStartDepth, "F": op.vertFeed}))
|
||||
|
||||
while fi<maxfi:
|
||||
x = region["HelixCenterPoint"][0] + r * math.cos(fi+offsetFi)
|
||||
y = region["HelixCenterPoint"][1] + r * math.sin(fi+offsetFi)
|
||||
z = passStartDepth - fi / maxfi * (passStartDepth - passEndDepth)
|
||||
op.commandlist.append(Path.Command("G1", { "X": x, "Y":y, "Z":z, "F": op.vertFeed}))
|
||||
lx=x
|
||||
ly=y
|
||||
fi=fi+math.pi/16
|
||||
op.commandlist.append(Path.Command("(adaptive - depth: %f)"%passEndDepth))
|
||||
#add adaptive paths
|
||||
for pth in region["AdaptivePaths"]:
|
||||
#print pth.Points
|
||||
motionType = pth[0] #[0] contains motion type
|
||||
for pt in pth[1]: #[1] contains list of points
|
||||
x=pt[0]
|
||||
y =pt[1]
|
||||
dist=math.sqrt((x-lx)*(x-lx) + (y-ly)*(y-ly))
|
||||
if motionType == area.AdaptiveMotionType.Cutting:
|
||||
op.commandlist.append(Path.Command("G1", { "X": x, "Y":y, "Z":passEndDepth, "F": op.horizFeed}))
|
||||
elif motionType == area.AdaptiveMotionType.LinkClear:
|
||||
if dist > minLiftDistance:
|
||||
if lx!=x or ly!=y:
|
||||
op.commandlist.append(Path.Command("G0", { "X": lx, "Y":ly, "Z":passEndDepth+stepUp}))
|
||||
op.commandlist.append(Path.Command("G0", { "X": x, "Y":y, "Z":passEndDepth+stepUp}))
|
||||
elif motionType == area.AdaptiveMotionType.LinkNotClear:
|
||||
if lx!=x or ly!=y:
|
||||
op.commandlist.append(Path.Command("G0", { "X": lx, "Y":ly, "Z":obj.ClearanceHeight.Value}))
|
||||
op.commandlist.append(Path.Command("G0", { "X": x, "Y":y, "Z":obj.ClearanceHeight.Value}))
|
||||
elif motionType == area.AdaptiveMotionType.LinkClearAtPrevPass:
|
||||
if lx!=x or ly!=y:
|
||||
op.commandlist.append(Path.Command("G0", { "X": lx, "Y":ly, "Z":passStartDepth+stepUp}))
|
||||
op.commandlist.append(Path.Command("G0", { "X": x, "Y":y, "Z":passStartDepth+stepUp}))
|
||||
lx=x
|
||||
ly=y
|
||||
|
||||
passStartDepth=passEndDepth
|
||||
#return to safe height in this Z pass
|
||||
op.commandlist.append(Path.Command("G0", { "X": lx, "Y":ly, "Z":obj.ClearanceHeight.Value}))
|
||||
|
||||
op.commandlist.append(Path.Command("G0", { "X": lx, "Y":ly, "Z":obj.ClearanceHeight.Value}))
|
||||
|
||||
def Execute(op,obj):
|
||||
global sceneGraph
|
||||
global topZ
|
||||
|
||||
sceneGraph = FreeCADGui.ActiveDocument.ActiveView.getSceneGraph()
|
||||
|
||||
Console.PrintMessage("*** Adaptive toolpath processing started...\n")
|
||||
|
||||
#hide old toolpaths during recalculation
|
||||
obj.Path = Path.Path("(calculating...)")
|
||||
|
||||
#store old visibility state
|
||||
job = op.getJob(obj)
|
||||
oldObjVisibility = obj.ViewObject.Visibility
|
||||
oldJobVisibility = job.ViewObject.Visibility
|
||||
|
||||
obj.ViewObject.Visibility = False
|
||||
job.ViewObject.Visibility = False
|
||||
|
||||
FreeCADGui.updateGui()
|
||||
try:
|
||||
Console.PrintMessage("Tool diam: %f \n"%op.tool.Diameter)
|
||||
helixDiameter = min(op.tool.Diameter,1000.0 if obj.HelixDiameterLimit.Value==0.0 else obj.HelixDiameterLimit.Value )
|
||||
nestingLimit=0
|
||||
topZ=op.stock.Shape.BoundBox.ZMax
|
||||
|
||||
opType = area.AdaptiveOperationType.Clearing
|
||||
obj.Stopped = False
|
||||
obj.StopProcessing = False
|
||||
if obj.Tolerance<0.001: obj.Tolerance=0.001
|
||||
|
||||
edges=[]
|
||||
for base, subs in obj.Base:
|
||||
#print (base,subs)
|
||||
for sub in subs:
|
||||
shape=base.Shape.getElement(sub)
|
||||
for edge in shape.Edges:
|
||||
edges.append(edge)
|
||||
|
||||
pathArray=connectEdges(edges)
|
||||
|
||||
if obj.OperationType == "Clearing":
|
||||
if obj.Side == "Outside":
|
||||
stockBB = op.stock.Shape.BoundBox
|
||||
v=[]
|
||||
v.append(FreeCAD.Vector(stockBB.XMin,stockBB.YMin,0))
|
||||
v.append(FreeCAD.Vector(stockBB.XMax,stockBB.YMin,0))
|
||||
v.append(FreeCAD.Vector(stockBB.XMax,stockBB.YMax,0))
|
||||
v.append(FreeCAD.Vector(stockBB.XMin,stockBB.YMax,0))
|
||||
v.append(FreeCAD.Vector(stockBB.XMin,stockBB.YMin,0))
|
||||
pathArray.append([v])
|
||||
if not obj.ProcessHoles: nestingLimit = 2
|
||||
elif not obj.ProcessHoles: nestingLimit = 1
|
||||
opType = area.AdaptiveOperationType.Clearing
|
||||
else: # profiling
|
||||
if obj.Side == "Outside":
|
||||
opType = area.AdaptiveOperationType.ProfilingOutside
|
||||
else:
|
||||
opType = area.AdaptiveOperationType.ProfilingInside
|
||||
if not obj.ProcessHoles: nestingLimit = 1
|
||||
|
||||
path2d = convertTo2d(pathArray)
|
||||
# put here all properties that influence calculation of adaptive base paths,
|
||||
inputStateObject = {
|
||||
"tool": op.tool.Diameter,
|
||||
"tolerance": obj.Tolerance,
|
||||
"geometry" : path2d,
|
||||
"stepover" :obj.StepOver,
|
||||
"effectiveHelixDiameter": helixDiameter,
|
||||
"operationType": obj.OperationType,
|
||||
"side": obj.Side,
|
||||
"processHoles": obj.ProcessHoles
|
||||
|
||||
}
|
||||
|
||||
inputStateChanged=False
|
||||
adaptiveResults=None
|
||||
|
||||
if obj.AdaptiveOutputState !=None and obj.AdaptiveOutputState != "":
|
||||
adaptiveResults = obj.AdaptiveOutputState
|
||||
|
||||
if json.dumps(obj.AdaptiveInputState) != json.dumps(inputStateObject):
|
||||
inputStateChanged=True
|
||||
adaptiveResults=None
|
||||
|
||||
# progress callback fn, if return true it will stop processing
|
||||
def progressFn(tpaths):
|
||||
for path in tpaths: #path[0] contains the MotionType,#path[1] contains list of points
|
||||
sceneDrawPath(path[1])
|
||||
FreeCADGui.updateGui()
|
||||
return obj.StopProcessing
|
||||
|
||||
start=time.time()
|
||||
|
||||
if inputStateChanged or adaptiveResults==None:
|
||||
a2d = area.Adaptive2d()
|
||||
a2d.stepOverFactor = 0.01*obj.StepOver
|
||||
a2d.toolDiameter = op.tool.Diameter
|
||||
a2d.helixRampDiameter = helixDiameter
|
||||
a2d.tolerance = obj.Tolerance
|
||||
a2d.opType = opType
|
||||
a2d.polyTreeNestingLimit = nestingLimit
|
||||
#EXECUTE
|
||||
results = a2d.Execute(path2d,progressFn)
|
||||
|
||||
#need to convert results to python object to be JSON serializable
|
||||
adaptiveResults = []
|
||||
for result in results:
|
||||
adaptiveResults.append({
|
||||
"HelixCenterPoint": result.HelixCenterPoint,
|
||||
"StartPoint": result.StartPoint,
|
||||
"AdaptivePaths": result.AdaptivePaths,
|
||||
"ReturnMotionType": result.ReturnMotionType })
|
||||
|
||||
|
||||
|
||||
GenerateGCode(op,obj,adaptiveResults,helixDiameter)
|
||||
|
||||
if not obj.StopProcessing:
|
||||
Console.PrintMessage("*** Done. Elapsed: %f sec\n\n" %(time.time()-start))
|
||||
obj.AdaptiveOutputState = adaptiveResults
|
||||
obj.AdaptiveInputState=inputStateObject
|
||||
else:
|
||||
Console.PrintMessage("*** Processing cancelled (after: %f sec).\n\n" %(time.time()-start))
|
||||
finally:
|
||||
obj.ViewObject.Visibility = oldObjVisibility
|
||||
job.ViewObject.Visibility = oldJobVisibility
|
||||
sceneClean()
|
||||
|
||||
|
||||
|
||||
class PathAdaptive(PathOp.ObjectOp):
|
||||
def opFeatures(self, obj):
|
||||
'''opFeatures(obj) ... returns the OR'ed list of features used and supported by the operation.
|
||||
The default implementation returns "FeatureTool | FeatureDeptsh | FeatureHeights | FeatureStartPoint"
|
||||
Should be overwritten by subclasses.'''
|
||||
return PathOp.FeatureTool | PathOp.FeatureBaseEdges | PathOp.FeatureDepths | PathOp.FeatureStepDown | PathOp.FeatureHeights | PathOp.FeatureBaseGeometry
|
||||
|
||||
def initOperation(self, obj):
|
||||
'''initOperation(obj) ... implement to create additional properties.
|
||||
Should be overwritten by subclasses.'''
|
||||
obj.addProperty("App::PropertyEnumeration", "Side", "Adaptive", "Side of selected faces that tool should cut")
|
||||
obj.Side = ['Outside', 'Inside'] # side of profile that cutter is on in relation to direction of profile
|
||||
|
||||
obj.addProperty("App::PropertyEnumeration", "OperationType", "Adaptive", "Type of adaptive operation")
|
||||
obj.OperationType = ['Clearing', 'Profiling'] # side of profile that cutter is on in relation to direction of profile
|
||||
|
||||
obj.addProperty("App::PropertyFloat", "Tolerance", "Adaptive", "Influences accuracy and performance")
|
||||
obj.addProperty("App::PropertyPercent", "StepOver", "Adaptive", "Percent of cutter diameter to step over on each pass")
|
||||
obj.addProperty("App::PropertyDistance", "LiftDistance", "Adaptive", "Lift distance for rapid moves")
|
||||
obj.addProperty("App::PropertyBool", "ProcessHoles", "Adaptive","Process holes as well as the face outline")
|
||||
obj.addProperty("App::PropertyBool", "Stopped",
|
||||
"Adaptive", "Stop processing")
|
||||
obj.setEditorMode('Stopped', 2) #hide this property
|
||||
|
||||
obj.addProperty("App::PropertyBool", "StopProcessing",
|
||||
"Adaptive", "Stop processing")
|
||||
obj.setEditorMode('StopProcessing', 2) # hide this property
|
||||
|
||||
obj.addProperty("App::PropertyPythonObject", "AdaptiveInputState",
|
||||
"Adaptive", "Internal input state")
|
||||
obj.addProperty("App::PropertyPythonObject", "AdaptiveOutputState",
|
||||
"Adaptive", "Internal output state")
|
||||
obj.setEditorMode('AdaptiveInputState', 2) #hide this property
|
||||
obj.setEditorMode('AdaptiveOutputState', 2) #hide this property
|
||||
obj.addProperty("App::PropertyAngle", "HelixAngle", "Adaptive", "Helix ramp entry angle (degrees)")
|
||||
obj.addProperty("App::PropertyLength", "HelixDiameterLimit", "Adaptive", "Limit helix entry diameter, if limit larger than tool diameter or 0, tool diameter is used")
|
||||
|
||||
|
||||
def opSetDefaultValues(self, obj):
|
||||
obj.Side="Inside"
|
||||
obj.OperationType = "Clearing"
|
||||
obj.Tolerance = 0.1
|
||||
obj.StepOver = 20
|
||||
obj.LiftDistance=1.0
|
||||
obj.ProcessHoles = True
|
||||
obj.Stopped = False
|
||||
obj.StopProcessing = False
|
||||
obj.HelixAngle = 5
|
||||
obj.HelixDiameterLimit = 0.0
|
||||
obj.AdaptiveInputState =""
|
||||
obj.AdaptiveOutputState = ""
|
||||
|
||||
def opExecute(self, obj):
|
||||
'''opExecute(obj) ... called whenever the receiver needs to be recalculated.
|
||||
See documentation of execute() for a list of base functionality provided.
|
||||
Should be overwritten by subclasses.'''
|
||||
Execute(self,obj)
|
||||
|
||||
|
||||
|
||||
def Create(name):
|
||||
'''Create(name) ... Creates and returns a Pocket operation.'''
|
||||
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
|
||||
proxy = PathAdaptive(obj)
|
||||
return obj
|
||||
168
src/Mod/Path/PathScripts/PathAdaptiveGui.py
Normal file
168
src/Mod/Path/PathScripts/PathAdaptiveGui.py
Normal file
@@ -0,0 +1,168 @@
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
import PathScripts.PathLog as PathLog
|
||||
import PathScripts.PathGui as PathGui
|
||||
import PathScripts.PathOpGui as PathOpGui
|
||||
from PySide import QtCore, QtGui
|
||||
import PathAdaptive
|
||||
|
||||
class TaskPanelOpPage(PathOpGui.TaskPanelPage):
|
||||
def initPage(self, obj):
|
||||
self.setTitle("Adaptive path operation")
|
||||
|
||||
def getForm(self):
|
||||
form = QtGui.QWidget()
|
||||
layout = QtGui.QVBoxLayout()
|
||||
|
||||
#tool contoller
|
||||
hlayout = QtGui.QHBoxLayout()
|
||||
form.ToolController = QtGui.QComboBox()
|
||||
form.ToolControllerLabel=QtGui.QLabel("Tool Controller")
|
||||
hlayout.addWidget(form.ToolControllerLabel)
|
||||
hlayout.addWidget(form.ToolController)
|
||||
layout.addLayout(hlayout)
|
||||
|
||||
#cut region
|
||||
formLayout = QtGui.QFormLayout()
|
||||
form.Side = QtGui.QComboBox()
|
||||
form.Side.addItem("Inside")
|
||||
form.Side.addItem("Outside")
|
||||
form.Side.setToolTip("Cut inside or outside of the selected face")
|
||||
formLayout.addRow(QtGui.QLabel("Cut Region"),form.Side)
|
||||
|
||||
#operation type
|
||||
form.OperationType = QtGui.QComboBox()
|
||||
form.OperationType.addItem("Clearing")
|
||||
form.OperationType.addItem("Profiling")
|
||||
form.OperationType.setToolTip("Type of adaptive operation")
|
||||
formLayout.addRow(QtGui.QLabel("Operation Type"),form.OperationType)
|
||||
|
||||
#step over
|
||||
form.StepOver = QtGui.QSpinBox()
|
||||
form.StepOver.setMinimum(15)
|
||||
form.StepOver.setMaximum(50)
|
||||
form.StepOver.setSingleStep(1)
|
||||
form.StepOver.setValue(25)
|
||||
form.StepOver.setToolTip("Tool step over percentage")
|
||||
formLayout.addRow(QtGui.QLabel("Step Over Percent"),form.StepOver)
|
||||
|
||||
#tolerance
|
||||
form.Tolerance = QtGui.QSlider(QtCore.Qt.Horizontal)
|
||||
form.Tolerance.setMinimum(5)
|
||||
form.Tolerance.setMaximum(15)
|
||||
form.Tolerance.setTickInterval(1)
|
||||
form.Tolerance.setValue(10)
|
||||
form.Tolerance.setTickPosition(QtGui.QSlider.TicksBelow)
|
||||
form.Tolerance.setToolTip("Influences calculation performace vs stability and accuracy")
|
||||
formLayout.addRow(QtGui.QLabel("Accuracy vs Performance"),form.Tolerance)
|
||||
|
||||
#helix angle
|
||||
form.HelixAngle = QtGui.QDoubleSpinBox()
|
||||
form.HelixAngle.setMinimum(0.1)
|
||||
form.HelixAngle.setMaximum(90)
|
||||
form.HelixAngle.setSingleStep(0.1)
|
||||
form.HelixAngle.setValue(5)
|
||||
form.HelixAngle.setToolTip("Angle of the helix ramp entry")
|
||||
formLayout.addRow(QtGui.QLabel("Helix Ramp Angle"),form.HelixAngle)
|
||||
|
||||
#helix diam. limit
|
||||
form.HelixDiameterLimit = QtGui.QDoubleSpinBox()
|
||||
form.HelixDiameterLimit.setMinimum(0.0)
|
||||
form.HelixDiameterLimit.setMaximum(90)
|
||||
form.HelixDiameterLimit.setSingleStep(0.1)
|
||||
form.HelixDiameterLimit.setValue(0)
|
||||
form.HelixDiameterLimit.setToolTip("If non zero it limits the size helix diameter, otherwise the tool radius is taken as the helix diameter")
|
||||
formLayout.addRow(QtGui.QLabel("Helix Max Diameter"),form.HelixDiameterLimit)
|
||||
|
||||
#lift distance
|
||||
form.LiftDistance = QtGui.QDoubleSpinBox()
|
||||
form.LiftDistance.setMinimum(0.0)
|
||||
form.LiftDistance.setMaximum(1000)
|
||||
form.LiftDistance.setSingleStep(0.1)
|
||||
form.LiftDistance.setValue(1.0)
|
||||
form.LiftDistance.setToolTip("How much to lift the tool up during the rapid repositioning moves (used when no obstacles)")
|
||||
formLayout.addRow(QtGui.QLabel("Lift Distance"),form.LiftDistance)
|
||||
|
||||
#process holes
|
||||
form.ProcessHoles = QtGui.QCheckBox()
|
||||
form.ProcessHoles.setChecked(True)
|
||||
formLayout.addRow(QtGui.QLabel("Process Holes"),form.ProcessHoles)
|
||||
|
||||
layout.addLayout(formLayout)
|
||||
|
||||
#stop button
|
||||
form.StopButton=QtGui.QPushButton("Stop")
|
||||
form.StopButton.setCheckable(True)
|
||||
layout.addWidget(form.StopButton)
|
||||
|
||||
form.setLayout(layout)
|
||||
return form
|
||||
|
||||
def getSignalsForUpdate(self, obj):
|
||||
'''getSignalsForUpdate(obj) ... return list of signals for updating obj'''
|
||||
signals = []
|
||||
#signals.append(self.form.button.clicked)
|
||||
signals.append(self.form.Side.currentIndexChanged)
|
||||
signals.append(self.form.OperationType.currentIndexChanged)
|
||||
signals.append(self.form.ToolController.currentIndexChanged)
|
||||
signals.append(self.form.StepOver.valueChanged)
|
||||
signals.append(self.form.Tolerance.valueChanged)
|
||||
signals.append(self.form.HelixAngle.valueChanged)
|
||||
signals.append(self.form.HelixDiameterLimit.valueChanged)
|
||||
signals.append(self.form.LiftDistance.valueChanged)
|
||||
|
||||
signals.append(self.form.ProcessHoles.stateChanged)
|
||||
signals.append(self.form.StopButton.toggled)
|
||||
return signals
|
||||
|
||||
def setFields(self, obj):
|
||||
self.selectInComboBox(obj.Side, self.form.Side)
|
||||
self.selectInComboBox(obj.OperationType, self.form.OperationType)
|
||||
self.form.StepOver.setValue(obj.StepOver)
|
||||
self.form.Tolerance.setValue(int(obj.Tolerance*100))
|
||||
self.form.HelixAngle.setValue(obj.HelixAngle)
|
||||
self.form.HelixDiameterLimit.setValue(obj.HelixDiameterLimit)
|
||||
self.form.LiftDistance.setValue(obj.LiftDistance)
|
||||
|
||||
self.form.ProcessHoles.setChecked(obj.ProcessHoles)
|
||||
self.setupToolController(obj, self.form.ToolController)
|
||||
self.form.StopButton.setChecked(obj.Stopped)
|
||||
obj.setEditorMode('AdaptiveInputState', 2) #hide this property
|
||||
obj.setEditorMode('AdaptiveOutputState', 2) #hide this property
|
||||
obj.setEditorMode('StopProcessing', 2) # hide this property
|
||||
obj.setEditorMode('Stopped', 2) # hide this property
|
||||
|
||||
def getFields(self, obj):
|
||||
if obj.Side != str(self.form.Side.currentText()):
|
||||
obj.Side = str(self.form.Side.currentText())
|
||||
|
||||
if obj.OperationType != str(self.form.OperationType.currentText()):
|
||||
obj.OperationType = str(self.form.OperationType.currentText())
|
||||
|
||||
obj.StepOver = self.form.StepOver.value()
|
||||
obj.Tolerance = 1.0*self.form.Tolerance.value()/100.0
|
||||
obj.HelixAngle = self.form.HelixAngle.value()
|
||||
obj.HelixDiameterLimit = self.form.HelixDiameterLimit.value()
|
||||
obj.LiftDistance = self.form.LiftDistance.value()
|
||||
|
||||
obj.ProcessHoles = self.form.ProcessHoles.isChecked()
|
||||
obj.Stopped = self.form.StopButton.isChecked()
|
||||
if(obj.Stopped):
|
||||
self.form.StopButton.setChecked(False) #reset the button
|
||||
obj.StopProcessing=True
|
||||
|
||||
self.updateToolController(obj, self.form.ToolController)
|
||||
obj.setEditorMode('AdaptiveInputState', 2) #hide this property
|
||||
obj.setEditorMode('AdaptiveOutputState', 2) #hide this property
|
||||
obj.setEditorMode('StopProcessing', 2) # hide this property
|
||||
obj.setEditorMode('Stopped', 2) # hide this property
|
||||
|
||||
|
||||
|
||||
|
||||
Command = PathOpGui.SetupOperation('Adaptive',
|
||||
PathAdaptive.Create,
|
||||
TaskPanelOpPage,
|
||||
'Path-Adaptive',
|
||||
QtCore.QT_TRANSLATE_NOOP("PathAdaptive", "Adaptive"),
|
||||
QtCore.QT_TRANSLATE_NOOP("PathPocket", "Adaptive clearing and profiling"))
|
||||
@@ -157,6 +157,31 @@ class POCKETGate:
|
||||
|
||||
return pocketable
|
||||
|
||||
class ADAPTIVEGate:
|
||||
def allow(self, doc, obj, sub):
|
||||
|
||||
adaptive = False
|
||||
try:
|
||||
obj = obj.Shape
|
||||
except:
|
||||
return False
|
||||
|
||||
if obj.ShapeType == 'Edge':
|
||||
adaptive = False
|
||||
|
||||
elif obj.ShapeType == 'Face':
|
||||
adaptive = True
|
||||
|
||||
elif obj.ShapeType == 'Solid':
|
||||
if sub and sub[0:4] == 'Face':
|
||||
adaptive = True
|
||||
|
||||
elif obj.ShapeType == 'Compound':
|
||||
if sub and sub[0:4] == 'Face':
|
||||
adaptive = True
|
||||
|
||||
return adaptive
|
||||
|
||||
class CONTOURGate:
|
||||
def allow(self, doc, obj, sub):
|
||||
pass
|
||||
@@ -189,6 +214,10 @@ def pocketselect():
|
||||
FreeCADGui.Selection.addSelectionGate(POCKETGate())
|
||||
FreeCAD.Console.PrintWarning("Pocketing Select Mode\n")
|
||||
|
||||
def adaptiveselect():
|
||||
FreeCADGui.Selection.addSelectionGate(ADAPTIVEGate())
|
||||
FreeCAD.Console.PrintWarning("Adaptive Select Mode\n")
|
||||
|
||||
def surfaceselect():
|
||||
FreeCADGui.Selection.addSelectionGate(MESHGate())
|
||||
FreeCAD.Console.PrintWarning("Surfacing Select Mode\n")
|
||||
@@ -207,6 +236,7 @@ def select(op):
|
||||
opsel['Profile Edges'] = eselect
|
||||
opsel['Profile Faces'] = profileselect
|
||||
opsel['Surface'] = surfaceselect
|
||||
opsel['Adaptive'] = adaptiveselect
|
||||
return opsel[op]
|
||||
|
||||
def clear():
|
||||
|
||||
1451
src/Mod/Path/libarea/Adaptive.cpp
Normal file
1451
src/Mod/Path/libarea/Adaptive.cpp
Normal file
File diff suppressed because it is too large
Load Diff
109
src/Mod/Path/libarea/Adaptive.hpp
Normal file
109
src/Mod/Path/libarea/Adaptive.hpp
Normal file
@@ -0,0 +1,109 @@
|
||||
#include "clipper.hpp"
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
#ifndef ADAPTIVE_HPP
|
||||
#define ADAPTIVE_HPP
|
||||
|
||||
//#define DEV_MODE
|
||||
|
||||
#define NTOL 1.0e-7 // numeric tolerance
|
||||
|
||||
namespace AdaptivePath {
|
||||
using namespace ClipperLib;
|
||||
|
||||
enum MotionType { mtCutting = 0, mtLinkClear = 1, mtLinkNotClear = 2, mtLinkClearAtPrevPass = 3 };
|
||||
|
||||
enum OperationType { otClearing = 0, otProfilingInside = 1, otProfilingOutside = 2 };
|
||||
|
||||
typedef std::pair<double,double> DPoint;
|
||||
typedef std::vector<DPoint> DPath;
|
||||
typedef std::vector<DPath> DPaths;
|
||||
typedef std::pair<int,DPath> TPath; // first parameter is MotionType, must use int due to problem with serialization to JSON in python
|
||||
|
||||
// struct TPath { #this does not work correctly with pybind, changed to pair
|
||||
// DPath Points;
|
||||
// MotionType MType;
|
||||
// };
|
||||
|
||||
typedef std::vector<TPath> TPaths;
|
||||
|
||||
struct AdaptiveOutput {
|
||||
DPoint HelixCenterPoint;
|
||||
DPoint StartPoint;
|
||||
TPaths AdaptivePaths;
|
||||
int ReturnMotionType; // MotionType enum, problem with serialization if enum is used
|
||||
};
|
||||
|
||||
// used to isolate state -> enable potential adding of multi-threaded processing of separate regions
|
||||
|
||||
class Adaptive2d {
|
||||
public:
|
||||
Adaptive2d();
|
||||
double toolDiameter=5;
|
||||
double helixRampDiameter=0;
|
||||
double stepOverFactor = 0.2;
|
||||
int polyTreeNestingLimit=0;
|
||||
double tolerance=0.1;
|
||||
OperationType opType = OperationType::otClearing;
|
||||
|
||||
std::list<AdaptiveOutput> Execute(const DPaths &paths, std::function<bool(TPaths)> progressCallbackFn);
|
||||
|
||||
#ifdef DEV_MODE
|
||||
/*for debugging*/
|
||||
std::function<void(double cx,double cy, double radius, int color)> DrawCircleFn;
|
||||
std::function<void(const DPath &, int color)> DrawPathFn;
|
||||
std::function<void()> ClearScreenFn;
|
||||
#endif
|
||||
|
||||
private:
|
||||
std::list<AdaptiveOutput> results;
|
||||
Paths inputPaths;
|
||||
|
||||
double scaleFactor=100;
|
||||
long toolRadiusScaled=10;
|
||||
long finishPassOffsetScaled=0;
|
||||
long helixRampRadiusScaled=0;
|
||||
long bbox_size=0;
|
||||
double referenceCutArea=0;
|
||||
double optimalCutAreaPD=0;
|
||||
double minCutAreaPD=0;
|
||||
bool stopProcessing=false;
|
||||
|
||||
time_t lastProgressTime = 0;
|
||||
|
||||
std::function<bool(TPaths)> * progressCallback=NULL;
|
||||
Path toolGeometry; // tool geometry at coord 0,0, should not be modified
|
||||
|
||||
void ProcessPolyNode(Paths & boundPaths, Paths & toolBoundPaths);
|
||||
bool FindEntryPoint(const Paths & toolBoundPaths,const Paths &bound, Paths &cleared /*output*/, IntPoint &entryPoint /*output*/);
|
||||
double CalcCutArea(Clipper & clip,const IntPoint &toolPos, const IntPoint &newToolPos, const Paths &cleared_paths);
|
||||
void AppendToolPath(AdaptiveOutput & output,const Path & passToolPath,const Paths & cleared, bool close=false);
|
||||
bool CheckCollision(const IntPoint &lastPoint,const IntPoint &nextPoint,const Paths & cleared);
|
||||
friend class EngagePoint; // for CalcCutArea
|
||||
|
||||
void CheckReportProgress(TPaths &progressPaths,bool force=false);
|
||||
|
||||
private: // constants for fine tuning
|
||||
const bool preventConvetionalMode = true;
|
||||
const double RESOLUTION_FACTOR = 8.0;
|
||||
const int MAX_ITERATIONS = 16;
|
||||
const double AREA_ERROR_FACTOR = 0.05; /* how precise to match the cut area to optimal, reasonable value: 0.05 = 5%*/
|
||||
const size_t ANGLE_HISTORY_POINTS=3; // used for angle prediction
|
||||
const int DIRECTION_SMOOTHING_BUFLEN=3; // gyro points - used for angle smoothing
|
||||
|
||||
const double ENGAGE_AREA_THR_FACTOR=0.2; // influences minimal engage area (factor relation to optimal)
|
||||
const double ENGAGE_SCAN_DISTANCE_FACTOR=0.1; // influences the engage scan/stepping distance
|
||||
|
||||
const double CLEAN_PATH_TOLERANCE = 1;
|
||||
const double FINISHING_CLEAN_PATH_TOLERANCE = 0.5;
|
||||
|
||||
// used for filtering out of insignificant cuts:
|
||||
const double MIN_CUT_AREA_FACTOR = 0.02; // influences filtering of cuts that with cumulative area below threshold, reasonable value is between 0.01 and 0.1
|
||||
|
||||
const long PASSES_LIMIT = __LONG_MAX__; // limit used while debugging
|
||||
const long POINTS_PER_PASS_LIMIT = __LONG_MAX__; // limit used while debugging
|
||||
const time_t PROGRESS_TICKS = CLOCKS_PER_SEC/20; // progress report interval
|
||||
};
|
||||
}
|
||||
#endif
|
||||
@@ -60,6 +60,7 @@ set(AREA_SRC_COMMON
|
||||
|
||||
set(AREA_SRC_CLIPPER
|
||||
AreaClipper.cpp
|
||||
Adaptive.cpp
|
||||
clipper.cpp
|
||||
)
|
||||
|
||||
@@ -99,6 +100,7 @@ add_library(
|
||||
${PYAREA_SRC}
|
||||
)
|
||||
|
||||
|
||||
if(MSVC)
|
||||
set(area_native_LIBS
|
||||
debug MSVCRTD.LIB
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Point.h"
|
||||
#include "AreaDxf.h"
|
||||
#include "kurve/geometry.h"
|
||||
#include "Adaptive.hpp"
|
||||
|
||||
#if defined (_POSIX_C_SOURCE)
|
||||
# undef _POSIX_C_SOURCE
|
||||
@@ -38,6 +39,7 @@
|
||||
#include <boost/python/wrapper.hpp>
|
||||
#include <boost/python/call.hpp>
|
||||
|
||||
|
||||
#include "clipper.hpp"
|
||||
using namespace ClipperLib;
|
||||
|
||||
@@ -237,7 +239,6 @@ boost::python::list spanIntersect(const Span& span1, const Span& span2) {
|
||||
}
|
||||
|
||||
//Matrix(boost::python::list &l){}
|
||||
|
||||
boost::shared_ptr<geoff_geometry::Matrix> matrix_constructor(const boost::python::list& lst) {
|
||||
double m[16] = {1,0,0,0,0,1,0,0, 0,0,1,0, 0,0,0,1};
|
||||
|
||||
@@ -291,8 +292,70 @@ double AreaGetArea(const CArea& a)
|
||||
return a.GetArea();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Adaptive2d.Execute wrapper
|
||||
bp::list AdaptiveExecute(AdaptivePath::Adaptive2d& ada,const boost::python::list &in_paths, boost::python::object progressCallbackFn) {
|
||||
bp::list out_list;
|
||||
// convert inputs
|
||||
AdaptivePath::DPaths dpaths;
|
||||
for(bp::ssize_t i=0;i<bp::len(in_paths);i++) {
|
||||
bp::list in_path=bp::extract<boost::python::list>(in_paths[i]);
|
||||
AdaptivePath::DPath dpath;
|
||||
for(bp::ssize_t j=0;j<bp::len(in_path);j++) {
|
||||
bp::list in_point = bp::extract<bp::list>(in_path[j]);
|
||||
dpath.push_back(pair<double,double>(bp::extract<double>(in_point[0]),bp::extract<double>(in_point[1])));
|
||||
}
|
||||
dpaths.push_back(dpath);
|
||||
}
|
||||
// Execute with callback
|
||||
std::list<AdaptivePath::AdaptiveOutput> result=ada.Execute(dpaths,[progressCallbackFn](AdaptivePath::TPaths tp)->bool {
|
||||
bp::list out_paths;
|
||||
for(const auto & in_pair : tp) {
|
||||
bp::list path;
|
||||
for(const auto & in_pt : in_pair.second) {
|
||||
path.append(bp::make_tuple(in_pt.first,in_pt.second));
|
||||
}
|
||||
out_paths.append(bp::make_tuple(in_pair.first,path));
|
||||
}
|
||||
return bp::extract<bool>(progressCallbackFn(out_paths));
|
||||
});
|
||||
// convert outputs back
|
||||
BOOST_FOREACH(const auto & res, result) {
|
||||
out_list.append(res);
|
||||
}
|
||||
return out_list;
|
||||
}
|
||||
|
||||
// Converts a std::pair instance to a Python tuple.
|
||||
template <typename T1, typename T2>
|
||||
struct std_pair_to_tuple
|
||||
{
|
||||
static PyObject* convert(std::pair<T1, T2> const& p)
|
||||
{
|
||||
return boost::python::incref(
|
||||
boost::python::make_tuple(p.first, p.second).ptr());
|
||||
}
|
||||
static PyTypeObject const *get_pytype () {
|
||||
return &PyTuple_Type;
|
||||
}
|
||||
};
|
||||
|
||||
boost::python::list AdaptiveOutput_AdaptivePaths(const AdaptivePath::AdaptiveOutput &ado) {
|
||||
bp::list olist;
|
||||
for(auto & ap : ado.AdaptivePaths) {
|
||||
bp::list op;
|
||||
for(auto & pt : ap.second) {
|
||||
op.append(bp::make_tuple(pt.first, pt.second));
|
||||
}
|
||||
olist.append(bp::make_tuple(ap.first, op));
|
||||
}
|
||||
return olist;
|
||||
}
|
||||
|
||||
|
||||
BOOST_PYTHON_MODULE(area) {
|
||||
bp::class_<Point>("Point")
|
||||
bp::class_<Point>("Point")
|
||||
.def(bp::init<double, double>())
|
||||
.def(bp::init<Point>())
|
||||
.def(bp::other<double>() * bp::self)
|
||||
@@ -418,4 +481,43 @@ BOOST_PYTHON_MODULE(area) {
|
||||
bp::def("holes_linked", holes_linked);
|
||||
bp::def("AreaFromDxf", AreaFromDxf);
|
||||
bp::def("TangentialArc", TangentialArc);
|
||||
|
||||
|
||||
using namespace AdaptivePath;
|
||||
|
||||
boost::python::to_python_converter<std::pair<double, double>, std_pair_to_tuple<double, double>,true>();
|
||||
|
||||
|
||||
bp::enum_<MotionType>("AdaptiveMotionType")
|
||||
.value("Cutting", MotionType::mtCutting)
|
||||
.value("LinkClear", MotionType::mtLinkClear)
|
||||
.value("LinkNotClear", MotionType::mtLinkNotClear)
|
||||
.value("LinkClearAtPrevPass", MotionType::mtLinkClearAtPrevPass);
|
||||
|
||||
bp::enum_<OperationType>("AdaptiveOperationType")
|
||||
.value("Clearing", OperationType::otClearing)
|
||||
.value("ProfilingInside", OperationType::otProfilingInside)
|
||||
.value("ProfilingOutside", OperationType::otProfilingOutside);
|
||||
|
||||
bp::class_<AdaptiveOutput> ("AdaptiveOutput")
|
||||
.def(bp::init<>())
|
||||
.add_property("HelixCenterPoint", bp::make_getter(&AdaptiveOutput::HelixCenterPoint, bp::return_value_policy<bp::return_by_value>()))
|
||||
.add_property("StartPoint", bp::make_getter(&AdaptiveOutput::StartPoint, bp::return_value_policy<bp::return_by_value>()))
|
||||
.add_property("AdaptivePaths", &AdaptiveOutput_AdaptivePaths)
|
||||
.def_readonly("ReturnMotionType",&AdaptiveOutput::ReturnMotionType);
|
||||
|
||||
bp::class_<Adaptive2d>("Adaptive2d")
|
||||
.def(bp::init<>())
|
||||
.def("Execute",&AdaptiveExecute)
|
||||
.def_readwrite("stepOverFactor", &Adaptive2d::stepOverFactor)
|
||||
.def_readwrite("toolDiameter", &Adaptive2d::toolDiameter)
|
||||
.def_readwrite("helixRampDiameter", &Adaptive2d::helixRampDiameter)
|
||||
.def_readwrite("polyTreeNestingLimit", &Adaptive2d::polyTreeNestingLimit)
|
||||
.def_readwrite("tolerance", &Adaptive2d::tolerance)
|
||||
.def_readwrite("opType", &Adaptive2d::opType);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "Point.h"
|
||||
#include "AreaDxf.h"
|
||||
#include "kurve/geometry.h"
|
||||
#include "Adaptive.hpp"
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
@@ -358,9 +359,46 @@ void init_pyarea(py::module &m){
|
||||
m.def("holes_linked", holes_linked);
|
||||
m.def("AreaFromDxf", AreaFromDxf);
|
||||
m.def("TangentialArc", TangentialArc);
|
||||
|
||||
using namespace AdaptivePath;
|
||||
py::enum_<MotionType>(m, "AdaptiveMotionType")
|
||||
.value("Cutting", MotionType::mtCutting)
|
||||
.value("LinkClear", MotionType::mtLinkClear)
|
||||
.value("LinkNotClear", MotionType::mtLinkNotClear)
|
||||
.value("LinkClearAtPrevPass", MotionType::mtLinkClearAtPrevPass);
|
||||
|
||||
py::enum_<OperationType>(m, "AdaptiveOperationType")
|
||||
.value("Clearing", OperationType::otClearing)
|
||||
.value("ProfilingInside", OperationType::otProfilingInside)
|
||||
.value("ProfilingOutside", OperationType::otProfilingOutside);
|
||||
|
||||
py::class_<AdaptiveOutput>(m, "AdaptiveOutput")
|
||||
.def(py::init<>())
|
||||
.def_readwrite("HelixCenterPoint",&AdaptiveOutput::HelixCenterPoint)
|
||||
.def_readwrite("StartPoint",&AdaptiveOutput::StartPoint)
|
||||
.def_readwrite("AdaptivePaths",&AdaptiveOutput::AdaptivePaths)
|
||||
.def_readwrite("ReturnMotionType",&AdaptiveOutput::ReturnMotionType);
|
||||
|
||||
py::class_<Adaptive2d>(m, "Adaptive2d")
|
||||
.def(py::init<>())
|
||||
.def("Execute",&Adaptive2d::Execute)
|
||||
.def_readwrite("stepOverFactor", &Adaptive2d::stepOverFactor)
|
||||
.def_readwrite("toolDiameter", &Adaptive2d::toolDiameter)
|
||||
.def_readwrite("helixRampDiameter", &Adaptive2d::helixRampDiameter)
|
||||
.def_readwrite("polyTreeNestingLimit", &Adaptive2d::polyTreeNestingLimit)
|
||||
.def_readwrite("tolerance", &Adaptive2d::tolerance)
|
||||
.def_readwrite("opType", &Adaptive2d::opType);
|
||||
}
|
||||
|
||||
PYBIND11_MODULE(area, m){
|
||||
m.doc()= "not yet";
|
||||
init_pyarea(m);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
using namespace AdaptivePath;
|
||||
PYBIND11_MODULE(AdaptivePath, m){
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user