Create workbench
This commit is contained in:
parent
866a20dd71
commit
caca713d8d
369
Gui/Resources/icons/Assembly_Move.svg
Normal file
369
Gui/Resources/icons/Assembly_Move.svg
Normal file
|
@ -0,0 +1,369 @@
|
||||||
|
<?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="svg2963"
|
||||||
|
sodipodi:version="0.32"
|
||||||
|
inkscape:version="0.48.5 r10040"
|
||||||
|
sodipodi:docname="Draft_Move.svg"
|
||||||
|
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||||
|
version="1.1">
|
||||||
|
<defs
|
||||||
|
id="defs2965">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3354">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#2157c7;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop3356" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#6daaff;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop3358" />
|
||||||
|
</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="perspective2971" />
|
||||||
|
<linearGradient
|
||||||
|
gradientTransform="matrix(0,-1.4500001,1.4705882,0,-15.05882,91.45)"
|
||||||
|
y2="36.079998"
|
||||||
|
x2="21.689653"
|
||||||
|
y1="29.279999"
|
||||||
|
x1="56.172409"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient3036"
|
||||||
|
xlink:href="#linearGradient3895"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3895">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#729fcf;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop3897" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#204a87;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop3899" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
y2="36.079998"
|
||||||
|
x2="21.689653"
|
||||||
|
y1="29.279999"
|
||||||
|
x1="56.172409"
|
||||||
|
gradientTransform="matrix(0,-0.58000003,0.58823527,0,13.176471,38.379999)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient3918-3"
|
||||||
|
xlink:href="#linearGradient3895-6"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3895-6">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#729fcf;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop3897-7" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#204a87;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop3899-5" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
y2="36.079998"
|
||||||
|
x2="21.689653"
|
||||||
|
y1="29.279999"
|
||||||
|
x1="56.172409"
|
||||||
|
gradientTransform="matrix(0.58000003,0,0,0.58823527,25.620001,13.176471)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient3029-6"
|
||||||
|
xlink:href="#linearGradient3895-6-2"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3895-6-2">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#729fcf;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop3897-7-9" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#204a87;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop3899-5-1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
y2="36.079998"
|
||||||
|
x2="21.689653"
|
||||||
|
y1="29.279999"
|
||||||
|
x1="56.172409"
|
||||||
|
gradientTransform="matrix(0,-0.58000003,0.58823527,0,13.176471,38.379999)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient3918-0"
|
||||||
|
xlink:href="#linearGradient3895-9"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3895-9">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#729fcf;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop3897-3" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#204a87;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop3899-6" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3895"
|
||||||
|
id="linearGradient3154"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0,-0.58000003,0.58823527,0,13.176471,38.379999)"
|
||||||
|
x1="45.482754"
|
||||||
|
y1="11.599999"
|
||||||
|
x2="-23.482759"
|
||||||
|
y2="52.400002" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3895-6-2"
|
||||||
|
id="linearGradient3156"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(-0.58000003,0,0,0.58823527,38.379999,13.176471)"
|
||||||
|
x1="31.689651"
|
||||||
|
y1="-2.0000007"
|
||||||
|
x2="-9.6896563"
|
||||||
|
y2="66" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3895-6"
|
||||||
|
id="linearGradient3158"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.58000003,0,0,0.58823527,25.620001,13.176471)"
|
||||||
|
x1="-9.6896563"
|
||||||
|
y1="-2.0000007"
|
||||||
|
x2="31.689651"
|
||||||
|
y2="66" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3895-9"
|
||||||
|
id="linearGradient3160"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0,0.58000003,0.58823527,0,13.176471,25.620001)"
|
||||||
|
x1="-23.482759"
|
||||||
|
y1="11.599999"
|
||||||
|
x2="45.482754"
|
||||||
|
y2="52.400002" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3895-9"
|
||||||
|
id="linearGradient3936"
|
||||||
|
x1="20"
|
||||||
|
y1="12"
|
||||||
|
x2="44"
|
||||||
|
y2="52"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3895-9"
|
||||||
|
id="linearGradient3944"
|
||||||
|
x1="20"
|
||||||
|
y1="12"
|
||||||
|
x2="44"
|
||||||
|
y2="52"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="10.193662"
|
||||||
|
inkscape:cx="21.49082"
|
||||||
|
inkscape:cy="36.860521"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:grid-bbox="true"
|
||||||
|
inkscape:window-width="1600"
|
||||||
|
inkscape:window-height="837"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:snap-global="true"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid3009"
|
||||||
|
empspacing="2"
|
||||||
|
visible="true"
|
||||||
|
enabled="true"
|
||||||
|
snapvisiblegridlinesonly="true" />
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid3011"
|
||||||
|
empspacing="2"
|
||||||
|
visible="true"
|
||||||
|
enabled="true"
|
||||||
|
snapvisiblegridlinesonly="true"
|
||||||
|
spacingx="16px"
|
||||||
|
spacingy="16px"
|
||||||
|
empcolor="#ff0000"
|
||||||
|
empopacity="0.25098039"
|
||||||
|
color="#ff0000"
|
||||||
|
opacity="0.1254902" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<g
|
||||||
|
id="layer1"
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer">
|
||||||
|
<rect
|
||||||
|
style="fill:url(#linearGradient3936);fill-opacity:1;stroke:none"
|
||||||
|
id="rect3126"
|
||||||
|
width="12"
|
||||||
|
height="6"
|
||||||
|
x="26"
|
||||||
|
y="29" />
|
||||||
|
<rect
|
||||||
|
style="fill:url(#linearGradient3944);fill-opacity:1;stroke:none"
|
||||||
|
id="rect3126-2"
|
||||||
|
width="6"
|
||||||
|
height="11.999999"
|
||||||
|
x="29"
|
||||||
|
y="26" />
|
||||||
|
<g
|
||||||
|
id="g4351"
|
||||||
|
inkscape:export-filename="/home/yorik/Documents/Lab/Draft/icons/move.png"
|
||||||
|
inkscape:export-xdpi="6.5591564"
|
||||||
|
inkscape:export-ydpi="6.5591564"
|
||||||
|
transform="matrix(0.1378133,0,0,0.1378133,-221.39699,-138.35275)" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:url(#linearGradient3154);fill-opacity:1;fill-rule:evenodd;stroke:#0b1521;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||||
|
d="m 37,28 0,-15 6,0 -11,-10 -11,10 6,0 0,15"
|
||||||
|
id="path3343"
|
||||||
|
sodipodi:nodetypes="ccccccc"
|
||||||
|
inkscape:export-filename="/home/yorik/Documents/Lab/Draft/icons/changeprop.png"
|
||||||
|
inkscape:export-xdpi="4.1683898"
|
||||||
|
inkscape:export-ydpi="4.1683898" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||||
|
d="M 35,29 35,11 37.831259,11 32,5.7026937 26.168741,11 29,11 29,29"
|
||||||
|
id="path3343-2"
|
||||||
|
sodipodi:nodetypes="ccccccc"
|
||||||
|
inkscape:export-filename="/home/yorik/Documents/Lab/Draft/icons/changeprop.png"
|
||||||
|
inkscape:export-xdpi="4.1683898"
|
||||||
|
inkscape:export-ydpi="4.1683898" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:url(#linearGradient3158);fill-opacity:1;fill-rule:evenodd;stroke:#0b1521;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||||
|
d="m 37,37 14,0 0,6 10,-11 -10,-11 0,6 -14,0"
|
||||||
|
id="path3343-3"
|
||||||
|
sodipodi:nodetypes="ccccccc"
|
||||||
|
inkscape:export-filename="/home/yorik/Documents/Lab/Draft/icons/changeprop.png"
|
||||||
|
inkscape:export-xdpi="4.1683898"
|
||||||
|
inkscape:export-ydpi="4.1683898" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||||
|
d="m 35,35 18,0 0,2.831259 L 58.297306,32 53,26.168741 53,29 34,29"
|
||||||
|
id="path3343-2-5"
|
||||||
|
sodipodi:nodetypes="ccccccc"
|
||||||
|
inkscape:export-filename="/home/yorik/Documents/Lab/Draft/icons/changeprop.png"
|
||||||
|
inkscape:export-xdpi="4.1683898"
|
||||||
|
inkscape:export-ydpi="4.1683898" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:url(#linearGradient3156);fill-opacity:1;fill-rule:evenodd;stroke:#0b1521;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||||
|
d="m 27,37 -14,0 0,6 -10,-11 10,-11 0,6 14,0"
|
||||||
|
id="path3343-3-2"
|
||||||
|
sodipodi:nodetypes="ccccccc"
|
||||||
|
inkscape:export-filename="/home/yorik/Documents/Lab/Draft/icons/changeprop.png"
|
||||||
|
inkscape:export-xdpi="4.1683898"
|
||||||
|
inkscape:export-ydpi="4.1683898" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||||
|
d="M 29,35 11,35 11,37.831259 5.702694,32 11,26.168741 11,29 30,29"
|
||||||
|
id="path3343-2-5-7"
|
||||||
|
sodipodi:nodetypes="ccccccc"
|
||||||
|
inkscape:export-filename="/home/yorik/Documents/Lab/Draft/icons/changeprop.png"
|
||||||
|
inkscape:export-xdpi="4.1683898"
|
||||||
|
inkscape:export-ydpi="4.1683898" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:url(#linearGradient3160);fill-opacity:1;fill-rule:evenodd;stroke:#0b1521;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||||
|
d="m 37,36 0,15 6,0 -11,10 -11,-10 6,0 0,-15"
|
||||||
|
id="path3343-0"
|
||||||
|
sodipodi:nodetypes="ccccccc"
|
||||||
|
inkscape:export-filename="/home/yorik/Documents/Lab/Draft/icons/changeprop.png"
|
||||||
|
inkscape:export-xdpi="4.1683898"
|
||||||
|
inkscape:export-ydpi="4.1683898" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||||
|
d="m 35,34 0,19 2.831259,0 L 32,58.297306 26.168741,53 29,53 29,34"
|
||||||
|
id="path3343-2-6"
|
||||||
|
sodipodi:nodetypes="ccccccc"
|
||||||
|
inkscape:export-filename="/home/yorik/Documents/Lab/Draft/icons/changeprop.png"
|
||||||
|
inkscape:export-xdpi="4.1683898"
|
||||||
|
inkscape:export-ydpi="4.1683898" />
|
||||||
|
</g>
|
||||||
|
<metadata
|
||||||
|
id="metadata5006">
|
||||||
|
<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>Draft_Move</dc:title>
|
||||||
|
<cc:license
|
||||||
|
rdf:resource="" />
|
||||||
|
<dc:date>Mon Oct 10 13:44:52 2011 +0000</dc:date>
|
||||||
|
<dc:creator>
|
||||||
|
<cc:Agent>
|
||||||
|
<dc:title>[wmayer]</dc:title>
|
||||||
|
</cc:Agent>
|
||||||
|
</dc:creator>
|
||||||
|
<dc:rights>
|
||||||
|
<cc:Agent>
|
||||||
|
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||||
|
</cc:Agent>
|
||||||
|
</dc:rights>
|
||||||
|
<dc:publisher>
|
||||||
|
<cc:Agent>
|
||||||
|
<dc:title>FreeCAD</dc:title>
|
||||||
|
</cc:Agent>
|
||||||
|
</dc:publisher>
|
||||||
|
<dc:identifier>FreeCAD/src/Mod/Draft/Resources/icons/Draft_Move.svg</dc:identifier>
|
||||||
|
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
|
||||||
|
<dc:contributor>
|
||||||
|
<cc:Agent>
|
||||||
|
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||||
|
</cc:Agent>
|
||||||
|
</dc:contributor>
|
||||||
|
<dc:subject>
|
||||||
|
<rdf:Bag>
|
||||||
|
<rdf:li>arrow</rdf:li>
|
||||||
|
<rdf:li>move</rdf:li>
|
||||||
|
<rdf:li>arrows</rdf:li>
|
||||||
|
<rdf:li>compass</rdf:li>
|
||||||
|
<rdf:li>cross</rdf:li>
|
||||||
|
</rdf:Bag>
|
||||||
|
</dc:subject>
|
||||||
|
<dc:description>Four equally sized arrow heads at 90° to eachother, all joined at the tail</dc:description>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
27
InitGui.py
Normal file
27
InitGui.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import FreeCAD, FreeCADGui
|
||||||
|
|
||||||
|
class Assembly3Workbench(FreeCADGui.Workbench):
|
||||||
|
import asm3
|
||||||
|
MenuText = 'Assembly 3'
|
||||||
|
Icon = asm3.utils.addIconToFCAD('AssemblyWorkbench.svg')
|
||||||
|
|
||||||
|
def Activated(self):
|
||||||
|
import asm3
|
||||||
|
asm3.constraint.Observer.attach()
|
||||||
|
|
||||||
|
def Deactivated(self):
|
||||||
|
import asm3
|
||||||
|
asm3.constraint.Observer.detach()
|
||||||
|
|
||||||
|
def Initialize(self):
|
||||||
|
import asm3
|
||||||
|
cmds = asm3.gui.AsmCmdType.getInfo().TypeNames
|
||||||
|
asm3.utils.logger.debug(cmds)
|
||||||
|
self.appendToolbar('asm3',cmds)
|
||||||
|
self.appendMenu('&Assembly3', cmds)
|
||||||
|
self.appendToolbar('asm3 Constraint',
|
||||||
|
asm3.constraint.Constraint.CommandList)
|
||||||
|
# FreeCADGui.addPreferencePage(
|
||||||
|
# ':/assembly3/ui/assembly3_prefs.ui','Assembly3')
|
||||||
|
|
||||||
|
FreeCADGui.addWorkbench(Assembly3Workbench)
|
|
@ -1,5 +1,5 @@
|
||||||
import FreeCAD, FreeCADGui, Part
|
import FreeCAD, FreeCADGui, Part
|
||||||
from asm3 import utils,assembly,solver,constraint,system
|
from asm3 import proxy,utils,assembly,solver,constraint,system,gui
|
||||||
from asm3.utils import logger
|
from asm3.utils import logger
|
||||||
from asm3.assembly import Assembly,AsmConstraint
|
from asm3.assembly import Assembly,AsmConstraint
|
||||||
try:
|
try:
|
||||||
|
|
74
assembly.py
74
assembly.py
|
@ -121,6 +121,7 @@ class AsmPartGroup(AsmGroup):
|
||||||
obj = parent.Document.addObject("App::FeaturePython",name,
|
obj = parent.Document.addObject("App::FeaturePython",name,
|
||||||
AsmPartGroup(parent),None,True)
|
AsmPartGroup(parent),None,True)
|
||||||
ViewProviderAsmPartGroup(obj.ViewObject)
|
ViewProviderAsmPartGroup(obj.ViewObject)
|
||||||
|
obj.purgeTouched()
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
|
@ -130,6 +131,11 @@ class ViewProviderAsmPartGroup(ViewProviderAsmBase):
|
||||||
def onDelete(self,_obj,_subs):
|
def onDelete(self,_obj,_subs):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def canDropObject(self,obj):
|
||||||
|
return isTypeOf(obj,Assembly) or not isTypeOf(obj,AsmBase)
|
||||||
|
|
||||||
|
def canDropObjects(self):
|
||||||
|
return True
|
||||||
|
|
||||||
class AsmElement(AsmBase):
|
class AsmElement(AsmBase):
|
||||||
def __init__(self,parent):
|
def __init__(self,parent):
|
||||||
|
@ -373,7 +379,7 @@ class AsmElementLink(AsmBase):
|
||||||
if not ret:
|
if not ret:
|
||||||
# It is from a non assembly child part, then use our own element
|
# It is from a non assembly child part, then use our own element
|
||||||
# group as the holder for elements
|
# group as the holder for elements
|
||||||
ret = [Assembly.Selection(assembly.obj,owner,subname)]
|
ret = [Assembly.Info(assembly.obj,owner,subname)]
|
||||||
|
|
||||||
if not isTypeOf(ret[-1].Object,AsmPartGroup):
|
if not isTypeOf(ret[-1].Object,AsmPartGroup):
|
||||||
raise RuntimeError('Invalid element link ' + subname)
|
raise RuntimeError('Invalid element link ' + subname)
|
||||||
|
@ -436,7 +442,8 @@ class AsmElementLink(AsmBase):
|
||||||
if not isTypeOf(part,Assembly,True) and \
|
if not isTypeOf(part,Assembly,True) and \
|
||||||
not Constraint.isDisabled(self.parent.obj) and \
|
not Constraint.isDisabled(self.parent.obj) and \
|
||||||
not Constraint.isLocked(self.parent.obj):
|
not Constraint.isLocked(self.parent.obj):
|
||||||
getter = getattr(part.getLinkedObject(True),'getLinkExtProperty')
|
getter = getattr(part.getLinkedObject(True),
|
||||||
|
'getLinkExtProperty',None)
|
||||||
|
|
||||||
# special treatment of link array (i.e. when ElementCount!=0), we
|
# special treatment of link array (i.e. when ElementCount!=0), we
|
||||||
# allow the array element to be moveable by the solver
|
# allow the array element to be moveable by the solver
|
||||||
|
@ -543,6 +550,7 @@ class ViewProviderAsmElementLink(ViewProviderAsmBase):
|
||||||
class AsmConstraint(AsmGroup):
|
class AsmConstraint(AsmGroup):
|
||||||
|
|
||||||
def __init__(self,parent):
|
def __init__(self,parent):
|
||||||
|
self._initializing = True
|
||||||
self.elements = None
|
self.elements = None
|
||||||
self.parent = getProxy(parent,AsmConstraintGroup)
|
self.parent = getProxy(parent,AsmConstraintGroup)
|
||||||
super(AsmConstraint,self).__init__()
|
super(AsmConstraint,self).__init__()
|
||||||
|
@ -585,8 +593,10 @@ class AsmConstraint(AsmGroup):
|
||||||
obj.recompute()
|
obj.recompute()
|
||||||
|
|
||||||
def execute(self,_obj):
|
def execute(self,_obj):
|
||||||
self.checkSupport()
|
if not getattr(self,'_initializing',False) and\
|
||||||
self.getElements(True)
|
getattr(self,'parent',None):
|
||||||
|
self.checkSupport()
|
||||||
|
self.getElements(True)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def getElements(self,refresh=False):
|
def getElements(self,refresh=False):
|
||||||
|
@ -691,6 +701,8 @@ class AsmConstraint(AsmGroup):
|
||||||
|
|
||||||
for e in selection.Elements:
|
for e in selection.Elements:
|
||||||
AsmElementLink.make(AsmElementLink.MakeInfo(cstr,*e))
|
AsmElementLink.make(AsmElementLink.MakeInfo(cstr,*e))
|
||||||
|
cstr.Proxy._initializing = False
|
||||||
|
cstr.recompute()
|
||||||
return cstr
|
return cstr
|
||||||
|
|
||||||
|
|
||||||
|
@ -727,6 +739,7 @@ class AsmConstraintGroup(AsmGroup):
|
||||||
obj = parent.Document.addObject("App::FeaturePython",name,
|
obj = parent.Document.addObject("App::FeaturePython",name,
|
||||||
AsmConstraintGroup(parent),None,True)
|
AsmConstraintGroup(parent),None,True)
|
||||||
ViewProviderAsmConstraintGroup(obj.ViewObject)
|
ViewProviderAsmConstraintGroup(obj.ViewObject)
|
||||||
|
obj.purgeTouched()
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
|
@ -750,6 +763,7 @@ class AsmElementGroup(AsmGroup):
|
||||||
obj = parent.Document.addObject("App::FeaturePython",name,
|
obj = parent.Document.addObject("App::FeaturePython",name,
|
||||||
AsmElementGroup(parent),None,True)
|
AsmElementGroup(parent),None,True)
|
||||||
ViewProviderAsmElementGroup(obj.ViewObject)
|
ViewProviderAsmElementGroup(obj.ViewObject)
|
||||||
|
obj.purgeTouched()
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
|
@ -797,17 +811,23 @@ class Assembly(AsmGroup):
|
||||||
System.touch(obj)
|
System.touch(obj)
|
||||||
return False # return False to call LinkBaseExtension::execute()
|
return False # return False to call LinkBaseExtension::execute()
|
||||||
|
|
||||||
def onSolverChanged(self):
|
def onSolverChanged(self,setup=False):
|
||||||
for obj in self.getConstraintGroup().Group:
|
for obj in self.getConstraintGroup().Group:
|
||||||
|
# setup==True usually means we are restoring, so try to restore the
|
||||||
|
# non-touched state if possible, since recompute() below will touch
|
||||||
|
# the constraint object
|
||||||
|
touched = not setup or 'Touched' in obj.State
|
||||||
obj.recompute()
|
obj.recompute()
|
||||||
|
if not touched:
|
||||||
|
obj.purgeTouched()
|
||||||
|
|
||||||
def buildShape(self):
|
def buildShape(self):
|
||||||
|
import Part
|
||||||
obj = self.obj
|
obj = self.obj
|
||||||
if not obj.BuildShape:
|
if obj.BuildShape == BuildShapeNone:
|
||||||
obj.Shape.nullify()
|
obj.Shape = Part.Shape()
|
||||||
return
|
return
|
||||||
|
|
||||||
import Part
|
|
||||||
shape = []
|
shape = []
|
||||||
partGroup = self.getPartGroup(obj)
|
partGroup = self.getPartGroup(obj)
|
||||||
group = partGroup.Group
|
group = partGroup.Group
|
||||||
|
@ -855,7 +875,8 @@ class Assembly(AsmGroup):
|
||||||
# all groups exist. The order of the group is important to make sure
|
# all groups exist. The order of the group is important to make sure
|
||||||
# correct rendering and picking behavior
|
# correct rendering and picking behavior
|
||||||
self.getPartGroup(True)
|
self.getPartGroup(True)
|
||||||
self.onSolverChanged()
|
|
||||||
|
self.onSolverChanged(True)
|
||||||
|
|
||||||
def onChanged(self, obj, prop):
|
def onChanged(self, obj, prop):
|
||||||
if prop == 'BuildShape':
|
if prop == 'BuildShape':
|
||||||
|
@ -958,10 +979,28 @@ class Assembly(AsmGroup):
|
||||||
"Part::FeaturePython",name,Assembly(),None,True)
|
"Part::FeaturePython",name,Assembly(),None,True)
|
||||||
ViewProviderAssembly(obj.ViewObject)
|
ViewProviderAssembly(obj.ViewObject)
|
||||||
obj.Visibility = True
|
obj.Visibility = True
|
||||||
|
obj.purgeTouched()
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
Info = namedtuple('AssemblyInfo',('Assembly','Object','Subname'))
|
Info = namedtuple('AssemblyInfo',('Assembly','Object','Subname'))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def find(sels=None):
|
||||||
|
'Find all assembly objects among the current selection'
|
||||||
|
objs = set()
|
||||||
|
if sels is None:
|
||||||
|
sels = FreeCADGui.Selection.getSelectionEx('',False)
|
||||||
|
for sel in sels:
|
||||||
|
if not sel.SubElementNames:
|
||||||
|
if isTypeOf(sel.Object,Assembly):
|
||||||
|
objs.add(sel.Object)
|
||||||
|
continue
|
||||||
|
for subname in sel.SubElementNames:
|
||||||
|
ret = Assembly.findChild(sel.Object,subname,recursive=True)
|
||||||
|
if ret:
|
||||||
|
objs.add(ret[-1].Assembly)
|
||||||
|
return tuple(objs)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def findChild(obj,subname,childType=None,
|
def findChild(obj,subname,childType=None,
|
||||||
recursive=False,relativeToChild=True):
|
recursive=False,relativeToChild=True):
|
||||||
|
@ -991,7 +1030,7 @@ class Assembly(AsmGroup):
|
||||||
if isTypeOf(obj,Assembly,True):
|
if isTypeOf(obj,Assembly,True):
|
||||||
assembly = obj
|
assembly = obj
|
||||||
subs = subname if isinstance(subname,list) else subname.split('.')
|
subs = subname if isinstance(subname,list) else subname.split('.')
|
||||||
for i,name in enumerate(subs[:-2]):
|
for i,name in enumerate(subs[:-1]):
|
||||||
obj = obj.getSubObject(name+'.',1)
|
obj = obj.getSubObject(name+'.',1)
|
||||||
if not obj:
|
if not obj:
|
||||||
raise RuntimeError('Cannot find sub object {}'.format(name))
|
raise RuntimeError('Cannot find sub object {}'.format(name))
|
||||||
|
@ -1043,12 +1082,21 @@ class ViewProviderAssembly(ViewProviderAsmGroup):
|
||||||
def canDragObjects(self):
|
def canDragObjects(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def canDropObject(self,_child):
|
@property
|
||||||
return False
|
def PartGroup(self):
|
||||||
|
return self.ViewObject.Object.Proxy.getPartGroup()
|
||||||
|
|
||||||
|
def canDropObject(self,obj):
|
||||||
|
self.PartGroup.ViewObject.canDropObject(obj)
|
||||||
|
|
||||||
def canDropObjects(self):
|
def canDropObjects(self):
|
||||||
return False
|
return True
|
||||||
|
|
||||||
|
def dropObjectEx(self,_vobj,obj,owner,subname):
|
||||||
|
self.PartGroup.ViewObject.dropObject(obj,owner,subname)
|
||||||
|
|
||||||
def getIcon(self):
|
def getIcon(self):
|
||||||
return System.getIcon(self.ViewObject.Object)
|
return System.getIcon(self.ViewObject.Object)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
124
constraint.py
124
constraint.py
|
@ -145,14 +145,83 @@ def _a(solver,partInfo,subname,shape):
|
||||||
return _c(solver,partInfo,subname,shape,True)
|
return _c(solver,partInfo,subname,shape,True)
|
||||||
|
|
||||||
|
|
||||||
|
class ConstraintCommand:
|
||||||
|
def __init__(self,tp):
|
||||||
|
self.tp = tp
|
||||||
|
|
||||||
|
def GetResources(self):
|
||||||
|
return self.tp.GetResources()
|
||||||
|
|
||||||
|
def Activated(self):
|
||||||
|
from asm3.assembly import AsmConstraint
|
||||||
|
AsmConstraint.make(self.tp._id)
|
||||||
|
|
||||||
|
def IsActive(self):
|
||||||
|
return FreeCADGui.ActiveDocument and self.tp._active
|
||||||
|
|
||||||
|
class SelectionObserver:
|
||||||
|
def __init__(self):
|
||||||
|
self._attached = False
|
||||||
|
|
||||||
|
def onChanged(self):
|
||||||
|
from asm3.assembly import AsmConstraint
|
||||||
|
for cls in Constraint._cmdTypes:
|
||||||
|
try:
|
||||||
|
AsmConstraint.getSelection()
|
||||||
|
except Exception as e:
|
||||||
|
logger.trace('selection "{}" exception: {}'.format(
|
||||||
|
cls.getName(),e.message),frame=1)
|
||||||
|
cls._active = False
|
||||||
|
else:
|
||||||
|
cls._active = True
|
||||||
|
|
||||||
|
def addSelection(self,*_args):
|
||||||
|
self.onChanged()
|
||||||
|
|
||||||
|
def removeSelection(self,*_args):
|
||||||
|
self.onChanged()
|
||||||
|
|
||||||
|
def setSelection(self,*_args):
|
||||||
|
self.onChanged()
|
||||||
|
|
||||||
|
def clearSelection(self,*_args):
|
||||||
|
logger.trace('selection cleared')
|
||||||
|
for cls in Constraint._cmdTypes:
|
||||||
|
cls._active = False
|
||||||
|
|
||||||
|
def attach(self):
|
||||||
|
if not self._attached:
|
||||||
|
FreeCADGui.Selection.addObserver(self)
|
||||||
|
self._attached = True
|
||||||
|
self.onChanged()
|
||||||
|
|
||||||
|
def detach(self):
|
||||||
|
if self._attached:
|
||||||
|
FreeCADGui.Selection.removeObserver(self)
|
||||||
|
self._attached = False
|
||||||
|
self.clearSelection('')
|
||||||
|
|
||||||
|
Observer = SelectionObserver()
|
||||||
|
|
||||||
class Constraint(ProxyType):
|
class Constraint(ProxyType):
|
||||||
'constraint meta class'
|
'constraint meta class'
|
||||||
|
|
||||||
_typeID = '_ConstraintType'
|
_typeID = '_ConstraintType'
|
||||||
_typeEnum = 'ConstraintType'
|
_typeEnum = 'ConstraintType'
|
||||||
|
|
||||||
_disabled = 'Disabled'
|
_disabled = 'Disabled'
|
||||||
|
|
||||||
|
CommandList = []
|
||||||
|
_cmdTypes = []
|
||||||
|
|
||||||
|
def register(cls):
|
||||||
|
super(Constraint,cls).register()
|
||||||
|
if cls._menuItem:
|
||||||
|
name = 'asm3Add'+cls.getName()
|
||||||
|
mcs = cls.__class__
|
||||||
|
mcs.CommandList.append(name)
|
||||||
|
mcs._cmdTypes.append(cls)
|
||||||
|
FreeCADGui.addCommand(name,ConstraintCommand(cls))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def attach(mcs,obj,checkType=True):
|
def attach(mcs,obj,checkType=True):
|
||||||
if checkType:
|
if checkType:
|
||||||
|
@ -220,8 +289,12 @@ class Base(with_metaclass(Constraint,object)):
|
||||||
_props = []
|
_props = []
|
||||||
_iconName = 'Assembly_ConstraintGeneral.svg'
|
_iconName = 'Assembly_ConstraintGeneral.svg'
|
||||||
|
|
||||||
|
_menuText = 'Add a "{}" constraint'
|
||||||
|
_active = False
|
||||||
|
_menuItem = False
|
||||||
|
|
||||||
def __init__(self,_obj):
|
def __init__(self,_obj):
|
||||||
self._supported = True
|
pass
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def getPropertyInfoList(cls):
|
def getPropertyInfoList(cls):
|
||||||
|
@ -295,10 +368,29 @@ class Base(with_metaclass(Constraint,object)):
|
||||||
else:
|
else:
|
||||||
logger.warn('{} no constraint func'.format(cstrName(obj)))
|
logger.warn('{} no constraint func'.format(cstrName(obj)))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def getMenuText(cls):
|
||||||
|
return cls._menuText.format(cls.getName())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def getToolTip(cls):
|
||||||
|
tooltip = getattr(cls,'_tooltip',None)
|
||||||
|
if not tooltip:
|
||||||
|
return cls.getMenuText()
|
||||||
|
return tooltip.format(cls.getName())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def GetResources(cls):
|
||||||
|
return {'Pixmap':utils.addIconToFCAD(cls._iconName,_iconPath),
|
||||||
|
'MenuText':cls.getMenuText(),
|
||||||
|
'ToolTip':cls.getToolTip()}
|
||||||
|
|
||||||
|
|
||||||
class Locked(Base):
|
class Locked(Base):
|
||||||
_id = 0
|
_id = 0
|
||||||
_iconName = 'Assembly_ConstraintLock.svg'
|
_iconName = 'Assembly_ConstraintLock.svg'
|
||||||
|
_menuItem = True
|
||||||
|
_tooltip = 'Add a "{}" constraint to fix part(s)'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def prepare(cls,obj,solver):
|
def prepare(cls,obj,solver):
|
||||||
|
@ -309,6 +401,7 @@ class Locked(Base):
|
||||||
def check(cls,_group):
|
def check(cls,_group):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BaseMulti(Base):
|
class BaseMulti(Base):
|
||||||
_id = -1
|
_id = -1
|
||||||
_entityDef = (_wa,)
|
_entityDef = (_wa,)
|
||||||
|
@ -414,23 +507,36 @@ class PlaneCoincident(BaseCascade):
|
||||||
_id = 35
|
_id = 35
|
||||||
_iconName = 'Assembly_ConstraintCoincidence.svg'
|
_iconName = 'Assembly_ConstraintCoincidence.svg'
|
||||||
_props = ['Cascade','Offset']
|
_props = ['Cascade','Offset']
|
||||||
|
_menuItem = True
|
||||||
|
_tooltip = \
|
||||||
|
'Add a "{}" constraint to conincide planes of two or more parts.\n'\
|
||||||
|
'The planes are coincided at their centers with an optional distance.'
|
||||||
|
|
||||||
|
|
||||||
class PlaneAlignment(BaseCascade):
|
class PlaneAlignment(BaseCascade):
|
||||||
_id = 37
|
_id = 37
|
||||||
_iconName = 'Assembly_ConstraintAlignment.svg'
|
_iconName = 'Assembly_ConstraintAlignment.svg'
|
||||||
_props = ['Cascade','Offset']
|
_props = ['Cascade','Offset']
|
||||||
|
_menuItem = True
|
||||||
|
_tooltip = 'Add a "{}" constraint to rotate planes of two or more parts\n'\
|
||||||
|
'into the same orientation'
|
||||||
|
|
||||||
|
|
||||||
class AxialAlignment(BaseMulti):
|
class AxialAlignment(BaseMulti):
|
||||||
_id = 36
|
_id = 36
|
||||||
_iconName = 'Assembly_ConstraintAxial.svg'
|
_iconName = 'Assembly_ConstraintAxial.svg'
|
||||||
|
_menuItem = True
|
||||||
|
_tooltip = 'Add a "{}" constraint to align planes of two or more parts.\n'\
|
||||||
|
'The planes are aligned at the direction of their surface normal axis.'
|
||||||
|
|
||||||
|
|
||||||
class SameOrientation(BaseMulti):
|
class SameOrientation(BaseMulti):
|
||||||
_id = 2
|
_id = 2
|
||||||
_entityDef = (_n,)
|
_entityDef = (_n,)
|
||||||
_iconName = 'Assembly_ConstraintOrientation.svg'
|
_iconName = 'Assembly_ConstraintOrientation.svg'
|
||||||
|
_menuItem = True
|
||||||
|
_tooltip = 'Add a "{}" constraint to align planes of two or more parts.\n'\
|
||||||
|
'The planes are aligned to have the same orientation (i.e. rotation)'
|
||||||
|
|
||||||
|
|
||||||
class Angle(Base):
|
class Angle(Base):
|
||||||
|
@ -439,6 +545,9 @@ class Angle(Base):
|
||||||
_workplane = True
|
_workplane = True
|
||||||
_props = ["Angle","Supplement"]
|
_props = ["Angle","Supplement"]
|
||||||
_iconName = 'Assembly_ConstraintAngle.svg'
|
_iconName = 'Assembly_ConstraintAngle.svg'
|
||||||
|
_menuItem = True
|
||||||
|
_tooltip = 'Add a "{}" constraint to set the angle of planes or linear\n'\
|
||||||
|
'edges of two parts.'
|
||||||
|
|
||||||
|
|
||||||
class Perpendicular(Base):
|
class Perpendicular(Base):
|
||||||
|
@ -446,19 +555,28 @@ class Perpendicular(Base):
|
||||||
_entityDef = (_ln,_ln)
|
_entityDef = (_ln,_ln)
|
||||||
_workplane = True
|
_workplane = True
|
||||||
_iconName = 'Assembly_ConstraintPerpendicular.svg'
|
_iconName = 'Assembly_ConstraintPerpendicular.svg'
|
||||||
|
_menuItem = True
|
||||||
|
_tooltip = 'Add a "{}" constraint to make planes or linear edges of two\n'\
|
||||||
|
'parts perpendicular.'
|
||||||
|
|
||||||
|
|
||||||
class Parallel(Base):
|
class Parallel(Base):
|
||||||
_id = 29
|
_id = -1
|
||||||
_entityDef = (_ln,_ln)
|
_entityDef = (_ln,_ln)
|
||||||
_workplane = True
|
_workplane = True
|
||||||
_iconName = 'Assembly_ConstraintParallel.svg'
|
_iconName = 'Assembly_ConstraintParallel.svg'
|
||||||
|
_menuItem = True
|
||||||
|
_tooltip = 'Add a "{}" constraint to make planes or linear edges of two\n'\
|
||||||
|
'parts parallel.'
|
||||||
|
|
||||||
|
|
||||||
class MultiParallel(BaseMulti):
|
class MultiParallel(BaseMulti):
|
||||||
_id = 291
|
_id = 291
|
||||||
_entityDef = (_ln,)
|
_entityDef = (_ln,)
|
||||||
_iconName = 'Assembly_ConstraintMultiParallel.svg'
|
_iconName = 'Assembly_ConstraintMultiParallel.svg'
|
||||||
|
_menuItem = True
|
||||||
|
_tooltip = 'Add a "{}" constraint to make planes or linear edges of two\n'\
|
||||||
|
'or more parts parallel.'
|
||||||
|
|
||||||
|
|
||||||
class PointsCoincident(Base):
|
class PointsCoincident(Base):
|
||||||
|
|
67
gui.py
Normal file
67
gui.py
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
from future.utils import with_metaclass
|
||||||
|
import FreeCAD, FreeCADGui
|
||||||
|
from asm3.utils import logger,objName,addIconToFCAD
|
||||||
|
from asm3.assembly import Assembly,AsmConstraint
|
||||||
|
from asm3.proxy import ProxyType
|
||||||
|
|
||||||
|
class AsmCmdType(ProxyType):
|
||||||
|
def register(cls):
|
||||||
|
super(AsmCmdType,cls).register()
|
||||||
|
if cls._id >= 0:
|
||||||
|
FreeCADGui.addCommand(cls.getName(),cls())
|
||||||
|
|
||||||
|
class AsmCmdBase(with_metaclass(AsmCmdType,object)):
|
||||||
|
_id = -1
|
||||||
|
_active = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def getName(cls):
|
||||||
|
return 'asm3'+cls.__name__[3:]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def GetResources(cls):
|
||||||
|
return {
|
||||||
|
'Pixmap':addIconToFCAD(cls._iconName),
|
||||||
|
'MenuText':cls.getMenuText(),
|
||||||
|
'ToolTip':cls.getToolTip()
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def getMenuText(cls):
|
||||||
|
return cls._menuText
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def getToolTip(cls):
|
||||||
|
return getattr(cls,'_tooltip',cls.getMenuText())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def IsActive(cls):
|
||||||
|
if FreeCAD.ActiveDocument and cls._active:
|
||||||
|
return True
|
||||||
|
|
||||||
|
class AsmCmdNew(AsmCmdBase):
|
||||||
|
_id = 0
|
||||||
|
_menuText = 'Create a new assembly'
|
||||||
|
_iconName = 'Assembly_New_Assembly.svg'
|
||||||
|
|
||||||
|
def Activated(self):
|
||||||
|
Assembly.make()
|
||||||
|
|
||||||
|
class AsmCmdSolve(AsmCmdBase):
|
||||||
|
_id = 1
|
||||||
|
_menuText = 'Solve the constraints of assembly(s)'
|
||||||
|
_iconName = 'AssemblyWorkbench.svg'
|
||||||
|
|
||||||
|
def Activated(self):
|
||||||
|
import asm3.solver as solver
|
||||||
|
solver.solve()
|
||||||
|
|
||||||
|
|
||||||
|
class AsmCmdMove(AsmCmdBase):
|
||||||
|
_id = 2
|
||||||
|
_menuText = 'Move assembly'
|
||||||
|
_iconName = 'Assembly_Move.svg'
|
||||||
|
|
||||||
|
def Activated(self):
|
||||||
|
pass
|
||||||
|
|
27
proxy.py
27
proxy.py
|
@ -9,6 +9,8 @@ def propGetValue(self,obj):
|
||||||
return getattr(getattr(obj,self.Name),'Value')
|
return getattr(getattr(obj,self.Name),'Value')
|
||||||
|
|
||||||
class PropertyInfo(object):
|
class PropertyInfo(object):
|
||||||
|
'For holding information to create dynamic properties'
|
||||||
|
|
||||||
def __init__(self,host,name,tp,doc='', enum=None,
|
def __init__(self,host,name,tp,doc='', enum=None,
|
||||||
getter=propGet,group='Base',internal=False,duplicate=False):
|
getter=propGet,group='Base',internal=False,duplicate=False):
|
||||||
self.Name = name
|
self.Name = name
|
||||||
|
@ -21,9 +23,15 @@ class PropertyInfo(object):
|
||||||
self.Key = host.addPropertyInfo(self,duplicate)
|
self.Key = host.addPropertyInfo(self,duplicate)
|
||||||
|
|
||||||
class ProxyType(type):
|
class ProxyType(type):
|
||||||
|
'''
|
||||||
|
Meta class for managing other "proxy" like classes whose instances can be
|
||||||
|
dynamically attached to or detached from FCAD FeaturePython Proxy objects.
|
||||||
|
In other word, it is meant for managing proxies of Proxies
|
||||||
|
'''
|
||||||
|
|
||||||
_typeID = '_ProxyType'
|
_typeID = '_ProxyType'
|
||||||
_typeEnum = 'ProxyType'
|
_typeEnum = 'ProxyType'
|
||||||
_typeGroup = 'Base'
|
_propGroup = 'Base'
|
||||||
_proxyName = '_proxy'
|
_proxyName = '_proxy'
|
||||||
_registry = {}
|
_registry = {}
|
||||||
|
|
||||||
|
@ -48,7 +56,7 @@ class ProxyType(type):
|
||||||
for tp in info.Types:
|
for tp in info.Types:
|
||||||
tp._idx = -1
|
tp._idx = -1
|
||||||
mcs.getInfo().Types.append(tp)
|
mcs.getInfo().Types.append(tp)
|
||||||
mcs.register(tp)
|
tp.register()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def getType(mcs,tp):
|
def getType(mcs,tp):
|
||||||
|
@ -99,8 +107,6 @@ class ProxyType(type):
|
||||||
obj.addProperty(prop.Type,prop.Name,prop.Group,prop.Doc)
|
obj.addProperty(prop.Type,prop.Name,prop.Group,prop.Doc)
|
||||||
if prop.Enum:
|
if prop.Enum:
|
||||||
setattr(obj,prop.Name,prop.Enum)
|
setattr(obj,prop.Name,prop.Enum)
|
||||||
else:
|
|
||||||
obj.setPropertyStatus(prop.Name,'-Hidden')
|
|
||||||
|
|
||||||
setattr(obj.Proxy,mcs._proxyName,cls(obj))
|
setattr(obj.Proxy,mcs._proxyName,cls(obj))
|
||||||
obj.ViewObject.signalChangeIcon()
|
obj.ViewObject.signalChangeIcon()
|
||||||
|
@ -114,7 +120,6 @@ class ProxyType(type):
|
||||||
proxy.__class__.__name__))
|
proxy.__class__.__name__))
|
||||||
for key in proxy.getPropertyInfoList():
|
for key in proxy.getPropertyInfoList():
|
||||||
prop = mcs.getPropertyInfo(key)
|
prop = mcs.getPropertyInfo(key)
|
||||||
# obj.setPropertyStatus(prop.Name,'Hidden')
|
|
||||||
obj.removeProperty(prop.Name)
|
obj.removeProperty(prop.Name)
|
||||||
callback = getattr(proxy,'onDetach',None)
|
callback = getattr(proxy,'onDetach',None)
|
||||||
if callback:
|
if callback:
|
||||||
|
@ -143,14 +148,14 @@ class ProxyType(type):
|
||||||
if checkType:
|
if checkType:
|
||||||
if mcs._typeID not in obj.PropertiesList:
|
if mcs._typeID not in obj.PropertiesList:
|
||||||
obj.addProperty("App::PropertyInteger",
|
obj.addProperty("App::PropertyInteger",
|
||||||
mcs._typeID,mcs._typeGroup,'',0,False,True)
|
mcs._typeID,mcs._propGroup,'',0,False,True)
|
||||||
mcs.setDefaultTypeID(obj)
|
mcs.setDefaultTypeID(obj)
|
||||||
|
|
||||||
if mcs._typeEnum not in obj.PropertiesList:
|
if mcs._typeEnum not in obj.PropertiesList:
|
||||||
logger.debug('type enum {}, {}'.format(mcs._typeEnum,
|
logger.debug('type enum {}, {}'.format(mcs._typeEnum,
|
||||||
mcs._typeGroup))
|
mcs._propGroup))
|
||||||
obj.addProperty("App::PropertyEnumeration",
|
obj.addProperty("App::PropertyEnumeration",
|
||||||
mcs._typeEnum,mcs._typeGroup,'',2)
|
mcs._typeEnum,mcs._propGroup,'',2)
|
||||||
mcs.setTypeName(obj,info.TypeNames)
|
mcs.setTypeName(obj,info.TypeNames)
|
||||||
|
|
||||||
idx = 0
|
idx = 0
|
||||||
|
@ -179,10 +184,9 @@ class ProxyType(type):
|
||||||
cls._idx = -1
|
cls._idx = -1
|
||||||
mcs = cls.__class__
|
mcs = cls.__class__
|
||||||
mcs.getInfo().Types.append(cls)
|
mcs.getInfo().Types.append(cls)
|
||||||
mcs.register(cls)
|
cls.register()
|
||||||
|
|
||||||
@classmethod
|
def register(cls):
|
||||||
def register(mcs,cls):
|
|
||||||
'''
|
'''
|
||||||
Register a class to this meta class
|
Register a class to this meta class
|
||||||
|
|
||||||
|
@ -193,6 +197,7 @@ class ProxyType(type):
|
||||||
'''
|
'''
|
||||||
if cls._id < 0:
|
if cls._id < 0:
|
||||||
return
|
return
|
||||||
|
mcs = cls.__class__
|
||||||
info = mcs.getInfo()
|
info = mcs.getInfo()
|
||||||
if cls._id in info.TypeMap:
|
if cls._id in info.TypeMap:
|
||||||
raise RuntimeError('Duplicate {} type id {}'.format(
|
raise RuntimeError('Duplicate {} type id {}'.format(
|
||||||
|
|
31
solver.py
31
solver.py
|
@ -22,15 +22,10 @@ class Solver(object):
|
||||||
self.system = System.getSystem(assembly)
|
self.system = System.getSystem(assembly)
|
||||||
cstrs = assembly.Proxy.getConstraints()
|
cstrs = assembly.Proxy.getConstraints()
|
||||||
if not cstrs:
|
if not cstrs:
|
||||||
self.system.log('no constraint found in assembly '
|
logger.warn('no constraint found in assembly '
|
||||||
'{}'.format(objName(assembly)))
|
'{}'.format(objName(assembly)))
|
||||||
return
|
return
|
||||||
|
|
||||||
parts = assembly.Proxy.getPartGroup().Group
|
|
||||||
if len(parts)<=1:
|
|
||||||
self.system.log('not enough parts in {}'.format(objName(assembly)))
|
|
||||||
return
|
|
||||||
|
|
||||||
self._fixedGroup = 2
|
self._fixedGroup = 2
|
||||||
self.group = 1 # the solving group
|
self.group = 1 # the solving group
|
||||||
self._partMap = {}
|
self._partMap = {}
|
||||||
|
@ -41,16 +36,24 @@ class Solver(object):
|
||||||
|
|
||||||
self.system.GroupHandle = self._fixedGroup
|
self.system.GroupHandle = self._fixedGroup
|
||||||
|
|
||||||
|
firstPart = None
|
||||||
|
firstPartName = None
|
||||||
for cstr in cstrs:
|
for cstr in cstrs:
|
||||||
if Constraint.isLocked(cstr):
|
if Constraint.isLocked(cstr):
|
||||||
Constraint.prepare(cstr,self)
|
Constraint.prepare(cstr,self)
|
||||||
elif not Constraint.isDisabled(cstr) and \
|
elif not Constraint.isDisabled(cstr) and \
|
||||||
System.isConstraintSupported(
|
System.isConstraintSupported(
|
||||||
assembly,Constraint.getTypeName(cstr)):
|
assembly,Constraint.getTypeName(cstr)):
|
||||||
|
if not firstPart:
|
||||||
|
elements = cstr.Proxy.getElements()
|
||||||
|
if elements:
|
||||||
|
info = elements[0].Proxy.getInfo()
|
||||||
|
firstPart = info.Part
|
||||||
|
firstPartName = info.PartName
|
||||||
self._cstrs.append(cstr)
|
self._cstrs.append(cstr)
|
||||||
if not self._fixedParts:
|
if not self._fixedParts:
|
||||||
self.system.log('lock first part {}'.format(objName(parts[0])))
|
self.system.log('lock first part {}'.format(firstPartName))
|
||||||
self._fixedParts.add(parts[0])
|
self._fixedParts.add(firstPart)
|
||||||
|
|
||||||
for cstr in self._cstrs:
|
for cstr in self._cstrs:
|
||||||
self.system.log('preparing {}'.format(cstrName(cstr)))
|
self.system.log('preparing {}'.format(cstrName(cstr)))
|
||||||
|
@ -162,9 +165,17 @@ class Solver(object):
|
||||||
self._partMap[info.Part] = partInfo
|
self._partMap[info.Part] = partInfo
|
||||||
return partInfo
|
return partInfo
|
||||||
|
|
||||||
def solve(objs=None,recursive=True,reportFailed=True,recompute=True):
|
def solve(objs=None,recursive=None,reportFailed=True,recompute=True):
|
||||||
if not objs:
|
if not objs:
|
||||||
objs = FreeCAD.ActiveDocument.Objects
|
sels = FreeCADGui.Selection.getSelectionEx('',False)
|
||||||
|
if len(sels):
|
||||||
|
objs = asm.Assembly.find()
|
||||||
|
if not objs:
|
||||||
|
raise RuntimeError('No assembly found in selection')
|
||||||
|
else:
|
||||||
|
objs = FreeCAD.ActiveDocument.Objects
|
||||||
|
if recursive is None:
|
||||||
|
recursive = True
|
||||||
elif not isinstance(objs,(list,tuple)):
|
elif not isinstance(objs,(list,tuple)):
|
||||||
objs = [objs]
|
objs = [objs]
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,12 @@ class _AlgoType(ProxyType):
|
||||||
|
|
||||||
_typeID = '_AlgorithmType'
|
_typeID = '_AlgorithmType'
|
||||||
_typeEnum = 'AlgorithmType'
|
_typeEnum = 'AlgorithmType'
|
||||||
_typeGroup = 'SolverAlgorithm'
|
_propGroup = 'SolverAlgorithm'
|
||||||
_proxyName = '_algo'
|
_proxyName = '_algo'
|
||||||
|
|
||||||
def _makeProp(name,doc='',tp='App::PropertyFloat',group=None):
|
def _makeProp(name,doc='',tp='App::PropertyFloat',group=None):
|
||||||
if not group:
|
if not group:
|
||||||
group = _AlgoType._typeGroup
|
group = _AlgoType._propGroup
|
||||||
info = PropertyInfo(_AlgoType,name,tp,doc,duplicate=True,group=group)
|
info = PropertyInfo(_AlgoType,name,tp,doc,duplicate=True,group=group)
|
||||||
return info.Key
|
return info.Key
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ class System(ProxyType):
|
||||||
|
|
||||||
_typeID = '_SolverType'
|
_typeID = '_SolverType'
|
||||||
_typeEnum = 'SolverType'
|
_typeEnum = 'SolverType'
|
||||||
_typeGroup = 'Solver'
|
_propGroup = 'Solver'
|
||||||
_iconName = 'Assembly_Assembly_Tree.svg'
|
_iconName = 'Assembly_Assembly_Tree.svg'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
21
utils.py
21
utils.py
|
@ -5,6 +5,11 @@ Most of the functions are borrowed directly from assembly2lib.py or lib3D.py in
|
||||||
assembly2
|
assembly2
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
import FreeCAD, FreeCADGui, Part
|
||||||
|
import numpy as np
|
||||||
|
from asm3.FCADLogger import FCADLogger
|
||||||
|
logger = FCADLogger('asm3')
|
||||||
|
|
||||||
import sys, os
|
import sys, os
|
||||||
modulePath = os.path.dirname(os.path.realpath(__file__))
|
modulePath = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
|
@ -29,12 +34,16 @@ def getIcon(obj,disabled=False,path=None):
|
||||||
obj._iconDisabled = QIcon(pixmap)
|
obj._iconDisabled = QIcon(pixmap)
|
||||||
return obj._iconDisabled
|
return obj._iconDisabled
|
||||||
|
|
||||||
|
def addIconToFCAD(iconFile,path=None):
|
||||||
import FreeCAD, FreeCADGui, Part
|
iconName = ':asm3/icons/' + iconFile
|
||||||
import numpy as np
|
if not path:
|
||||||
|
path = iconPath
|
||||||
import asm3.FCADLogger
|
try:
|
||||||
logger = asm3.FCADLogger.FCADLogger('assembly3')
|
path = os.path.join(path,iconFile)
|
||||||
|
FreeCADGui.addIcon(iconName,path)
|
||||||
|
except AssertionError:
|
||||||
|
pass
|
||||||
|
return iconName
|
||||||
|
|
||||||
def objName(obj):
|
def objName(obj):
|
||||||
if obj.Label == obj.Name:
|
if obj.Label == obj.Name:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user