New feature pack: Subsequencing and TopoSeries

This commit is contained in:
DeepSOIC 2017-01-15 22:39:17 +03:00
parent 1246a85e74
commit d609d265de
22 changed files with 2565 additions and 59 deletions

View File

@ -73,7 +73,7 @@ class Lattice2Workbench (Workbench):
+ Lattice2.CompoundFeatures.Slice.exportedCommands
+ Lattice2.CompoundFeatures.BoundBox.exportedCommands
+ Lattice2.CompoundFeatures.ShapeString.exportedCommands
+ Lattice2.CompoundFeatures.ParaSeries.exportedCommands
+ Lattice2.CompoundFeatures.SeriesGroup.exportedCommands
)
self.appendToolbar('Lattice2CompoundFeatures', cmdsCompoundTools)
self.appendMenu('Lattice2', cmdsCompoundTools)

View File

@ -6,4 +6,6 @@ import lattice2GeomUtils as GeomUtils
import lattice2InterpolatorUtil as InterpolatorUtil
import lattice2Markers as Markers
import lattice2ValueSeriesGenerator as ValueSeriesGenerator
import lattice2ShapeCopy as ShapeCopy
import lattice2ShapeCopy as ShapeCopy
import lattice2Subsequencer as Subsequencer
import lattice2Utils as Utils

View File

@ -7,4 +7,6 @@ import lattice2BoundBox as BoundBox
import lattice2ShapeString as ShapeString
import lattice2MakeCompound as MakeCompound
import lattice2ParaSeries as ParaSeries
import lattice2TopoSeries as TopoSeries
import lattice2SeriesGroup as SeriesGroup
import lattice2Slice as Slice

View File

@ -3,6 +3,7 @@
<file>icons/Lattice2_ArrayFilter.svg</file>
<file>icons/Lattice2_ArrayFromShape.svg</file>
<file>icons/Lattice2_AttachablePlacement.svg</file>
<file>icons/Lattice2_AttachedPlacementSubsequence.svg</file>
<file>icons/Lattice2_BoundBox.svg</file>
<file>icons/Lattice2_BoundBox_Compound.svg</file>
<file>icons/Lattice2_CompoundFilter.svg</file>
@ -52,6 +53,11 @@
<file>icons/Lattice2_SubLink_Edge.svg</file>
<file>icons/Lattice2_SubLink_Face.svg</file>
<file>icons/Lattice2_SubLink_Vertex.svg</file>
<file>icons/Lattice2_SubLinkSubsequence.svg</file>
<file>icons/Lattice2_SubLinkSubsequence_Edge.svg</file>
<file>icons/Lattice2_SubLinkSubsequence_Face.svg</file>
<file>icons/Lattice2_SubLinkSubsequence_Vertex.svg</file>
<file>icons/Lattice2_SubstituteObject.svg</file>
<file>icons/Lattice2_TopoSeries.svg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,251 @@
<?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="svg2726"
sodipodi:version="0.32"
inkscape:version="0.48.4 r9939"
sodipodi:docname="Lattice2_AttachablePlacement.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs2728">
<linearGradient
id="linearGradient3766">
<stop
style="stop-color:#004bed;stop-opacity:1;"
offset="0"
id="stop3768" />
<stop
style="stop-color:#bbd7ff;stop-opacity:1;"
offset="1"
id="stop3770" />
</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="perspective2734" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3144-4"
id="radialGradient3850-9"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,0.6985294,0,202.82863)"
cx="225.26402"
cy="672.79736"
fx="225.26402"
fy="672.79736"
r="34.345188" />
<linearGradient
inkscape:collect="always"
id="linearGradient3144-4">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop3146-2" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop3148-0" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient3772"
x1="21.905107"
y1="26.587624"
x2="35.65699"
y2="29.344099"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient3774"
x1="-670.94934"
y1="-470.34324"
x2="-296.345"
y2="-470.34324"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.89593793,0,0,0.89568922,-15.05163,-57.346577)" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="7.7781746"
inkscape:cx="-10.770151"
inkscape:cy="23.597166"
inkscape:current-layer="g4289"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="986"
inkscape:window-x="-11"
inkscape:window-y="-11"
inkscape:window-maximized="1"
inkscape:snap-global="false"
inkscape:object-paths="false"
inkscape:object-nodes="true"
inkscape:snap-nodes="true" />
<metadata
id="metadata2731">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g4289"
transform="matrix(0.1621282,0,0,0.1621282,6.3605986,-66.108806)">
<g
transform="matrix(0.8961095,0,0,0.89552164,-19.242681,54.006866)"
id="g3776-0"
style="stroke:#ffffff;stroke-width:41.3117981;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none">
<path
transform="matrix(6.1679584,0,0,6.1679584,-39.231908,407.75637)"
inkscape:connector-curvature="0"
id="path3758-6"
d="M 51.683077,25.430539 C 54.768634,32.887302 46.797612,48.315086 49.36891,44.20101"
style="fill:none;stroke:#ffffff;stroke-width:6.69780779;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
transform="matrix(6.1679584,0,0,6.1679584,-39.231908,407.75637)"
inkscape:connector-curvature="0"
id="path3760-1"
d="M 20.05612,25.17341 C 24.941585,16.945258 35.741034,15.14535 35.741034,15.14535"
style="fill:none;stroke:#ffffff;stroke-width:6.69780779;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
sodipodi:nodetypes="cc"
transform="matrix(6.1679584,0,0,6.1679584,-39.231908,407.75637)"
inkscape:connector-curvature="0"
id="path3762-3"
d="M 28.027141,31.087393 C 29.171402,23.677761 39.824421,20.298174 39.85511,20.287944"
style="fill:none;stroke:#ffffff;stroke-width:6.69780779;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
transform="matrix(6.1679584,0,0,6.1679584,-39.231908,407.75637)"
inkscape:connector-curvature="0"
id="path3764-8"
d="m 44.483445,27.230447 c 0.514259,5.913984 -7.713892,14.142136 -4.371206,10.54232"
style="fill:none;stroke:#ffffff;stroke-width:6.69780779;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
</g>
<path
style="fill:none;stroke:#ff0000;stroke-width:18.50387573;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 57.737765,560.81227 c 27.002777,-45.44853 86.693125,-55.3904 86.693125,-55.3904"
id="path3760"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#ff0000;stroke-width:18.50387573;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 196.30464,545.89946 c 2.8424,32.66613 -17.76498,68.88292 -27.71338,84.50586"
id="path3764"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<rect
style="color:#000000;fill:url(#linearGradient3774);fill-opacity:1;fill-rule:nonzero;stroke:#002e2e;stroke-width:18.50410652;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"
id="rect3942-4-9-9"
width="319.04367"
height="67.759109"
x="-607.8913"
y="-512.50751"
transform="matrix(-0.84163721,-0.54004334,0.53408016,-0.84543384,0,0)" />
<g
id="g3782"
transform="matrix(0.8961095,0,0,0.89552164,-17.959656,56.611269)">
<path
transform="matrix(6.1679584,0,0,6.1679584,-39.231908,407.75637)"
inkscape:connector-curvature="0"
id="path3008"
d="m 24.29876,2.031733 25.712974,27.127187 5.01403,-7.842457 z"
style="fill:#ffb70a;fill-opacity:1;stroke:#000000;stroke-width:1.1163013px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
transform="matrix(6.1679584,0,0,6.1679584,-39.231908,407.75637)"
inkscape:connector-curvature="0"
id="path3010"
d="M 24.29876,2.0317333 62.096832,32.373042 55.025764,21.316463 z"
style="fill:#45340a;fill-opacity:1;stroke:#000000;stroke-width:1.1163013px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
transform="matrix(6.1679584,0,0,6.1679584,-39.231908,407.75637)"
inkscape:connector-curvature="0"
id="path3012"
d="m 24.29876,2.0317333 30.727004,19.2847297 8.999541,0.385695 z"
style="fill:#45340a;fill-opacity:1;stroke:#000000;stroke-width:1.1163013px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<path
style="fill:none;stroke:#ff0000;stroke-width:18.50387573;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 229.70281,569.33386 c 19.04577,37.66513 12.37346,71.07876 -14.21198,95.15785"
id="path3758"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:18.50387573;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 101.79492,593.47839 c 5.15742,-34.66317 35.27506,-62.4425 64.80272,-68.64679"
id="path3762"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<g
id="g3049"
style="fill:none;stroke:#ffffff;stroke-width:6.38425779;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
transform="matrix(8.9342587,0,0,6.6862636,-48.479466,290.48255)">
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path3045"
d="m 10.351377,24.493827 -5.6980057,0 0,25.925926 5.6980057,0"
style="fill:none;stroke:#ffffff;stroke-width:6.38425779;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<use
height="64"
width="64"
transform="matrix(-1,0,0,1,47.081698,0)"
id="use3047"
xlink:href="#path3045"
y="0"
x="0"
style="fill:none;stroke:#ffffff;stroke-width:6.38425779;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
</g>
<g
id="g3049-8"
style="stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none"
transform="matrix(8.9113926,0,0,6.7667899,-48.785503,286.56618)">
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path3045-7"
d="m 10.351377,24.493827 -5.6980057,0 0,25.925926 5.6980057,0"
style="fill:none;stroke:#000000;stroke-width:1.58857334;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<use
height="64"
width="64"
transform="matrix(-1,0,0,1,47.081698,0)"
id="use3047-4"
xlink:href="#path3045-7"
y="0"
x="0"
style="stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,173 @@
<?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="svg6248"
sodipodi:version="0.32"
inkscape:version="0.48.4 r9939"
sodipodi:docname="Lattice2_SubLink.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs6250">
<linearGradient
inkscape:collect="always"
id="linearGradient6816">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop6818" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop6820" />
</linearGradient>
<linearGradient
id="linearGradient6781">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop6783" />
<stop
style="stop-color:#3465a4;stop-opacity:0;"
offset="1"
id="stop6785" />
</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="perspective6256" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6781"
id="linearGradient6787"
x1="5.3860474"
y1="20.454828"
x2="8.1818161"
y2="33.165546"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.85913167,0,0,0.85953422,5.5606698,5.2356595)" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient6816"
id="radialGradient6822"
cx="33.369828"
cy="51.929391"
fx="33.369828"
fy="51.929391"
r="25.198714"
gradientTransform="matrix(0.9485226,0,0,0.51415231,-0.01213181,19.953978)"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.5"
inkscape:cx="8.7394063"
inkscape:cy="33.796811"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="986"
inkscape:window-x="-11"
inkscape:window-y="-11"
inkscape:window-maximized="1" />
<metadata
id="metadata6253">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#969696;stroke-width:1.5;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 28.805272,7.1910123 55.41822,11.033125 40.562353,27.803392 9.2197797,21.465415 28.805272,7.1910123 z"
id="rect6771"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<path
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#969696;stroke-width:1.5;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 40.713234,27.655817 55.478093,11.031776 54.540858,39.231322 41.181851,58.980942 40.713234,27.655817 z"
id="rect6769"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<path
style="opacity:0.7;fill:none;stroke:#464646;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2, 1;stroke-dashoffset:0"
d="m 28.91343,8.3612383 0.702926,25.9423067 23.352761,4.844648"
id="path6789"
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0" />
<path
style="opacity:0.43829789;fill:url(#radialGradient6822);fill-opacity:1;fill-rule:evenodd;stroke:none"
d="M 28.713182,33.69762 7.7383539,50.038495 41.395637,59.609577 55.541451,39.300205 28.713182,33.69762 z"
id="path6814"
inkscape:connector-curvature="0" />
<path
style="opacity:0.7;fill:none;stroke:#464646;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2, 1;stroke-dashoffset:0"
d="M 28.601019,34.616102 11.105974,49.071905"
id="path6791"
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0" />
<path
style="fill:#0b26ea;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3;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"
inkscape:transform-center-y="-6.9839422"
d="m 9.1819144,21.369127 31.8864266,6.343707 0,31.210584 L 10.471608,49.776989 9.1819144,21.369127 z"
id="rect6767"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<path
style="fill:url(#linearGradient6787);fill-opacity:1;fill-rule:evenodd;stroke:none"
d="m 39.357966,28.372798 c 0,0 -24.847816,-5.221938 -26.722286,-5.534496 -1.874469,-0.312558 -2.8513791,-0.314374 -2.426739,6.041253 0.348074,5.209659 0.975136,8.237011 0.975136,8.237011 0,0 1.88557,-2.920274 4.85348,-4.795622 2.967909,-1.875347 18.746037,-4.961659 23.320409,-3.948146 z"
id="path6779"
sodipodi:nodetypes="csscsc"
inkscape:connector-curvature="0" />
<g
id="g3049"
style="stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none"
transform="matrix(1.5615031,0,0,2.068971,-4.3045641,-45.4061)">
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path3045"
d="m 10.351377,24.493827 -5.6980057,0 0,25.925926 5.6980057,0"
style="fill:none;stroke:#000000;stroke-width:1.11270833;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<use
height="64"
width="64"
transform="matrix(-1,0,0,1,47.081698,0)"
id="use3047"
xlink:href="#path3045"
y="0"
x="0"
style="stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -0,0 +1,262 @@
<?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="svg6248"
sodipodi:version="0.32"
inkscape:version="0.48.4 r9939"
sodipodi:docname="Lattice2_SubLink_Edge.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs6250">
<marker
inkscape:stockid="DotS"
orient="auto"
refY="0.0"
refX="0.0"
id="DotS"
style="overflow:visible">
<path
id="path3841"
d="M -2.5,-1.0 C -2.5,1.7600000 -4.7400000,4.0 -7.5,4.0 C -10.260000,4.0 -12.5,1.7600000 -12.5,-1.0 C -12.5,-3.7600000 -10.260000,-6.0 -7.5,-6.0 C -4.7400000,-6.0 -2.5,-3.7600000 -2.5,-1.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
transform="scale(0.2) translate(7.4, 1)" />
</marker>
<marker
inkscape:stockid="DotM"
orient="auto"
refY="0.0"
refX="0.0"
id="DotM"
style="overflow:visible">
<path
id="path3838"
d="M -2.5,-1.0 C -2.5,1.7600000 -4.7400000,4.0 -7.5,4.0 C -10.260000,4.0 -12.5,1.7600000 -12.5,-1.0 C -12.5,-3.7600000 -10.260000,-6.0 -7.5,-6.0 C -4.7400000,-6.0 -2.5,-3.7600000 -2.5,-1.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
transform="scale(0.4) translate(7.4, 1)" />
</marker>
<linearGradient
id="linearGradient3253">
<stop
style="stop-color:#89d5f8;stop-opacity:1;"
offset="0"
id="stop3255" />
<stop
style="stop-color:#00899e;stop-opacity:1;"
offset="1"
id="stop3257" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient6816">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop6818" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop6820" />
</linearGradient>
<linearGradient
id="linearGradient6781">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop6783" />
<stop
style="stop-color:#3465a4;stop-opacity:0;"
offset="1"
id="stop6785" />
</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="perspective6256" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6781"
id="linearGradient6787"
x1="8.2986603"
y1="15.743738"
x2="1.7074128"
y2="36.600822"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-0.1723565,0.9850346,0.9850346,0.1723565,-9.8385315,6.3516142)" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient6816"
id="radialGradient6822"
cx="33.369828"
cy="51.929391"
fx="33.369828"
fy="51.929391"
r="25.198714"
gradientTransform="matrix(1.1581633,0,0,0.6558985,59.798539,15.944259)"
gradientUnits="userSpaceOnUse" />
<filter
inkscape:collect="always"
id="filter5217"
x="-0.12669664"
width="1.2533933"
y="-0.36856957"
height="1.7371391">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="2.3166284"
id="feGaussianBlur5219" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="7.7781746"
inkscape:cx="25.093165"
inkscape:cy="34.924952"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="986"
inkscape:window-x="-11"
inkscape:window-y="-11"
inkscape:window-maximized="1" />
<metadata
id="metadata6253">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g3049"
style="stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none"
transform="matrix(1.5831197,0,0,2.1670484,-4.8696351,-49.826156)">
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path3045"
d="m 10.351377,24.493827 -5.6980057,0 0,25.925926 5.6980057,0"
style="fill:none;stroke:#000000;stroke-width:1.0797888;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<use
height="64"
width="64"
transform="matrix(-1,0,0,1,47.081698,0)"
id="use3047"
xlink:href="#path3045"
y="0"
x="0"
style="stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none" />
</g>
<path
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000d5b;stroke-width:2.16146827;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:0.56055364;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
inkscape:transform-center-y="-7.6811979"
d="m 7.253497,19.747301 35.087429,6.977043 0,34.326554 L 8.8445463,52.194487 7.253497,19.747301 z"
id="rect6767"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<path
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000d5b;stroke-width:2.16146827;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:0.56055364;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 41.95017,26.661635 58.197238,8.3779015 58.541012,42.830431 42.465831,61.114165 41.95017,26.661635 z"
id="rect6769"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<path
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000d5b;stroke-width:2.16146827;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:0.56055364;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 29.018683,3.2942807 58.131354,8.3793849 41.784142,26.823943 7.2951635,19.853202 29.018683,3.2942807 z"
id="rect6771"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<g
id="g5138"
transform="matrix(0.94537785,0,0,0.94534751,55.775031,-30.569195)">
<g
id="g5178"
style="filter:url(#filter5217)">
<path
inkscape:connector-curvature="0"
id="path5136"
d="m -51.168818,53.457681 36.512423,7.713892"
style="fill:none;stroke:#fffe1a;stroke-width:5.28897524;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none" />
<path
transform="matrix(3.0667261,0,0,2.3590202,-142.57227,-5.8809727)"
d="m 42.940667,28.387531 c 0,0.923058 -0.575605,1.671344 -1.285649,1.671344 -0.710044,0 -1.285649,-0.748286 -1.285649,-1.671344 0,-0.923057 0.575605,-1.671343 1.285649,-1.671343 0.710044,0 1.285649,0.748286 1.285649,1.671343 z"
sodipodi:ry="1.6713433"
sodipodi:rx="1.2856487"
sodipodi:cy="28.387531"
sodipodi:cx="41.655018"
id="path5174"
style="fill:#f3f316;fill-opacity:1;stroke:none"
sodipodi:type="arc" />
<use
height="64"
width="64"
transform="translate(-35.998163,-7.1996327)"
id="use5176"
xlink:href="#path5174"
y="0"
x="0" />
</g>
<g
id="g5183">
<path
style="fill:none;stroke:#0a005e;stroke-width:5.28897524;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none"
d="m -51.168818,53.457681 36.512423,7.713892"
id="path5185"
inkscape:connector-curvature="0" />
<path
sodipodi:type="arc"
style="fill:#061272;fill-opacity:1;stroke:none"
id="path5187"
sodipodi:cx="41.655018"
sodipodi:cy="28.387531"
sodipodi:rx="1.2856487"
sodipodi:ry="1.6713433"
d="m 42.940667,28.387531 c 0,0.923058 -0.575605,1.671344 -1.285649,1.671344 -0.710044,0 -1.285649,-0.748286 -1.285649,-1.671344 0,-0.923057 0.575605,-1.671343 1.285649,-1.671343 0.710044,0 1.285649,0.748286 1.285649,1.671343 z"
transform="matrix(3.0667261,0,0,2.3590202,-142.57227,-5.8809727)" />
<use
x="0"
y="0"
xlink:href="#path5187"
id="use5207"
transform="translate(-35.741034,-7.1996327)"
width="64"
height="64" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,173 @@
<?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="svg6248"
sodipodi:version="0.32"
inkscape:version="0.48.4 r9939"
sodipodi:docname="Lattice2_SubLinkSequence.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs6250">
<linearGradient
inkscape:collect="always"
id="linearGradient6816">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop6818" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop6820" />
</linearGradient>
<linearGradient
id="linearGradient6781">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop6783" />
<stop
style="stop-color:#3465a4;stop-opacity:0;"
offset="1"
id="stop6785" />
</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="perspective6256" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6781"
id="linearGradient6787"
x1="5.3860474"
y1="20.454828"
x2="8.1818161"
y2="33.165546"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.85913167,0,0,0.85953422,5.5606698,5.2356595)" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient6816"
id="radialGradient6822"
cx="33.369828"
cy="51.929391"
fx="33.369828"
fy="51.929391"
r="25.198714"
gradientTransform="matrix(0.9485226,0,0,0.51415231,-0.01213181,19.953978)"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.5"
inkscape:cx="8.7394063"
inkscape:cy="33.796811"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="986"
inkscape:window-x="-11"
inkscape:window-y="-11"
inkscape:window-maximized="1" />
<metadata
id="metadata6253">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#969696;stroke-width:1.5;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 28.805272,7.1910123 55.41822,11.033125 40.562353,27.803392 9.2197797,21.465415 28.805272,7.1910123 z"
id="rect6771"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<path
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#969696;stroke-width:1.5;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 40.713234,27.655817 55.478093,11.031776 54.540858,39.231322 41.181851,58.980942 40.713234,27.655817 z"
id="rect6769"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<path
style="opacity:0.7;fill:none;stroke:#464646;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2, 1;stroke-dashoffset:0"
d="m 28.91343,8.3612383 0.702926,25.9423067 23.352761,4.844648"
id="path6789"
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0" />
<path
style="opacity:0.43829789;fill:url(#radialGradient6822);fill-opacity:1;fill-rule:evenodd;stroke:none"
d="M 28.713182,33.69762 7.7383539,50.038495 41.395637,59.609577 55.541451,39.300205 28.713182,33.69762 z"
id="path6814"
inkscape:connector-curvature="0" />
<path
style="opacity:0.7;fill:none;stroke:#464646;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2, 1;stroke-dashoffset:0"
d="M 28.601019,34.616102 11.105974,49.071905"
id="path6791"
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0" />
<path
style="fill:#0b26ea;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3;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"
inkscape:transform-center-y="-6.9839422"
d="m 9.1819144,21.369127 31.8864266,6.343707 0,31.210584 L 10.471608,49.776989 9.1819144,21.369127 z"
id="rect6767"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<path
style="fill:url(#linearGradient6787);fill-opacity:1;fill-rule:evenodd;stroke:none"
d="m 39.357966,28.372798 c 0,0 -24.847816,-5.221938 -26.722286,-5.534496 -1.874469,-0.312558 -2.8513791,-0.314374 -2.426739,6.041253 0.348074,5.209659 0.975136,8.237011 0.975136,8.237011 0,0 1.88557,-2.920274 4.85348,-4.795622 2.967909,-1.875347 18.746037,-4.961659 23.320409,-3.948146 z"
id="path6779"
sodipodi:nodetypes="csscsc"
inkscape:connector-curvature="0" />
<g
id="g3049"
style="stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none"
transform="matrix(1.5615031,0,0,2.068971,-4.3045641,-45.4061)">
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path3045"
d="m 10.351377,24.493827 -5.6980057,0 0,25.925926 5.6980057,0"
style="fill:none;stroke:#000000;stroke-width:1.11270833;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<use
height="64"
width="64"
transform="matrix(-1,0,0,1,47.081698,0)"
id="use3047"
xlink:href="#path3045"
y="0"
x="0"
style="stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -0,0 +1,238 @@
<?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="svg6248"
sodipodi:version="0.32"
inkscape:version="0.48.4 r9939"
sodipodi:docname="Lattice2_SubLink_Vertex.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs6250">
<marker
inkscape:stockid="DotS"
orient="auto"
refY="0.0"
refX="0.0"
id="DotS"
style="overflow:visible">
<path
id="path3841"
d="M -2.5,-1.0 C -2.5,1.7600000 -4.7400000,4.0 -7.5,4.0 C -10.260000,4.0 -12.5,1.7600000 -12.5,-1.0 C -12.5,-3.7600000 -10.260000,-6.0 -7.5,-6.0 C -4.7400000,-6.0 -2.5,-3.7600000 -2.5,-1.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
transform="scale(0.2) translate(7.4, 1)" />
</marker>
<marker
inkscape:stockid="DotM"
orient="auto"
refY="0.0"
refX="0.0"
id="DotM"
style="overflow:visible">
<path
id="path3838"
d="M -2.5,-1.0 C -2.5,1.7600000 -4.7400000,4.0 -7.5,4.0 C -10.260000,4.0 -12.5,1.7600000 -12.5,-1.0 C -12.5,-3.7600000 -10.260000,-6.0 -7.5,-6.0 C -4.7400000,-6.0 -2.5,-3.7600000 -2.5,-1.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
transform="scale(0.4) translate(7.4, 1)" />
</marker>
<linearGradient
id="linearGradient3253">
<stop
style="stop-color:#89d5f8;stop-opacity:1;"
offset="0"
id="stop3255" />
<stop
style="stop-color:#00899e;stop-opacity:1;"
offset="1"
id="stop3257" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient6816">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop6818" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop6820" />
</linearGradient>
<linearGradient
id="linearGradient6781">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop6783" />
<stop
style="stop-color:#3465a4;stop-opacity:0;"
offset="1"
id="stop6785" />
</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="perspective6256" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6781"
id="linearGradient6787"
x1="8.2986603"
y1="15.743738"
x2="1.7074128"
y2="36.600822"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-0.1723565,0.9850346,0.9850346,0.1723565,-9.8385315,6.3516142)" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient6816"
id="radialGradient6822"
cx="33.369828"
cy="51.929391"
fx="33.369828"
fy="51.929391"
r="25.198714"
gradientTransform="matrix(1.1581633,0,0,0.6558985,59.798539,15.944259)"
gradientUnits="userSpaceOnUse" />
<filter
inkscape:collect="always"
id="filter5217"
x="-0.12669664"
width="1.2533933"
y="-0.36856957"
height="1.7371391">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="2.3166284"
id="feGaussianBlur5219" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="7.7781746"
inkscape:cx="33.251659"
inkscape:cy="32.504041"
inkscape:current-layer="g5138"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="986"
inkscape:window-x="-11"
inkscape:window-y="-11"
inkscape:window-maximized="1" />
<metadata
id="metadata6253">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000d5b;stroke-width:2.16146827;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:0.56055364;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
inkscape:transform-center-y="-7.5616418"
d="m 6.9148676,20.905427 34.5289964,6.868447 0,33.792269 L 8.4805947,52.84758 6.9148676,20.905427 z"
id="rect6767"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<path
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000d5b;stroke-width:2.16146827;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:0.56055364;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 41.059327,27.712141 57.047816,9.7129899 57.386119,43.629274 41.566781,61.628425 41.059327,27.712141 z"
id="rect6769"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<path
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000d5b;stroke-width:2.16146827;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:0.56055364;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 28.333651,4.7084942 56.982981,9.7144499 40.895942,27.871923 6.955871,21.00968 28.333651,4.7084942 z"
id="rect6771"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<g
id="g5138"
transform="translate(55.540023,-34.455385)">
<g
id="g5178"
style="filter:url(#filter5217)"
transform="matrix(0.93033173,0,0,0.93063338,-0.87586316,5.8274816)">
<path
transform="matrix(3.0667261,0,0,2.3590202,-142.57227,-5.8809727)"
d="m 42.940667,28.387531 c 0,0.923058 -0.575605,1.671344 -1.285649,1.671344 -0.710044,0 -1.285649,-0.748286 -1.285649,-1.671344 0,-0.923057 0.575605,-1.671343 1.285649,-1.671343 0.710044,0 1.285649,0.748286 1.285649,1.671343 z"
sodipodi:ry="1.6713433"
sodipodi:rx="1.2856487"
sodipodi:cy="28.387531"
sodipodi:cx="41.655018"
id="path5174"
style="fill:#f3f316;fill-opacity:1;stroke:none"
sodipodi:type="arc" />
</g>
<g
id="g5183"
transform="matrix(0.93033173,0,0,0.93063338,-0.87586316,5.8274816)">
<path
sodipodi:type="arc"
style="fill:#061272;fill-opacity:1;stroke:none"
id="path5187"
sodipodi:cx="41.655018"
sodipodi:cy="28.387531"
sodipodi:rx="1.2856487"
sodipodi:ry="1.6713433"
d="m 42.940667,28.387531 c 0,0.923058 -0.575605,1.671344 -1.285649,1.671344 -0.710044,0 -1.285649,-0.748286 -1.285649,-1.671344 0,-0.923057 0.575605,-1.671343 1.285649,-1.671343 0.710044,0 1.285649,0.748286 1.285649,1.671343 z"
transform="matrix(3.0667261,0,0,2.3590202,-142.57227,-5.8809727)" />
</g>
<g
id="g3049"
style="stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none"
transform="matrix(1.5536158,0,0,2.0428586,-60.036521,-10.140475)">
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path3045"
d="m 10.351377,24.493827 -5.6980057,0 0,25.925926 5.6980057,0"
style="fill:none;stroke:#000000;stroke-width:1.1226362;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<use
height="64"
width="64"
transform="matrix(-1,0,0,1,47.081698,0)"
id="use3047"
xlink:href="#path3045"
y="0"
x="0"
style="stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -0,0 +1,186 @@
<?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="svg2784"
sodipodi:version="0.32"
inkscape:version="0.48.4 r9939"
sodipodi:docname="Tree_Part_Sphere_Parametric.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs2786">
<linearGradient
id="linearGradient3777">
<stop
style="stop-color:#71b2f8;stop-opacity:1;"
offset="0"
id="stop3779" />
<stop
style="stop-color:#002795;stop-opacity:1;"
offset="1"
id="stop3781" />
</linearGradient>
<linearGradient
id="linearGradient3377">
<stop
id="stop3379"
offset="0"
style="stop-color:#faff2b;stop-opacity:1;" />
<stop
id="stop3381"
offset="1"
style="stop-color:#ffaa00;stop-opacity:1;" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3777"
id="radialGradient3692"
cx="45.883327"
cy="28.869568"
fx="45.883327"
fy="28.869568"
r="19.467436"
gradientUnits="userSpaceOnUse" />
<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="perspective2792" />
<linearGradient
id="linearGradient3377-3">
<stop
id="stop3379-8"
offset="0"
style="stop-color:#faff2b;stop-opacity:1;" />
<stop
id="stop3381-3"
offset="1"
style="stop-color:#ffaa00;stop-opacity:1;" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3777"
id="linearGradient3784"
x1="32.476803"
y1="36.57143"
x2="36.289989"
y2="45.479855"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3777"
id="linearGradient3792"
x1="9.9713058"
y1="32.03907"
x2="20.504885"
y2="32.820511"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="6.3984375"
inkscape:cx="-30.978416"
inkscape:cy="35.390162"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="986"
inkscape:window-x="-11"
inkscape:window-y="-11"
inkscape:window-maximized="1" />
<metadata
id="metadata2789">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
style="opacity:0.66523605;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.47351637;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 34.070818,53.84127 58.764347,44.151404 48.605617,42.901098 29.382174,50.402931 z"
id="path3812"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<g
id="g3564"
transform="matrix(0.44012748,0,0,0.44012748,6.3081072,2.1867501)">
<path
transform="matrix(1.2482835,0,0,0.4121139,-28.969888,102.91872)"
d="m 71.785715,34.571426 c 0,10.256717 -8.314712,18.571429 -18.571428,18.571429 -10.256717,0 -18.571428,-8.314712 -18.571428,-18.571429 0,-10.256716 8.314711,-18.571428 18.571428,-18.571428 10.256716,0 18.571428,8.314712 18.571428,18.571428 z"
sodipodi:ry="18.571428"
sodipodi:rx="18.571428"
sodipodi:cy="34.571426"
sodipodi:cx="53.214287"
id="path3694"
style="opacity:0.66523605;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc" />
<path
transform="matrix(1.2276699,0,0,1.2276699,-36.802054,58.263192)"
d="m 71.785715,34.571426 c 0,10.256717 -8.314712,18.571429 -18.571428,18.571429 -10.256717,0 -18.571428,-8.314712 -18.571428,-18.571429 0,-10.256716 8.314711,-18.571428 18.571428,-18.571428 10.256716,0 18.571428,8.314712 18.571428,18.571428 z"
sodipodi:ry="18.571428"
sodipodi:rx="18.571428"
sodipodi:cy="34.571426"
sodipodi:cx="53.214287"
id="path3696"
style="fill:url(#radialGradient3692);fill-opacity:1;fill-rule:evenodd;stroke:#000137;stroke-width:4.07157639;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"
sodipodi:type="arc" />
</g>
<use
x="0"
y="0"
xlink:href="#g3564"
id="use3002"
transform="translate(-6.2515262,-30.319902)"
width="64"
height="64" />
<use
x="0"
y="0"
xlink:href="#use3002"
id="use3004"
transform="translate(37.978022,17.191697)"
width="64"
height="64" />
<path
style="fill:url(#linearGradient3792);fill-opacity:1;stroke:#000000;stroke-width:2.20000005;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 10.471306,25.86569 11.096459,40.2442 23.599512,37.431013 18.754579,24.14652 z"
id="path3006"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:url(#linearGradient3784);fill-opacity:1;stroke:#000000;stroke-width:2.20000005;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 25.943834,39.619047 15.003663,-8.752136 4.844932,11.565323 -16.87912,4.688645 z"
id="path3008"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -0,0 +1,171 @@
<?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="svg2784"
sodipodi:version="0.32"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="Tree_Part_Sphere_Parametric.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs2786">
<linearGradient
id="linearGradient3777">
<stop
style="stop-color:#71b2f8;stop-opacity:1;"
offset="0"
id="stop3779" />
<stop
style="stop-color:#002795;stop-opacity:1;"
offset="1"
id="stop3781" />
</linearGradient>
<linearGradient
id="linearGradient3377">
<stop
id="stop3379"
offset="0"
style="stop-color:#faff2b;stop-opacity:1;" />
<stop
id="stop3381"
offset="1"
style="stop-color:#ffaa00;stop-opacity:1;" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3777"
id="radialGradient3692"
cx="45.883327"
cy="28.869568"
fx="45.883327"
fy="28.869568"
r="19.467436"
gradientUnits="userSpaceOnUse" />
<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="perspective2792" />
<radialGradient
r="19.467436"
fy="28.869568"
fx="45.883327"
cy="28.869568"
cx="45.883327"
gradientTransform="translate(-135.72159,-55.525617)"
gradientUnits="userSpaceOnUse"
id="radialGradient4514"
xlink:href="#linearGradient3377-3"
inkscape:collect="always" />
<linearGradient
id="linearGradient3377-3">
<stop
id="stop3379-8"
offset="0"
style="stop-color:#faff2b;stop-opacity:1;" />
<stop
id="stop3381-3"
offset="1"
style="stop-color:#ffaa00;stop-opacity:1;" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="12.796875"
inkscape:cx="32"
inkscape:cy="32"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1280"
inkscape:window-height="1004"
inkscape:window-x="1278"
inkscape:window-y="-3"
inkscape:window-maximized="1" />
<metadata
id="metadata2789">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g3564"
transform="translate(-0.8153068,-67.540042)">
<path
transform="matrix(1.2482835,0,0,0.4121139,-28.969888,102.91872)"
d="m 71.785715,34.571426 c 0,10.256717 -8.314712,18.571429 -18.571428,18.571429 -10.256717,0 -18.571428,-8.314712 -18.571428,-18.571429 0,-10.256716 8.314711,-18.571428 18.571428,-18.571428 10.256716,0 18.571428,8.314712 18.571428,18.571428 z"
sodipodi:ry="18.571428"
sodipodi:rx="18.571428"
sodipodi:cy="34.571426"
sodipodi:cx="53.214287"
id="path3694"
style="opacity:0.66523605;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc" />
<path
transform="matrix(1.2276699,0,0,1.2276699,-36.802054,58.263192)"
d="m 71.785715,34.571426 c 0,10.256717 -8.314712,18.571429 -18.571428,18.571429 -10.256717,0 -18.571428,-8.314712 -18.571428,-18.571429 0,-10.256716 8.314711,-18.571428 18.571428,-18.571428 10.256716,0 18.571428,8.314712 18.571428,18.571428 z"
sodipodi:ry="18.571428"
sodipodi:rx="18.571428"
sodipodi:cy="34.571426"
sodipodi:cx="53.214287"
id="path3696"
style="opacity:1;fill:url(#radialGradient3692);fill-opacity:1;fill-rule:evenodd;stroke:#000137;stroke-width:1.79201268999999996;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc" />
</g>
<path
sodipodi:type="arc"
style="fill:#ff2600;fill-opacity:1;stroke:#ff2600;stroke-width:2.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
id="path4465-9"
sodipodi:cx="36.376068"
sodipodi:cy="21.84127"
sodipodi:rx="2.3052504"
sodipodi:ry="2.4615386"
d="m 38.681319,21.84127 a 2.3052504,2.4615386 0 1 1 -4.610501,0 2.3052504,2.4615386 0 1 1 4.610501,0 z"
transform="matrix(0.97719968,0,0,0.96509721,11.925845,1.2702567)" />
<path
sodipodi:type="arc"
style="fill:#ff2600;fill-opacity:1;stroke:#ff2600;stroke-width:2.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
id="path4465-0"
sodipodi:cx="36.376068"
sodipodi:cy="21.84127"
sodipodi:rx="2.3052504"
sodipodi:ry="2.4615386"
d="m 38.681319,21.84127 a 2.3052504,2.4615386 0 1 1 -4.610501,0 2.3052504,2.4615386 0 1 1 4.610501,0 z"
transform="matrix(1.0557539,0,0,1.0545369,-11.444469,9.6317992)" />
<path
style="fill:url(#radialGradient4514);fill-opacity:1;fill-rule:evenodd;stroke:#ff2600;stroke-width:3.5;stroke-linecap:round;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 27.778645,32.101834 47.630389,22.208303"
id="path3536-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@ -32,6 +32,7 @@ import Part
from lattice2Common import *
import lattice2BaseFeature
import lattice2Subsequencer as Subsequencer
def makeAttachablePlacement(name):
'''makeAttachablePlacement(name): makes an attachable Placement object.'''
@ -47,7 +48,7 @@ def makeAttachablePlacement(name):
return obj
class AttachablePlacement(lattice2BaseFeature.LatticeFeature):
"The Lattice Placement object"
"Attachable Lattice Placement object"
def derivedInit(self,obj):
self.Type = "AttachablePlacement"
@ -79,6 +80,46 @@ class ViewProviderAttachablePlacement(lattice2BaseFeature.ViewProviderLatticeFea
Gui.Control.closeDialog()
return True
def makeLatticeAttachedPlacementSubsequence(name):
'''makeLatticeAttachedPlacementSubsequence(name): makes a AttachedPlacementSubsequence object.'''
return lattice2BaseFeature.makeLatticeFeature(name, AttachedPlacementSubsequence, ViewProviderAttachedPlacementSubsequence)
class AttachedPlacementSubsequence(lattice2BaseFeature.LatticeFeature):
"Array Maker from Attachable Lattice Placement"
def derivedInit(self,obj):
self.Type = "AttachablePlacementSubsequence"
obj.ExposePlacement = False
obj.setEditorMode("ExposePlacement", 1) #read-only
obj.addProperty("App::PropertyLink", "Base", "Lattice Attached Placement Subsequence", "Link to Lattice Attached Placement, which is to be subsequenced.")
obj.addProperty("App::PropertyString", "RefIndexFilter","Lattice Attached Placement Subsequence","Sets which references of attachment to cycle through children. '0000' = no cycle, '1000' = cycle only ref1. '' = cycle all if possible")
obj.addProperty("App::PropertyEnumeration", "CycleMode","Lattice Attached Placement Subsequence", "How to cycle through chidren. Open = advance each link till one reaches the end of array. Periodic = if array end reached, continue from begin if any children left.")
obj.CycleMode = ['Open','Periodic']
def derivedExecute(self,obj):
attacher = obj.Base.Attacher.copy()
attacher.readParametersFromFeature(obj.Base)
i_filt_str = obj.RefIndexFilter
ifilt = None if i_filt_str == "" else [i for i in range(len(i_filt_str)) if int(i_filt_str[i]) != 0]
sublinks = Subsequencer.Subsequence_auto(attacher.References,
loop= ('Till end' if obj.CycleMode == 'Open' else 'All around'),
index_filter= ifilt)
plms = []
for lnkval in sublinks:
attacher.References = lnkval
plms.append(attacher.calculateAttachedPlacement(obj.Base.Placement))
return plms
class ViewProviderAttachedPlacementSubsequence(lattice2BaseFeature.ViewProviderLatticeFeature):
def getIcon(self):
return getIconPath('Lattice2_AttachedPlacementSubsequence.svg')
def claimChildren(self):
return [self.Object.Base]
# -------------------------- /document object --------------------------------------------------
# -------------------------- Gui command --------------------------------------------------
@ -96,6 +137,19 @@ def CreateAttachablePlacement(name):
"callback_Cancel= lambda: App.ActiveDocument.abortTransaction())")
FreeCAD.ActiveDocument.commitTransaction()
def cmdCreateAttachedPlacementSubsequence(name):
sel = FreeCADGui.Selection.getSelectionEx()
FreeCAD.ActiveDocument.openTransaction("Array an attached placement")
FreeCADGui.addModule("lattice2AttachablePlacement")
FreeCADGui.addModule("lattice2Executer")
FreeCADGui.doCommand("f = lattice2AttachablePlacement.makeLatticeAttachedPlacementSubsequence(name='"+name+"')")
FreeCADGui.doCommand("f.Base = App.ActiveDocument."+sel[0].Object.Name)
FreeCADGui.doCommand("f.Base.ViewObject.hide()")
FreeCADGui.doCommand("lattice2Executer.executeFeature(f)")
FreeCAD.ActiveDocument.commitTransaction()
FreeCADGui.doCommand("Gui.Selection.addSelection(f)")
deselect(sel)
class CommandAttachablePlacement:
"Command to create Lattice Placement feature"
@ -120,6 +174,56 @@ class CommandAttachablePlacement:
else:
return False
class CommandAttachedPlacementSubsequence:
"Command to convert a attached placement into an array"
def __init__(self):
pass
def GetResources(self):
return {'Pixmap' : getIconPath("Lattice2_AttachedPlacementSubsequence.svg"),
'MenuText': QtCore.QT_TRANSLATE_NOOP("Lattice2_Placement","Array an attached placement") ,
'Accel': "",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Lattice2_Placement","Attached Placement: makes an array of placements from an attached placement by cycling attachment references...")}
def Activated(self):
try:
sel = FreeCADGui.Selection.getSelectionEx()
if len(sel) == 0:
infoMessage("Attached Placement Subsequence",
"Attached Placement Subsequence feature: makes an array of placements from an attached placement by cycling attachment references through children of an array the placement is attached to."+
"\n\nPlease select an attached placement object, first. Then invoke this tool. Adjust the properties of the created object if necessary." )
else:
if len(sel)!=1:
raise SelectionError("PlacementSubsequence", "Please select just one object, an attached placement. You have seleced {num}.".format(num= len(sel)))
cmdCreateAttachedPlacementSubsequence(name= "PlacementSubsequence")
except Exception as err:
msgError(err)
def IsActive(self):
if FreeCAD.ActiveDocument:
return True
else:
return False
FreeCADGui.addCommand("Lattice2_AttachedPlacement", CommandAttachablePlacement())
exportedCommands = ["Lattice2_AttachedPlacement"]
FreeCADGui.addCommand("Lattice2_AttachedPlacementSubsequence", CommandAttachedPlacementSubsequence())
class CommandAttachedPlacementGroup:
def GetCommands(self):
return ("Lattice2_AttachedPlacement","Lattice2_AttachedPlacementSubsequence")
def GetDefaultCommand(self): # return the index of the tuple of the default command.
return 0
def GetResources(self):
return { 'MenuText': 'Attached Placement:',
'ToolTip': 'Attached Placement (group): tools to work with attached placement objects.'}
def IsActive(self): # optional
return App.ActiveDocument is not None
FreeCADGui.addCommand("Lattice2_AttachedPlacement_Group", CommandAttachedPlacementGroup())
exportedCommands = ["Lattice2_AttachedPlacement_Group"]
# -------------------------- /Gui command --------------------------------------------------

View File

@ -118,16 +118,7 @@ class LatticeFeature():
a property if one is missing, and sets its value to default. Does nothing if property
already exists. Returns True if property was created, or False if not."""
if hasattr(selfobj, propname):
#todo: check type match
return False
selfobj.addProperty(proptype, propname, group, tooltip)
if defvalue is not None:
setattr(selfobj, propname, defvalue)
return True
return assureProperty(selfobj, proptype, propname, defvalue, group, tooltip)
def derivedInit(self, obj):
'''for overriding by derived classes'''
@ -296,6 +287,21 @@ class ViewProviderLatticeFeature:
FreeCAD.Console.PrintError("Error in onDelete: " + err.message)
return True
def assureProperty(docobj, proptype, propname, defvalue, group, tooltip):
"""assureProperty(docobj, proptype, propname, defvalue, group, tooltip): adds
a property if one is missing, and sets its value to default. Does nothing if property
already exists. Returns True if property was created, or False if not."""
if hasattr(docobj, propname):
#todo: check type match
return False
docobj.addProperty(proptype, propname, group, tooltip)
if defvalue is not None:
setattr(docobj, propname, defvalue)
return True
# ----------------------utility functions -------------------------------------

View File

@ -37,13 +37,13 @@ def executeFeature(obj):
obj.Proxy.execute(obj)
obj.purgeTouched()
except CancelError:
FreeCAD.ActiveDocument.abortTransaction()
obj.Document.abortTransaction()
raise
except Exception as err:
try:
error(obj,err.message)
except CancelError:
FreeCAD.ActiveDocument.abortTransaction()
obj.Document.abortTransaction()
raise
finally:
globalIsCreatingLatticeFeature = False

View File

@ -32,9 +32,11 @@ import Part
from lattice2Common import *
import lattice2BaseFeature
from lattice2BaseFeature import assureProperty
import lattice2Executer
import lattice2GeomUtils
from lattice2ValueSeriesGenerator import ValueSeriesGenerator
from lattice2Utils import sublinkFromApart, syncSublinkApart
def makeLinearArray(name):
'''makeLinearArray(name): makes a LinearArray object.'''
@ -77,6 +79,8 @@ class LinearArray(lattice2BaseFeature.LatticeFeature):
obj.SpanEnd = 12.0
obj.Step = 3.0
obj.Count = 5.0
self.assureProperties(obj)
def updateReadonlyness(self, obj):
obj.setEditorMode("Dir", 1 if (obj.Link and obj.DirIsDriven) else 0)
@ -98,10 +102,12 @@ class LinearArray(lattice2BaseFeature.LatticeFeature):
valuestype= "App::PropertyDistance")
self.updateReadonlyness(obj)
def assureProperties(self, selfobj):
assureProperty(selfobj, "App::PropertyLinkSub", "SubLink", sublinkFromApart(selfobj.Link, selfobj.LinkSubelement), "Lattice Array", "Mirror of Object+SubNames properties")
def derivedExecute(self,obj):
self.assureGenerator(obj)
self.assureProperties(obj)
self.updateReadonlyness(obj)
# Apply links
@ -166,6 +172,12 @@ class LinearArray(lattice2BaseFeature.LatticeFeature):
output.append( App.Placement(obj.Point + obj.Dir*v, ori) )
return output
def onChanged(self, selfobj, prop): #prop is a string - name of the property
# synchronize SubLink and Object+SubNames properties
syncSublinkApart(selfobj, prop, 'SubLink', 'Link', 'LinkSubelement')
return lattice2BaseFeature.LatticeFeature.onChanged(self, selfobj, prop)
class ViewProviderLinearArray(lattice2BaseFeature.ViewProviderLatticeFeature):

View File

@ -32,9 +32,11 @@ import Part
from lattice2Common import *
import lattice2BaseFeature
from lattice2BaseFeature import assureProperty
import lattice2Executer
import lattice2GeomUtils
from lattice2ValueSeriesGenerator import ValueSeriesGenerator
from lattice2Utils import sublinkFromApart, syncSublinkApart
def makePolarArray(name):
'''makePolarArray(name): makes a PolarArray object.'''
@ -72,6 +74,8 @@ class PolarArray(lattice2BaseFeature.LatticeFeature):
obj.SpanEnd = 360
obj.EndInclusive = False
obj.Count = 5
self.assureProperties(obj)
def assureGenerator(self, obj):
'''Adds an instance of value series generator, if one doesn't exist yet.'''
@ -90,10 +94,14 @@ class PolarArray(lattice2BaseFeature.LatticeFeature):
obj.setEditorMode("AxisDirIsDriven", 0 if obj.AxisLink else 1)
obj.setEditorMode("AxisPointIsDriven", 0 if obj.AxisLink else 1)
self.generator.updateReadonlyness()
def assureProperties(self, selfobj):
assureProperty(selfobj, "App::PropertyLinkSub", "AxisSubLink", sublinkFromApart(selfobj.AxisLink, selfobj.AxisLinkSubelement), "Lattice Array", "Mirror of Object+SubNames properties")
def derivedExecute(self,obj):
self.assureGenerator(obj)
self.assureProperties(obj)
self.updateReadonlyness(obj)
# Apply links
@ -153,6 +161,11 @@ class PolarArray(lattice2BaseFeature.LatticeFeature):
return output
def onChanged(self, selfobj, prop): #prop is a string - name of the property
# synchronize SubLink and Object+SubNames properties
syncSublinkApart(selfobj, prop, 'AxisSubLink', 'AxisLink', 'AxisLinkSubelement')
return lattice2BaseFeature.LatticeFeature.onChanged(self, selfobj, prop)
class ViewProviderPolarArray(lattice2BaseFeature.ViewProviderLatticeFeature):
def getIcon(self):

52
lattice2SeriesGroup.py Normal file
View File

@ -0,0 +1,52 @@
#***************************************************************************
#* *
#* Copyright (c) 2016 - Victor Titov (DeepSOIC) *
#* <vv.titov@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 *
#* *
#***************************************************************************
__title__="Group command for Lattice Series features"
__author__ = "DeepSOIC"
__url__ = ""
__doc__ = "Group command for Lattice Series features"
import lattice2ParaSeries as ParaSeries
import lattice2TopoSeries as TopoSeries
import FreeCAD as App
import FreeCADGui
class CommandSeriesGroup:
def GetCommands(self):
return tuple(ParaSeries.exportedCommands + TopoSeries.exportedCommands)
def GetDefaultCommand(self): # return the index of the tuple of the default command.
return 0
def GetResources(self):
return { 'MenuText': 'Series features:',
'ToolTip': 'Series features (group): features that collect permutations of an object by changing dependent objects.'}
def IsActive(self): # optional
return App.ActiveDocument is not None
FreeCADGui.addCommand('Lattice2_Series_GroupCommand',CommandSeriesGroup())
exportedCommands = ['Lattice2_Series_GroupCommand']

View File

@ -26,10 +26,13 @@ __author__ = "DeepSOIC"
__doc__ = "Lattice SubLink is like Draft Facebinder, but for edges and vertices too."
from lattice2Common import *
from lattice2BaseFeature import isObjectLattice
from lattice2BaseFeature import isObjectLattice, assureProperty #assureProperty(self, selfobj, proptype, propname, defvalue, group, tooltip)
import lattice2Markers as markers
import FreeCAD as App
import lattice2ShapeCopy as ShapeCopy
import lattice2Subsequencer as LSS
from lattice2Utils import sublinkFromApart, syncSublinkApart
# -------------------------- feature --------------------------------------------------
@ -51,32 +54,75 @@ class LatticeSubLink:
obj.Proxy = self
self.assureProperties(obj)
def assureProperties(self, selfobj):
assureProperty(selfobj, "App::PropertyEnumeration","Looping", ["Single"] + LSS.LOOP_MODES, "Lattice SubLink", "Sets wether to collect just the element, or all similar from array.")
assureProperty(selfobj, "App::PropertyEnumeration","CompoundTraversal", LSS.TRAVERSAL_MODES, "Lattice SubLink", "Sets how to unpack compounds if Looping is not 'Single'.")
assureProperty(selfobj, "App::PropertyLinkSub", "SubLink", sublinkFromApart(selfobj.Object, selfobj.SubNames), "Lattice SubLink", "Mirror of Object+SubNames properties")
def execute(self,selfobj):
self.assureProperties(selfobj)
#validity check
if isObjectLattice(selfobj.Object):
import lattice2Executer
lattice2Executer.warning(selfobj,"A generic shape is expected, but a placement/array was supplied. It will be treated as a generic shape.")
rst = [] #variable to receive the final list of shapes
lnkobj = selfobj.Object
for subname in selfobj.SubNames:
subname = subname.strip()
if len(subname)==0:
raise ValueError("Empty subname! Not allowed.")
if 'Face' in subname:
index = int(subname.replace('Face',''))-1
rst.append(lnkobj.Shape.Faces[index])
elif 'Edge' in subname:
index = int(subname.replace('Edge',''))-1
rst.append(lnkobj.Shape.Edges[index])
elif 'Vertex' in subname:
index = int(subname.replace('Vertex',''))-1
rst.append(lnkobj.Shape.Vertexes[index])
sh = lnkobj.Shape
# subsequencing
full_link = (lnkobj, selfobj.SubNames)
if selfobj.Looping == 'Single':
lnkseq = [full_link]
else:
lnkseq = LSS.Subsequence_auto(full_link, selfobj.CompoundTraversal, selfobj.Looping )
# main code
seq_packs = [] #pack = single item of subsequence. Pack contains list of elements that were selected.
shape_count = 0
for lnk in lnkseq: # loop over subsequence (if Looping == 'Single', this loop will only loop once)
# extract the pack
assert(lnk[0] is lnkobj) # all links should point to elements of one object anyway
subnames = lnk[1]
pack = [] #acculumator, to eventually become a compound of shapes for this subsequence item
for subname in subnames:
subname = subname.strip()
if len(subname)==0:
raise ValueError("Empty subname! Not allowed.")
if 'Face' in subname: # manual handling of standard cases, because support for negative indexing is needed
index = int(subname.replace('Face',''))-1
pack.append(sh.Faces[index])
elif 'Edge' in subname:
index = int(subname.replace('Edge',''))-1
pack.append(sh.Edges[index])
elif 'Vertex' in subname:
index = int(subname.replace('Vertex',''))-1
pack.append(sh.Vertexes[index])
else: #fail-safe. non-standard sublink.
lattice2Executer.warning(selfobj,"Unexpected subelement name: "+subname+". Trying to extract it with .Shape.getElement()...")
pack.append(sh.getElement(subname))
shape_count += len(pack)
# convert list into compound
if len(pack) == 1:
pack = ShapeCopy.transformCopy(pack[0])
else:
lattice2Executer.warning(selfobj,"Unexpected subelement name: "+subname+". Trying to extract it with .Shape.getElement()...")
rst.append(linkobj.Shape.getElement(subname))
if len(rst) == 0:
pack = Part.makeCompound(pack)
# accumulate
seq_packs.append(pack)
# convert list into compound
if len(seq_packs) == 1:
seq_packs = seq_packs[0]
else:
seq_packs = Part.makeCompound(seq_packs)
if shape_count == 0:
# no shapes collected, FAIL!
scale = 1.0
try:
if selfobj.Object:
@ -88,16 +134,13 @@ class LatticeSubLink:
selfobj.Shape = markers.getNullShapeShape(scale)
raise ValueError('Nothing is linked, apparently!') #Feeding empty compounds to FreeCAD seems to cause rendering issues, otherwise it would have been a good idea to output nothing.
if len(rst) > 1:
selfobj.Shape = Part.makeCompound(rst)
else: # don't make compound of one shape, output it directly
sh = rst[0]
# absorb placement of original shape
sh = ShapeCopy.transformCopy(sh)
# apply Placement that is filled into feature's Placement property (not necessary)
sh.Placement = selfobj.Placement
selfobj.Shape = sh
# done!
selfobj.Shape = seq_packs
def onChanged(self, selfobj, prop): #prop is a string - name of the property
# synchronize SubLink and Object+SubNames properties
syncSublinkApart(selfobj, prop, 'SubLink', 'Object', 'SubNames')
def __getstate__(self):
return None
@ -111,15 +154,20 @@ class ViewProviderSubLink:
vobj.Proxy = self
def getIcon(self):
ret = ""
if len(self.Object.SubNames) == 1:
subname = self.Object.SubNames[0]
if 'Face' in subname:
return getIconPath("Lattice2_SubLink_Face.svg")
ret = getIconPath("Lattice2_SubLink_Face.svg")
elif 'Edge' in subname:
return getIconPath("Lattice2_SubLink_Edge.svg")
ret = getIconPath("Lattice2_SubLink_Edge.svg")
elif 'Vertex' in subname:
return getIconPath("Lattice2_SubLink_Vertex.svg")
return getIconPath("Lattice2_SubLink.svg")
ret = getIconPath("Lattice2_SubLink_Vertex.svg")
if len(ret) == 0:
ret = getIconPath("Lattice2_SubLink.svg")
if hasattr(self.Object,'Looping') and self.Object.Looping != 'Single':
ret = ret.replace("SubLink","SubLinkSubsequence")
return ret
def attach(self, vobj):
self.ViewObject = vobj
@ -141,7 +189,7 @@ class ViewProviderSubLink:
def claimChildren(self):
return []
def CreateSubLink(object, subnames):
def CreateSubLink(object, subnames, looping):
#stabilize links
subnames = list(subnames) #'tuple' object does not support item assignment; SubElementNames of SelectionObject is a tuple
try:
@ -187,11 +235,14 @@ def CreateSubLink(object, subnames):
FreeCADGui.addModule("lattice2SubLink")
FreeCADGui.addModule("lattice2Executer")
name = object.Name+"_"+subnames[0] if len(subnames)==1 else "SubLink"
if looping != 'Single':
name = object.Name+"_"+"Elements"
FreeCADGui.doCommand("f = lattice2SubLink.makeSubLink(name = "+repr(name)+")")
label = unicode(subnames[0] if len(subnames)==1 else "subelements") + u" of " + object.Label
FreeCADGui.doCommand("f.Label = "+repr(label))
FreeCADGui.doCommand("f.Object = App.ActiveDocument."+object.Name)
FreeCADGui.doCommand("f.SubNames = "+repr(subnames))
FreeCADGui.doCommand("f.Looping = "+repr(looping))
FreeCADGui.doCommand("lattice2Executer.executeFeature(f)")
if cnt_vertexes > 0 and cnt_faces+cnt_edges+cnt_somethingelse == 0: #only vertices selected - make them bigger to make them visible
FreeCADGui.doCommand("f.ViewObject.PointSize = 10")
@ -200,7 +251,7 @@ def CreateSubLink(object, subnames):
FreeCADGui.doCommand("f = None")
return App.ActiveDocument.ActiveObject
def cmdSubLink():
def cmdSubLink(looping = 'Single'):
sel = FreeCADGui.Selection.getSelectionEx()
if len(sel) == 0:
raise SelectionError("Bad selection", "Please select some subelements from one object, first.")
@ -209,7 +260,7 @@ def cmdSubLink():
if len(sel[0].SubElementNames)==0:
raise SelectionError("Bad selection", "Please select some subelements, not the whole object.")
App.ActiveDocument.openTransaction("Create SubLink")
CreateSubLink(sel[0].Object,sel[0].SubElementNames)
CreateSubLink(sel[0].Object,sel[0].SubElementNames, looping)
deselect(sel)
App.ActiveDocument.commitTransaction()
@ -217,7 +268,7 @@ def cmdSubLink():
# -------------------------- Gui command --------------------------------------------------
class _CommandSubLink:
class CommandSubLink:
"Command to create SubLink feature"
def GetResources(self):
return {'Pixmap' : getIconPath("Lattice2_SubLink.svg"),
@ -242,8 +293,51 @@ class _CommandSubLink:
else:
return False
FreeCADGui.addCommand('Lattice2_SubLink', _CommandSubLink())
class CommandSublinkSubsequence:
"Command to create SubLink Subsequence feature"
def GetResources(self):
return {'Pixmap' : getIconPath("Lattice2_SubLinkSubsequence.svg"),
'MenuText': QtCore.QT_TRANSLATE_NOOP("Lattice2_SubLink","Subsequence"),
'Accel': "",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Lattice2_SubLink","Subsequence: extract individual vertices, edges and faces from shapes, from each instance in an array.")}
def Activated(self):
try:
if len(FreeCADGui.Selection.getSelection())==0:
infoMessage("SubLink",
"'Subsequence' command. Extracts all faces/edges/vertexes similar to those selected, from an array of shapes.\n\n"+
"Please select one or more subelements of one array (compound), then invoke the command.")
return
cmdSubLink(looping= 'All around')
except Exception as err:
msgError(err)
def IsActive(self):
if App.ActiveDocument:
return True
else:
return False
exportedCommands = ['Lattice2_SubLink']
FreeCADGui.addCommand('Lattice2_SubLink', CommandSubLink())
FreeCADGui.addCommand('Lattice2_SublinkSubsequence', CommandSublinkSubsequence())
class CommandSublinkGroup:
def GetCommands(self):
return ("Lattice2_SubLink","Lattice2_SublinkSubsequence")
def GetDefaultCommand(self): # return the index of the tuple of the default command.
return 0
def GetResources(self):
return { 'MenuText': 'Sublink:',
'ToolTip': 'Sublink (group): extract elements from shapes.'}
def IsActive(self): # optional
return App.ActiveDocument is not None
FreeCADGui.addCommand('Lattice2_Sublink_GroupCommand',CommandSublinkGroup())
exportedCommands = ['Lattice2_Sublink_GroupCommand']
# -------------------------- /Gui command --------------------------------------------------

388
lattice2Subsequencer.py Normal file
View File

@ -0,0 +1,388 @@
#***************************************************************************
#* *
#* Copyright (c) 2017 - Victor Titov (DeepSOIC) *
#* <vv.titov@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 *
#* *
#***************************************************************************
__title__="Subsequencer: module with code to extract chains of similar elements from compounds"
__author__ = "DeepSOIC"
__url__ = ""
# -----------------------<CONSTANTS>-------------------------
TRAVERSAL_MODES = ['Compund children','Compound leaves']
LOOP_MODES = ['Till end', 'All around', 'All from first']
# -----------------------</CONSTANTS>------------------------
# -----------------------<EXCEPTIONS>------------------------
class TraversalError(TypeError):
"Error to raise when extracting children from compound fails"
pass
class SubsequencingError(ValueError):
"General error, that subsequencing is impossible or failed"
pass
class SubsequencingError_LinkType(SubsequencingError):
"Subsequencing can't be applied to this link type (e.g. App::PropertyLink)."
pass
class SubsequencingError_LinkValue(SubsequencingError):
"Type of links to subsequence are right, but they happen to be links to whole objects, or otherwise impossible to iterate"
pass
# -----------------------</EXCEPTIONS>------------------------
# -----------------------<HELPER STUFF>-----------------------
class HashableShape(object):
"Decorator for Part.Shape, that can be used as key in dicts. Based on isSame method."
def __init__(self, shape):
self.Shape = shape
self.hash = shape.hashCode()
def __eq__(self, other):
return self.Shape.isSame(other.Shape)
def __hash__(self):
return self.hash
def traverseCompound(compound, traversal):
if traversal == 'Compund children':
if compound.ShapeType != 'Compound':
raise TraversalError("Shape is not compound; can't traverse it in direct children mode.")
return compound.childShapes()
elif traversal == 'Compound leaves':
import lattice2CompoundExplorer as LCE
return LCE.allLeaves(compound)
element_extractors = {
"Vertex": (lambda(sh): sh.Vertexes),
"Edge": (lambda(sh): sh.Edges),
"Wire": (lambda(sh): sh.Wires),
"Face": (lambda(sh): sh.Faces),
"Shell": (lambda(sh): sh.Shells),
"Solid": (lambda(sh): sh.Solids),
"CompSolid": (lambda(sh): sh.CompSolids),
"Compound": (lambda(sh): sh.Compounds),
}
def getIndexesIntoList(element, list_of_shapes):
"""Finds this element in shapes in list_of_shapes. This is a generator function (to be
used if there are multiple occurences of the element).
[(index_into_list, element_type_string, subelement_index), ...]"""
element_type_string = element.ShapeType
element_extractor = element_extractors[element_type_string]
ret = []
for i_sh in xrange(len(list_of_shapes)):
elements = element_extractor(list_of_shapes[i_sh])
for i_el in xrange(len(elements)):
if elements[i_el].isEqual(element):
# to make link more robust, use negative index if one is closer to the end
if i_el * 2 > len(elements):
i_el = i_el - len(elements)
yield (i_sh, element_type_string, i_el)
# -----------------------</HELPER STUFF>-----------------------
# -------------------<LINK TYPE CONVERSION>--------------------
def linkSubList_convertToOldStyle(references):
("input: [(obj1, (sub1, sub2)), (obj2, (sub1, sub2))]\n"
"output: [(obj1, sub1), (obj1, sub2), (obj2, sub1), (obj2, sub2)]")
result = []
for tup in references:
if type(tup[1]) is tuple or type(tup[1]) is list:
for subname in tup[1]:
result.append((tup[0], subname))
if len(tup[1]) == 0:
result.append((tup[0], ''))
elif isinstance(tup[1],basestring):
# old style references, no conversion required
result.append(tup)
return result
def toLinkSubList(linksub):
if linksub is None:
return []
object, subs = linksub
if not hasattr(subs, '__iter__'):
subs = [subs]
return [(object, sub) for sub in subs]
def toLinkSub(linksublist):
if not linksublist:
return None
linksublist = linkSubList_convertToOldStyle(linksublist)
subs = []
object = linksublist[0][0]
for itobj, sub in linksublist:
if itobj is not object:
raise ValueError("LinkSubList can't be converted into LinkSub because it links to more than one object.")
subs.append(sub)
return (object, subs)
# -------------------</LINK TYPE CONVERSION>--------------------
# ---------------------------<API>------------------------------
def Subsequence_basic(link, traversal, loop):
"""Subsequence_basic(link, traversal, loop): low-level function powering Subsequencing. Transforms
a single sub-link into a list of sub-links to every child of the linked compound.
link: tuple (object, subelement), where object is a document object, and subelement is
a string like 'Edge3'.
traversal: either of values from TRAVERSAL_MODES, that sets how to enumerate children
loop: either of values from LOOP_MODES. Sets which children to use.
returns: list of links [(object,subelement), ....]"""
# extract shapes of the array
compound = link[0].Shape
children = traverseCompound(compound, traversal)
# parse link string. Input: element_string. Output: element_shape, element_type_string
element_string = link[1]
if not issubclass(type(element_string), basestring):
raise TypeError("Second element of link tuple must be a string, not {typ}".format(typ= type(element_string).__name__))
element_type_string = None
for key in element_extractors.keys():
if element_string.startswith(key):
element_type_string = key
break
if element_type_string is None:
# raise ValueError("Subelement string format not recognized")
# resort to generic FreeCAD method
element_shape = compound.getElement(element_string)
else:
# use negative-index-aware method
#extract index from string:
index = -1 + int( element_string[ len(element_type_string) : ] )
element_shape = element_extractors[element_type_string](compound)[index]
# convert global element index to index in child
i_first_child, element_type_string, i_in_child = getIndexesIntoList(element_shape, children).next()
if loop == 'All from first':
i_first_child = 0
elements = element_extractors[element_type_string](compound)
index_dict = dict([(HashableShape(elements[i]), i) for i in xrange(len(elements))])
# find the element in each child, find out its global index, and output result in a form of a string for a link
ret = [] #list of tuples (object, subelement_string)
for i in range( len(children) if loop != 'Till end' else len(children) - i_first_child ):
i_child = (i + i_first_child) % len(children)
element = element_extractors[element_type_string](children[i_child])[i_in_child]
ret.append((
link[0],
element_type_string + str(index_dict[HashableShape(element)]+1)
))
return ret
def Subsequence_LinkSubList(linksublist, traversal = TRAVERSAL_MODES[0], loop = LOOP_MODES[0], object_filter = None, index_filter = None):
"""Subsequence_LinkSubList(linksublist, traversal = TRAVERSAL_MODES[0], loop = 'Till end', object_filter = None):
form a list of values for iterating over elements in App::PropertyLinkSubList.
linksublist: the value of property (either of type [(object, sub), ..], or
[(object, [sub1, sub2, ...]), ...]
traversal: how to unpack compounds
loop: sets which children to process.
object_filter: list or set of objects that should be considered being arrays. If
omitted, all links to subelements are attempted to be enumerated as arrays.
index_list: list or set of ints, that sets which parts of link are to be subsequenced.
If None, all elements are attempted to be subsequenced, and only if none can be, an error
is raised. If index_list is specified, it is treated as strict, and if any
corresponding sublink can't be subsequenced, an error is raised.
return: list of values that can be assigned to the link in a loop.
"""
linksublist = linkSubList_convertToOldStyle(linksublist)
if object_filter is None:
object_filter = [obj for (obj,sub) in linksublist] #number of links is likely quite low, so using sets might give more of a penalty than gain
loops = [] #list to receive subsequences for made for pieces of the link
n_seq = None
i = -1
for object,sub in linksublist:
i += 1
if (sub
and (object in object_filter)
and (index_filter is None or i in index_filter)
and hasattr(object, "Shape") ):
try:
seq = Subsequence_basic((object, sub), traversal, loop)
if len(seq) < 2:
from lattice2Executer import warning
warning(None, u"Subsequencing link index {i} to {sub} of '{obj}' yielded only one item."
.format(i= i, obj= object.Label, sub= sub))
except TraversalError:
if index_filter is not None:
raise # re-raise. When index list is given, treat it as that it must be subsequenced.
loops.append((object,sub))
continue
loops.append(seq)
if n_seq is None:
n_seq = len(seq)
else:
n_seq = min(n_seq, len(seq))
else:
if index_filter and i in index_filter:
if not sub:
raise SubsequencingError_LinkValue("Sublink part {index} can't be subsequenced, because it's a link to whole object, not to subelement.".format(index= i))
loops.append((object,sub))
assert(len(loops) == len(linksublist))
if n_seq is None:
raise SubsequencingError_LinkValue("In supplied link, nothing to loop over compounds was found.")
# expand non-subsequenced parts of linksublist
for i_loop in range(len(loops)):
if type(loops[i_loop]) is not list:
loops[i_loop] = [loops[i_loop]]*n_seq
# form the result
ret = []
for i_seq in range(n_seq):
ret.append(
[loop[i_seq] for loop in loops]
)
return ret
def Subsequence_LinkSub(linksub, traversal = TRAVERSAL_MODES[0], loop = LOOP_MODES[0], object_filter = None, index_filter = None):
"""Subsequence_LinkSub(linksub, traversal = TRAVERSAL_MODES[0], loop = LOOP_MODES[0], object_filter = None):
form a list of values for iterating over elements in App::PropertyLinkSub.
linksub: the value of property, like (object, ["Edge1", "Edge3"...])
traversal: how to unpack compounds
loop: sets which children to process.
object_filter: list or set of objects that should be considered being arrays. If
omitted, all links to subelements are attempted to be enumerated as arrays.
index_list: list or set of ints, that sets which parts of link are to be subsequenced.
If None, all elements are attempted to be subsequenced, and only if none can be, an error
is raised. If index_list is specified, it is treated as strict, and if any
corresponding sublink can't be subsequenced, an error is raised.
return: list of values that can be assigned to the link in a loop.
"""
object, subs = linksub
if not hasattr(subs, '__iter__'):
subs = [subs]
linksublist = toLinkSubList(linksub)
vals = Subsequence_LinkSubList(linksublist, traversal, loop, object_filter, index_filter)
return [toLinkSub(v) for v in vals]
def Subsequence_auto(link, traversal = TRAVERSAL_MODES[0], loop = LOOP_MODES[0], object_filter = None, index_filter = None):
"""Subsequence_auto(link, traversal = TRAVERSAL_MODES[0], loop = LOOP_MODES[0], object_filter = None, index_filter = None):
form a list of values for iterating over elements in App::PropertyLinkSub or
App::PropertyLinkSubList.
link: the value of property
traversal: how to unpack compounds
loop: sets which children to process.
object_filter: list or set of objects that should be considered being arrays. If
omitted, all links to subelements are attempted to be enumerated as arrays.
index_list: list or set of ints, that sets which parts of link are to be subsequenced.
If None, all elements are attempted to be subsequenced, and only if none can be, an error
is raised. If index_list is specified, it is treated as strict, and if any
corresponding sublink can't be subsequenced, an error is raised.
return: list of values that can be assigned to the link in a loop.
"""
if type(link) is list:
# linkSubList or linkList!
if len(link) == 0:
raise SubsequencingError_LinkValue("Cannot subsequence empty link (link is empty list).")
if type(link[0]) is not tuple:
raise SubsequencingError_LinkType("LinkList cannot be subsequenced (only LinkSub or LinkSubList can).")
return Subsequence_LinkSubList(link, traversal, loop, object_filter, index_filter)
elif type(link) is tuple:
# linkSub!
return Subsequence_LinkSub(link, traversal, loop, object_filter, index_filter)
elif link is None:
raise SubsequencingError_LinkValue("Cannot subsequence empty link (link is None).")
else:
raise SubsequencingError_LinkType("Link type not recognized.")
def Subsequence_LinkDict(link_dict, traversal = TRAVERSAL_MODES[0], loop = LOOP_MODES[0], object_filter = None, index_filter = None):
"""Subsequence_LinkDict(link_dict, traversal = TRAVERSAL_MODES[0], loop = LOOP_MODES[0], object_filter = None, index_filter = None):
subsequence a heterogeneous list of links supplied as a dict.
link_dict: dictionary. Key is any, value is the value of some link property. It can be
SubLink, SubList, and plain Link, and LinkList (last two are skipped).
traversal: how to unpack compounds
loop: sets which children to process.
object_filter: list or set of objects that should be considered being arrays. If
omitted, all links to subelements are attempted to be enumerated as arrays.
index_list: list or set of ints, that sets which parts of link are to be subsequenced.
If None, all elements are attempted to be subsequenced, and only if none can be, an error
is raised. If index_list is specified, it is treated as strict, and if any
corresponding sublink can't be subsequenced, an error is raised.
return: tuple (int, dict). Int is the length of the subsequence. Dict contains the
subsequences. It is similar to input dikt, but link values were replaced with lists of
link values. If a link failed to be subsequenced, the key/value pair is not added to
return dict at all."""
ret_dict = {} #ret_dict is the dict to receive result
err_dict = {}
# subsequence all links
n_seq = None # length of shortest subsequence; None means no subsequences were made yet.
for key in link_dict.keys():
link = link_dict[key]
try:
link_seq = Subsequence_auto(link, traversal, loop, object_filter, index_filter)
n_seq = len(link_seq) if n_seq is None else min(n_seq, len(link_seq))
ret_dict[key] = link_seq
# silently absorb non-subsequencable links; fail only if everything fails
except SubsequencingError_LinkType as err:
err_dict[key] = err
except SubsequencingError_LinkValue as err:
err_dict[key] = err
# trim them to shortest subsequence
if n_seq is None:
raise SubsequencingError_LinkValue("In supplied links, nothing to loop over compounds was found. Key-by-key errors follow: {err_list}"
.format(err_list= "\n".join([repr(key)+": "+err_dict[key].message for key in err_dict])))
for key in ret_dict.keys():
seq = ret_dict[key]
seq = seq[0:n_seq]
ret_dict[key] = seq
# done!
return (n_seq, ret_dict)

309
lattice2TopoSeries.py Normal file
View File

@ -0,0 +1,309 @@
#***************************************************************************
#* *
#* Copyright (c) 2016 - Victor Titov (DeepSOIC) *
#* <vv.titov@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 *
#* *
#***************************************************************************
__title__="Lattice TopoSeries feature"
__author__ = "DeepSOIC"
__url__ = ""
__doc__ = "Lattice TopoSeries feature: generates series of shapes by subsequencing sublinks"
import math
import FreeCAD as App
import Part
from lattice2Common import *
import lattice2BaseFeature
import lattice2Executer as Executer
import lattice2Markers as markers
import lattice2Subsequencer as Subsequencer
# --------------------------- general routines ------------------------------------------------
def findAllLinksTo(doc_obj):
"""findAllLinksTo(doc_obj): finds all link properties pointing to supplied object.
Returns them as list of tuples (dependent_object_name, property_name). Does not include
expression links."""
ret = []
doc = doc_obj.Document
for obj in doc_obj.InList:
for prop_name in obj.PropertiesList:
typ = obj.getTypeIdOfProperty(prop_name)
if typ == 'App::PropertyLink':
if readProperty(doc, obj.Name, prop_name) is doc_obj:
ret.append((obj.Name, prop_name))
elif typ == 'App::PropertyLinkList':
if doc_obj in readProperty(doc, obj.Name, prop_name):
ret.append((obj.Name, prop_name))
elif typ == 'App::PropertyLinkSub':
val = readProperty(doc, obj.Name, prop_name)
if val is not None and doc_obj is val[0]:
ret.append((obj.Name, prop_name))
elif typ == 'App::PropertyLinkSubList':
if doc_obj in [tup[0] for tup in readProperty(doc, obj.Name, prop_name)]:
ret.append((obj.Name, prop_name))
return ret
def readProperty(doc, object_name, property_name):
return getattr(doc.getObject(object_name), property_name)
def writeProperty(doc, object_name, property_name, value):
setattr(doc.getObject(object_name), property_name, value)
# -------------------------- document object --------------------------------------------------
def makeLatticeTopoSeries(name):
'''makeLatticeTopoSeries(name): makes a LatticeTopoSeries object.'''
return lattice2BaseFeature.makeLatticeFeature(name, LatticeTopoSeries, ViewProviderLatticeTopoSeries)
class LatticeTopoSeries(lattice2BaseFeature.LatticeFeature):
"The Lattice TopoSeries object"
def derivedInit(self,obj):
self.Type = "LatticeTopoSeries"
obj.addProperty("App::PropertyLink","ObjectToTake","Lattice TopoSeries","Object to collect permutations of. Can be any generic shape, as well as an array of placements.")
obj.addProperty("App::PropertyLink","ObjectToLoopOver","Lattice TopoSeries","Array object to subsequence sublinks to.")
obj.addProperty("App::PropertyEnumeration", "CycleMode", "Lattice TopoSeries", "Sets how to treat the ObjectToLoopOver")
obj.CycleMode = ["Open", "Periodic"]
obj.addProperty("App::PropertyEnumeration","Recomputing","Lattice TopoSeries","Sets recomputing policy.")
obj.Recomputing = ["Disabled", "Recompute Once", "Enabled"]
obj.Recomputing = "Disabled" # recomputing TopoSeries can be very long, so disable it by default
def makeSubsequence(self, selfobj, object_to_loop):
# gather up the links
links = findAllLinksTo(object_to_loop)
if self.isVerbose():
print ("All links to {feature}:\n {links}"
.format(feature= object_to_loop.Document.Name+"."+object_to_loop.Name,
links= "\n ".join([link[0]+"."+link[1] for link in links]) ) )
# subsequencing
# prepare dict of link values
linkdict = {} #key is tuple (object_name, property_name). Value is the value of property.
for link in links:
link_val = readProperty(object_to_loop.Document, link[0], link[1])
linkdict[link] = link_val
# do the subsequencing
ret = Subsequencer.Subsequence_LinkDict(
linkdict,
loop= ('Till end' if selfobj.CycleMode == 'Open' else 'All around'),
object_filter= [object_to_loop] )
if self.isVerbose():
print ("Subsequence made. Length: {n_seq}".format(n_seq= ret[0]))
return ret
def isVerbose(self):
return True
def derivedExecute(self,selfobj):
if selfobj.Recomputing == "Disabled":
raise ValueError(selfobj.Name+": recomputing of this object is currently disabled. Modify 'Recomputing' property to enable it.")
try:
# do the subsequencing in this document first, to verify stuff is set up correctly, and to obtain sequence length
if self.isVerbose():
print ("In-place pre-subsequencing, for early check")
n_seq, subs_linkdict = self.makeSubsequence(selfobj, selfobj.ObjectToLoopOver)
bGui = bool(App.GuiUp) and Executer.globalIsCreatingLatticeFeature #disabled for most recomputes, because it causes a crash if property edits are approved by hitting Enter
if bGui:
import PySide
progress = PySide.QtGui.QProgressDialog(u"Recomputing "+selfobj.Label, u"Abort", 0, n_seq+1)
progress.setModal(True)
progress.show()
doc1 = selfobj.Document
doc2 = App.newDocument()
object_to_take_in_doc2 = None # define the variable, to prevent del() in finally block from raising another error
object_to_loop_in_doc2 = None
try:
if self.isVerbose():
print ("Copying object with dependencies to a temporary document...")
doc2.copyObject(selfobj.ObjectToTake, True)
if self.isVerbose():
print ("Enabling nested para/toposeries, if any...")
#if there are nested para/toposeries in the dependencies, make sure to enable them
for objd2 in doc2.Objects:
if hasattr(objd2,"Recomputing"):
try:
objd2.Recomputing = "Enabled"
objd2.purgeTouched()
except exception:
Executer.warning(selfobj,"Failed to enable recomputing of "+objd2.Name)
object_to_take_in_doc2 = doc2.getObject(selfobj.ObjectToTake.Name)
object_to_loop_in_doc2 = doc2.getObject(selfobj.ObjectToLoopOver.Name)
if bGui:
progress.setValue(1)
if self.isVerbose():
print ("Repeating subsequencing in temporary document...")
n_seq, subs_linkdict = self.makeSubsequence(selfobj, object_to_loop_in_doc2)
output_shapes = []
for i in range(n_seq):
if self.isVerbose():
print ("Computing {x}/{y}".format(x= i+1, y= n_seq))
for key in subs_linkdict:
writeProperty(doc2, key[0], key[1], subs_linkdict[key][i])
#recompute
doc2.recompute()
#get shape
shape = None
for obj in doc2.Objects:
if 'Invalid' in obj.State:
Executer.error(obj,"Recomputing shape for subsequence index "+repr(i)+" failed.")
scale = 1.0
try:
if not selfobj.ObjectToTake.Shape.isNull():
scale = selfobj.ObjectToTake.Shape.BoundBox.DiagonalLength/math.sqrt(3)
except Exception:
pass
if scale < DistConfusion * 100:
scale = 1.0
shape = markers.getNullShapeShape(scale)
if shape is None:
shape = object_to_take_in_doc2.Shape.copy()
output_shapes.append(shape)
#update progress
if bGui:
progress.setValue(progress.value()+1)
if progress.wasCanceled():
raise Executer.CancelError()
finally:
#delete all references, before destroying the document. Probably not required, but to be sure...
if self.isVerbose():
print ("Cleanup...")
del(object_to_take_in_doc2)
del(object_to_loop_in_doc2)
doc2_name = doc2.Name
del(doc2)
App.closeDocument(doc2_name)
if bGui:
progress.setValue(n_seq+1)
selfobj.Shape = Part.makeCompound(output_shapes)
output_is_lattice = lattice2BaseFeature.isObjectLattice(selfobj.ObjectToTake)
if 'Auto' in selfobj.isLattice:
new_isLattice = 'Auto-On' if output_is_lattice else 'Auto-Off'
if selfobj.isLattice != new_isLattice:#check, to not cause onChanged without necessity (onChange messes with colors, it's better to keep user color)
selfobj.isLattice = new_isLattice
finally:
if selfobj.Recomputing == "Recompute Once":
selfobj.Recomputing = "Disabled"
return "suppress" # "suppress" disables most convenience code of lattice2BaseFeature. We do it because we build a nested array, which are not yet supported by lattice WB.
class ViewProviderLatticeTopoSeries(lattice2BaseFeature.ViewProviderLatticeFeature):
def getIcon(self):
return getIconPath("Lattice2_TopoSeries.svg")
def claimChildren(self):
return [self.Object.ObjectToTake]
# -------------------------- /document object --------------------------------------------------
# -------------------------- Gui command --------------------------------------------------
def CreateLatticeTopoSeries(name, shapeObj, loopObj):
FreeCADGui.addModule("lattice2TopoSeries")
FreeCADGui.addModule("lattice2Executer")
#fill in properties
FreeCADGui.doCommand("f = lattice2TopoSeries.makeLatticeTopoSeries(name='"+name+"')")
FreeCADGui.doCommand("f.ObjectToTake = App.ActiveDocument."+shapeObj.Name)
FreeCADGui.doCommand("f.ObjectToLoopOver = App.ActiveDocument."+loopObj.Name)
#execute
FreeCADGui.doCommand("f.Recomputing = 'Recompute Once'")
FreeCADGui.doCommand("lattice2Executer.executeFeature(f)")
#hide something
FreeCADGui.doCommand("f.ObjectToTake.ViewObject.hide()")
#finalize
FreeCADGui.doCommand("Gui.Selection.addSelection(f)")
FreeCADGui.doCommand("f = None")
def cmdCreateSeries():
sel = FreeCADGui.Selection.getSelectionEx()
if len(sel) == 2 :
doc = FreeCAD.ActiveDocument #remember it! Recomputing TopoSeries messes up ActiveDocument, so committing transaction is screwed up...
if sel[1].Object.Shape.ShapeType != "Compound":
raise SelectionError("Bad selection", "Second selected object ({label}) should be an array of shapes (a compound). It is not.".format(label= sel[1].Object.Label))
doc.openTransaction("TopoSeries")
CreateLatticeTopoSeries("TopoSeries",sel[0].Object, sel[1].Object)
deselect(sel)
doc.commitTransaction()
else:
raise SelectionError("Bad selection","Please select two objects, first. First one is the result shape to collect variation of. Second one is an array to loop over.")
class _CommandLatticeTopoSeries:
"Command to create LatticeTopoSeries feature"
def GetResources(self):
return {'Pixmap' : getIconPath("Lattice2_TopoSeries.svg"),
'MenuText': QtCore.QT_TRANSLATE_NOOP("Lattice2_TopoSeries","TopoSeries"),
'Accel': "",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Lattice2_TopoSeries","TopoSeries: generate an array of shapes by subsequencing (looping subelement links across an array).")}
def Activated(self):
try:
if len(FreeCADGui.Selection.getSelection())==0:
infoMessage("TopoSeries",
"TopoSeries command. Generates an array of shapes by subsequencing links in dependencies (looping subelement links across an array).\n\n"+
"Please select an object to generate array from, and an array object to loop over (order of selection matters!). Then invoke the command.\n\n"+
"TopoSeries will find all objects that link to the array object, and if a link is a link to subelement (e.g., to Edge1), it will advance it to the corresponding subelements of next array child. Then recompute the result shape and output it as a child. So on until any link goes out of bounds (or it will go around, if 'CycleMode' property is set to `Periodic`)."
)
return
cmdCreateSeries()
except Exception as err:
msgError(err)
def IsActive(self):
if FreeCAD.ActiveDocument:
return True
else:
return False
FreeCADGui.addCommand('Lattice2_TopoSeries', _CommandLatticeTopoSeries())
exportedCommands = ['Lattice2_TopoSeries']

64
lattice2Utils.py Normal file
View File

@ -0,0 +1,64 @@
#***************************************************************************
#* *
#* Copyright (c) 2017 - Victor Titov (DeepSOIC) *
#* <vv.titov@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 *
#* *
#***************************************************************************
__title__="Utility functions for Lattice2"
__author__ = "DeepSOIC"
__url__ = ""
def sublinkFromApart(object, subnames):
if type(subnames) is not list and type(subnames) is not tuple:
subnames = [subnames]
return (object, [str(sub) for sub in subnames]) if object is not None else None
def syncSublinkApart(selfobj, prop, sublink_prop_name, obj_property_name, subnames_prop_name):
"""syncSublinkApart(selfobj, prop, sublink_prop_name, obj_property_name, subnames_prop_name):
Function that synchronizes a sublink mirror property with split apart property pair.
selfobj, prop: as in onChanged
sublink_prop_name: name of property of type "App::PropertyLinkSub"
obj_property_name, subnames_prop_name: names of apart properties. First must be
App::PropertyLink. Second can be PropertyString or PropertyStringList.
"""
# check if changed property is relevant
if not prop in (sublink_prop_name, obj_property_name, subnames_prop_name):
return
#if restoring, some of the properties may not exist yet. If they don't, skip, and wait for the last relevant onChanged.
if not ( hasattr(selfobj, sublink_prop_name) and hasattr(selfobj, obj_property_name) and hasattr(selfobj, subnames_prop_name) ):
return
sl = sublinkFromApart(getattr(selfobj,obj_property_name), getattr(selfobj,subnames_prop_name))
if getattr(selfobj,sublink_prop_name) != sl: #assign only if actually changed, to prevent recursive onChanged calls
if prop == sublink_prop_name:
# update apart properties
tup_apart = (None, []) if getattr(selfobj,sublink_prop_name) is None else getattr(selfobj,sublink_prop_name)
if type(getattr(selfobj, subnames_prop_name)) is not list:
tup_apart = (tup_apart[0], tup_apart[1][0] if len(tup_apart[1]) == 1 else "")
setattr(selfobj, obj_property_name, tup_apart[0])
if tup_apart[0] is not None:
setattr(selfobj, subnames_prop_name, tup_apart[1])
else:
setattr(selfobj, sublink_prop_name, sl)

File diff suppressed because one or more lines are too long