Merge branch 'master' into feature/misc-improvements

This commit is contained in:
sliptonic
2019-08-16 13:38:10 -05:00
committed by GitHub
61 changed files with 13731 additions and 2401 deletions
+1 -2
View File
@@ -379,7 +379,7 @@ protected:
enum eWinGestureTuneState{
ewgtsDisabled, //suppress tuning/re-tuning after errors
ewgtsNeedTuning, //gestures are to be retuned upon next event
ewgtsNeedTuning, //gestures are to be re-tuned upon next event
ewgtsTuned
};
eWinGestureTuneState winGestureTuneState;//See ViewerEventFilter::eventFilter function for explanation
@@ -458,4 +458,3 @@ private:
} // namespace Gui
#endif // GUI_VIEW3DINVENTORVIEWER_H
+22
View File
@@ -182,6 +182,7 @@ void View3DInventorPy::init_type()
add_varargs_method("getActiveObject", &View3DInventorPy::getActiveObject, "getActiveObject(name)\nreturns the active object for the given type");
add_varargs_method("getViewProvidersOfType", &View3DInventorPy::getViewProvidersOfType, "getViewProvidersOfType(name)\nreturns a list of view providers for the given type");
add_varargs_method("redraw", &View3DInventorPy::redraw, "redraw(): renders the scene on screen (useful for animations)");
add_varargs_method("setName",&View3DInventorPy::setName,"setName(str): sets a name to this viewer\nThe name sets the widget's windowTitle and appears on the viewer tab");
}
@@ -2451,3 +2452,24 @@ Py::Object View3DInventorPy::redraw(const Py::Tuple& args)
_view->getViewer()->redraw();
return Py::None();
}
Py::Object View3DInventorPy::setName(const Py::Tuple& args)
{
char* buffer;
if (!PyArg_ParseTuple(args.ptr(), "s", &buffer))
throw Py::Exception();
try {
_view->setWindowTitle(QString::fromUtf8(buffer));
return Py::None();
}
catch (const Base::Exception& e) {
throw Py::RuntimeError(e.what());
}
catch (const std::exception& e) {
throw Py::RuntimeError(e.what());
}
catch(...) {
throw Py::RuntimeError("Unknown C++ exception");
}
}
+1
View File
@@ -129,6 +129,7 @@ public:
Py::Object getActiveObject(const Py::Tuple&);
Py::Object getViewProvidersOfType(const Py::Tuple&);
Py::Object redraw(const Py::Tuple&);
Py::Object setName(const Py::Tuple&);
private:
static void eventCallback(void * ud, SoEventCallback * n);
@@ -2,11 +2,12 @@
<qresource>
<file>icons/3D_Printing_Tools_workbench_icon.svg</file>
<file>icons/A2plus_workbench_icon.svg</file>
<file>icons/AirPlaneDesign_workbench-icon.svg</file>
<file>icons/AirPlaneDesign_workbench_icon.svg</file>
<file>icons/ArchTextures_workbench_icon.svg</file>
<file>icons/BIMBots_workbench_icon.svg</file>
<file>icons/BIM_workbench_icon.svg</file>
<file>icons/BOLTSFC_workbench_icon.svg</file>
<file>icons/CADExchanger_workbench_icon.svg</file>
<file>icons/cadquery_module_workbench_icon.svg</file>
<file>icons/CfdOF_workbench_icon.svg</file>
<file>icons/CurvedShapes_workbench_icon.svg</file>
@@ -24,19 +25,21 @@
<file>icons/InventorLoader_workbench_icon.svg</file>
<file>icons/kicadStepUpMod_workbench_icon.svg</file>
<file>icons/lattice2_workbench_icon.svg</file>
<file>icons/LCInterlocking_workbench_icon.svg</file>
<file>icons/LCInterlocking_workbench_icon.svg</file>
<file>icons/Lithophane_workbench_icon.svg</file>
<file>icons/Manipulator_workbench_icon.svg</file>
<file>icons/MOOC_workbench_icon.svg</file>
<file>icons/Part-o-magic_workbench_icon.svg</file>
<file>icons/Plot_workbench_icon.svg</file>
<file>icons/pyrate_workbench_icon.svg</file>
<file>icons/Reinforcement_workbench_icon.svg</file>
<file>icons/Reporting_workbench_icon.svg</file>
<file>icons/Render_workbench_icon.svg</file>
<file>icons/sheetmetal_workbench_icon.svg</file>
<file>icons/slic3r-tools_workbench_icon.svg</file>
<file>icons/Ship_workbench_icon.svg</file>
<file>icons/timber_workbench_icon.svg</file>
<file>icons/ThreadProfile_workbench_icon.svg</file>
<file>icons/yaml-workspace_workbench_icon.svg</file>
<file>translations/AddonManager_af.qm</file>
<file>translations/AddonManager_ar.qm</file>

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 53 KiB

@@ -0,0 +1,169 @@
<?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="svg2985" version="1.1" inkscape:version="0.48.5 r10040" sodipodi:docname="Arch_Rebar.svg">
<defs id="defs2987">
<linearGradient id="linearGradient4025">
<stop id="stop4027" offset="0" style="stop-color:#c4a000;stop-opacity:1"/>
<stop id="stop4029" offset="1" style="stop-color:#fce94f;stop-opacity:1"/>
</linearGradient>
<linearGradient id="linearGradient4017">
<stop id="stop4019" offset="0" style="stop-color:#c4a000;stop-opacity:1"/>
<stop id="stop4021" offset="1" style="stop-color:#fce94f;stop-opacity:1"/>
</linearGradient>
<linearGradient inkscape:collect="always" id="linearGradient4007">
<stop style="stop-color:#c4a000;stop-opacity:1" offset="0" id="stop4009"/>
<stop style="stop-color:#fce94f;stop-opacity:1" offset="1" id="stop4011"/>
</linearGradient>
<linearGradient inkscape:collect="always" id="linearGradient3999">
<stop style="stop-color:#c4a000;stop-opacity:1" offset="0" id="stop4001"/>
<stop style="stop-color:#fce94f;stop-opacity:1" offset="1" id="stop4003"/>
</linearGradient>
<linearGradient inkscape:collect="always" id="linearGradient3991">
<stop style="stop-color:#c4a000;stop-opacity:1" offset="0" id="stop3993"/>
<stop style="stop-color:#fce94f;stop-opacity:1" offset="1" id="stop3995"/>
</linearGradient>
<linearGradient id="linearGradient3217">
<stop id="stop3219" offset="0" style="stop-color:#c4a000;stop-opacity:1"/>
<stop id="stop3221" offset="1" style="stop-color:#fce94f;stop-opacity:1"/>
</linearGradient>
<linearGradient id="linearGradient3883">
<stop style="stop-color:#ffb400;stop-opacity:1;" offset="0" id="stop3885"/>
<stop style="stop-color:#ffe900;stop-opacity:1;" offset="1" id="stop3887"/>
</linearGradient>
<linearGradient id="linearGradient3793">
<stop style="stop-color:#000f8a;stop-opacity:1;" offset="0" id="stop3795"/>
<stop style="stop-color:#0066ff;stop-opacity:1;" offset="1" id="stop3797"/>
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3793-2" id="linearGradient3799-8" x1="12.037806" y1="54.001419" x2="52.882648" y2="9.274148" gradientUnits="userSpaceOnUse"/>
<linearGradient id="linearGradient3793-2">
<stop style="stop-color:#000f8a;stop-opacity:1;" offset="0" id="stop3795-6"/>
<stop style="stop-color:#0066ff;stop-opacity:1;" offset="1" id="stop3797-0"/>
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3883" id="linearGradient3889" x1="3" y1="31.671875" x2="59.25" y2="31.671875" gradientUnits="userSpaceOnUse" gradientTransform="translate(84.181818,-14.181818)"/>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3883-6" id="linearGradient3889-4" x1="3" y1="31.671875" x2="59.25" y2="31.671875" gradientUnits="userSpaceOnUse" gradientTransform="translate(-1.2727273,-0.18181818)"/>
<linearGradient id="linearGradient3883-6">
<stop style="stop-color:#ffb400;stop-opacity:1;" offset="0" id="stop3885-4"/>
<stop style="stop-color:#ffe900;stop-opacity:1;" offset="1" id="stop3887-5"/>
</linearGradient>
<linearGradient id="linearGradient3883-63">
<stop style="stop-color:#ffb400;stop-opacity:1;" offset="0" id="stop3885-6"/>
<stop style="stop-color:#ffe900;stop-opacity:1;" offset="1" id="stop3887-51"/>
</linearGradient>
<linearGradient y2="31.671875" x2="59.25" y1="31.671875" x1="3" gradientTransform="translate(-3,-1.9375)" gradientUnits="userSpaceOnUse" id="linearGradient3099" xlink:href="#linearGradient3883-63" inkscape:collect="always"/>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3883-1" id="linearGradient3889-9" x1="-45.909092" y1="52.217331" x2="-45.659092" y2="37.671875" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.78523034,-0.61920378,0.61920378,0.78523034,40.449388,-50.080588)"/>
<linearGradient id="linearGradient3883-1">
<stop style="stop-color:#a27200;stop-opacity:1;" offset="0" id="stop3885-63"/>
<stop style="stop-color:#ffe900;stop-opacity:1;" offset="1" id="stop3887-3"/>
</linearGradient>
<linearGradient y2="31.671875" x2="59.25" y1="31.671875" x1="3" gradientTransform="translate(-3,-1.9375)" gradientUnits="userSpaceOnUse" id="linearGradient3950" xlink:href="#linearGradient3883-1" inkscape:collect="always"/>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3883-1-0" id="linearGradient3889-9-4" x1="-45.909092" y1="52.217331" x2="-45.659092" y2="37.671875" gradientUnits="userSpaceOnUse" gradientTransform="translate(62.772175,-14.278383)"/>
<linearGradient id="linearGradient3883-1-0">
<stop style="stop-color:#a27200;stop-opacity:1;" offset="0" id="stop3885-63-6"/>
<stop style="stop-color:#ffe900;stop-opacity:1;" offset="1" id="stop3887-3-5"/>
</linearGradient>
<linearGradient y2="37.671875" x2="-45.659092" y1="52.217331" x1="-45.909092" gradientTransform="translate(72.070588,5.7891214)" gradientUnits="userSpaceOnUse" id="linearGradient3983" xlink:href="#linearGradient3883-1-0" inkscape:collect="always"/>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3883-1-5" id="linearGradient3889-9-5" x1="-45.909092" y1="52.217331" x2="-45.659092" y2="37.671875" gradientUnits="userSpaceOnUse" gradientTransform="translate(62.772175,-14.278383)"/>
<linearGradient id="linearGradient3883-1-5">
<stop style="stop-color:#a27200;stop-opacity:1;" offset="0" id="stop3885-63-3"/>
<stop style="stop-color:#ffe900;stop-opacity:1;" offset="1" id="stop3887-3-2"/>
</linearGradient>
<linearGradient y2="37.671875" x2="-45.659092" y1="52.217331" x1="-45.909092" gradientTransform="matrix(0.78523034,-0.61920378,0.61920378,0.78523034,80.903931,-30.262405)" gradientUnits="userSpaceOnUse" id="linearGradient3983-2" xlink:href="#linearGradient3883-1-5" inkscape:collect="always"/>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3883-1-0" id="linearGradient4060" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.78523034,-0.61920378,0.61920378,0.78523034,60.176658,-40.080587)" x1="-45.909092" y1="52.217331" x2="-45.659092" y2="37.671875"/>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3883-1-6" id="linearGradient3889-9-2" x1="-45.909092" y1="52.217331" x2="-45.659092" y2="37.671875" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.78523034,-0.61920378,0.61920378,0.78523034,40.449388,-50.080588)"/>
<linearGradient id="linearGradient3883-1-6">
<stop style="stop-color:#a27200;stop-opacity:1;" offset="0" id="stop3885-63-4"/>
<stop style="stop-color:#ffe900;stop-opacity:1;" offset="1" id="stop3887-3-7"/>
</linearGradient>
<linearGradient y2="37.671875" x2="-45.659092" y1="52.217331" x1="-45.909092" gradientTransform="matrix(0.78523034,-0.61920378,0.61920378,0.78523034,40.449388,-50.080588)" gradientUnits="userSpaceOnUse" id="linearGradient4058" xlink:href="#linearGradient3883-1-6" inkscape:collect="always"/>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3217" id="linearGradient4081" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.76307355,-0.59933979,0.60173176,0.76004024,38.095031,-48.22656)" x1="-47.090748" y1="48.182411" x2="-47.046482" y2="41.506298"/>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient4017" id="linearGradient4083" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.75961823,-0.62787354,0.59900702,0.7962247,56.938596,-42.236467)" x1="-46.284084" y1="48.523933" x2="-45.804276" y2="40.519474"/>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient4025" id="linearGradient4085" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.73381378,-0.61846048,0.57865858,0.78428772,76.44662,-31.907951)" x1="-63.788338" y1="48.997299" x2="-62.86702" y2="40.553333"/>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3883-1-1" id="linearGradient4081-3" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.7532208,-0.59396224,0.59396224,0.7532208,94.343245,-4.8301808)" x1="-45.909092" y1="52.217331" x2="-45.659092" y2="37.671875"/>
<linearGradient id="linearGradient3883-1-1">
<stop style="stop-color:#a27200;stop-opacity:1;" offset="0" id="stop3885-63-8"/>
<stop style="stop-color:#ffe900;stop-opacity:1;" offset="1" id="stop3887-3-0"/>
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3883-1-0-2" id="linearGradient4083-9" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.7532208,-0.59396224,0.59396224,0.7532208,113.26634,4.7621752)" x1="-45.909092" y1="52.217331" x2="-45.659092" y2="37.671875"/>
<linearGradient id="linearGradient3883-1-0-2">
<stop style="stop-color:#a27200;stop-opacity:1;" offset="0" id="stop3885-63-6-2"/>
<stop style="stop-color:#ffe900;stop-opacity:1;" offset="1" id="stop3887-3-5-1"/>
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3883-1-5-6" id="linearGradient4085-4" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.7532208,-0.59396224,0.59396224,0.7532208,77.313909,-25.823666)" x1="-45.909092" y1="52.217331" x2="-45.659092" y2="37.671875"/>
<linearGradient id="linearGradient3883-1-5-6">
<stop style="stop-color:#a27200;stop-opacity:1;" offset="0" id="stop3885-63-3-2"/>
<stop style="stop-color:#ffe900;stop-opacity:1;" offset="1" id="stop3887-3-2-8"/>
</linearGradient>
<linearGradient y2="37.671875" x2="-45.659092" y1="52.217331" x1="-45.909092" gradientTransform="matrix(0.7532208,-0.59396224,0.59396224,0.7532208,133.14868,14.180124)" gradientUnits="userSpaceOnUse" id="linearGradient4115" xlink:href="#linearGradient3883-1-5-6" inkscape:collect="always"/>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3883-1-12" id="linearGradient4081-9" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.77104208,-0.59933979,0.60801545,0.76004024,38.440632,-48.22656)" x1="-45.909092" y1="52.217331" x2="-45.659092" y2="37.671875"/>
<linearGradient id="linearGradient3883-1-12">
<stop style="stop-color:#a27200;stop-opacity:1;" offset="0" id="stop3885-63-7"/>
<stop style="stop-color:#ffe900;stop-opacity:1;" offset="1" id="stop3887-3-09"/>
</linearGradient>
<linearGradient y2="37.671875" x2="-45.659092" y1="52.217331" x1="-45.909092" gradientTransform="matrix(0.65709111,-0.49036892,0.5181579,0.62185111,35.498499,-36.91264)" gradientUnits="userSpaceOnUse" id="linearGradient3147" xlink:href="#linearGradient3883-1-12" inkscape:collect="always"/>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3883-1-06" id="linearGradient4081-6" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.77104208,-0.59933979,0.60801545,0.76004024,38.440632,-48.22656)" x1="-45.909092" y1="52.217331" x2="-45.659092" y2="37.671875"/>
<linearGradient id="linearGradient3883-1-06">
<stop style="stop-color:#a27200;stop-opacity:1;" offset="0" id="stop3885-63-2"/>
<stop style="stop-color:#ffe900;stop-opacity:1;" offset="1" id="stop3887-3-6"/>
</linearGradient>
<linearGradient y2="37.671875" x2="-45.659092" y1="52.217331" x1="-45.909092" gradientTransform="matrix(0.77104208,-0.59933979,0.60801545,0.76004024,18.064696,-48.22656)" gradientUnits="userSpaceOnUse" id="linearGradient3147-1" xlink:href="#linearGradient3883-1-06" inkscape:collect="always"/>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3883-1-9" id="linearGradient4081-7" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.76307355,-0.59933979,0.60173176,0.76004024,38.095031,-48.22656)" x1="-45.909092" y1="52.217331" x2="-45.659092" y2="37.671875"/>
<linearGradient id="linearGradient3883-1-9">
<stop style="stop-color:#a27200;stop-opacity:1;" offset="0" id="stop3885-63-20"/>
<stop style="stop-color:#ffe900;stop-opacity:1;" offset="1" id="stop3887-3-23"/>
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3991" id="linearGradient3997" x1="13.3365" y1="27.160084" x2="16.853151" y2="18.167061" gradientUnits="userSpaceOnUse"/>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3999" id="linearGradient4005" x1="13.809239" y1="27.325958" x2="16.208029" y2="18.637737" gradientUnits="userSpaceOnUse"/>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient4007" id="linearGradient4013" x1="13.305584" y1="27.051975" x2="15.567404" y2="18.380537" 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="51.352241" inkscape:cy="21.397156" 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:window-maximized="1" inkscape:snap-bbox="true" inkscape:snap-nodes="true" inkscape:snap-global="false">
<inkscape:grid type="xygrid" id="grid3045" empspacing="2" visible="true" enabled="true" snapvisiblegridlinesonly="true"/>
</sodipodi:namedview>
<metadata id="metadata2990">
<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:creator>
<cc:Agent>
<dc:title>[Yorik van Havre]</dc:title>
</cc:Agent>
</dc:creator>
<dc:title>Arch_Rebar</dc:title>
<dc:date>2013-10-07</dc:date>
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_Rebar.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<g id="layer1" inkscape:label="Layer 1" inkscape:groupmode="layer">
<path style="color:#000000;fill:url(#linearGradient4085);fill-opacity:1;fill-rule:evenodd;stroke:#302b00;stroke-width:2;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 60.999997,29 43,44 l 8,12 9.999997,-8.522207 z" id="rect3927-7" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
<path style="color:#000000;fill:url(#linearGradient4083);fill-opacity:1;fill-rule:evenodd;stroke:#302b00;stroke-width:1.99999988000000006;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 61,2.9999998 23,34 31,46 61,21.790714 z" id="rect3927-9" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
<path style="color:#000000;fill:url(#linearGradient4081);fill-opacity:1;fill-rule:evenodd;stroke:#302b00;stroke-width:2;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 39.353422,14.334536 C 44.482951,10.010831 36.930113,0.05679041 30.855842,4.0421362 20.14891,12.460802 5,24 5,24 l 8,12 c 0,0 19.508425,-16.226689 26.353422,-21.665464 z" id="rect3927" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
<path style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" d="m 25.249695,34.588267 c 0.485572,0 33.781873,-27.4694484 33.781873,-27.4694484 l -10e-7,13.6653574 -28.579325,23.099308 z" id="path4015" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
<path style="color:#000000;fill:none;stroke:#fce94f;stroke-width:2;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 37.913291,12.965316 C 41.46823,10.375694 35.930633,2.1213928 31.173418,6.2601274 20.466486,14.678793 7,25 7,25 l 6.232988,8.24525 c 0,0 17.835306,-14.841159 24.680303,-20.279934 z" id="rect3927-75" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
<path sodipodi:type="arc" style="color:#000000;fill:url(#linearGradient3997);fill-opacity:1;fill-rule:evenodd;stroke:#302b00;stroke-width:2.52394294999999991;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="path3082" sodipodi:cx="15.545455" sodipodi:cy="23" sodipodi:rx="8.090909" sodipodi:ry="8.090909" d="M 23.636364,23 A 8.090909,8.090909 0 1 1 7.454546,23 8.090909,8.090909 0 1 1 23.636364,23 z" transform="matrix(0.56525353,-0.41335011,0.47999651,0.75985114,-10.827043,18.949139)"/>
<path sodipodi:type="arc" style="color:#000000;fill:none;stroke:#fce94f;stroke-width:3.69287395;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="path3082-7" sodipodi:cx="15.545455" sodipodi:cy="23" sodipodi:rx="8.090909" sodipodi:ry="8.090909" d="M 23.636364,23 A 8.090909,8.090909 0 1 1 7.454546,23 8.090909,8.090909 0 1 1 23.636364,23 z" transform="matrix(0.30023259,-0.36676447,0.39686301,0.49214378,-4.813901,24.421156)"/>
<path sodipodi:type="arc" style="color:#000000;fill:url(#linearGradient4005);fill-opacity:1;fill-rule:evenodd;stroke:#302b00;stroke-width:2.52394294999999991;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="path3082-5" sodipodi:cx="15.545455" sodipodi:cy="23" sodipodi:rx="8.090909" sodipodi:ry="8.090909" d="M 23.636364,23 A 8.090909,8.090909 0 1 1 7.454546,23 8.090909,8.090909 0 1 1 23.636364,23 z" transform="matrix(0.56525353,-0.41335011,0.47999651,0.75985114,7.2182949,28.876511)"/>
<path sodipodi:type="arc" style="color:#000000;fill:none;stroke:#fce94f;stroke-width:3.69287395;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="path3082-7-3" sodipodi:cx="15.545455" sodipodi:cy="23" sodipodi:rx="8.090909" sodipodi:ry="8.090909" d="M 23.636364,23 A 8.090909,8.090909 0 1 1 7.454546,23 8.090909,8.090909 0 1 1 23.636364,23 z" transform="matrix(0.30023259,-0.36676447,0.39686301,0.49214378,13.231436,34.348528)"/>
<path style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" d="M 44.395069,45.478932 59.031568,33.270288 58.9622,46.519442 50.360655,54.01111 z" id="path4023" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
<path sodipodi:type="arc" style="color:#000000;fill:url(#linearGradient4013);fill-opacity:1;fill-rule:evenodd;stroke:#302b00;stroke-width:2.52394294999999991;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="path3082-56" sodipodi:cx="15.545455" sodipodi:cy="23" sodipodi:rx="8.090909" sodipodi:ry="8.090909" d="M 23.636364,23 A 8.090909,8.090909 0 1 1 7.454546,23 8.090909,8.090909 0 1 1 23.636364,23 z" transform="matrix(0.56525353,-0.41335011,0.47999651,0.75985114,27.165219,38.943882)"/>
<path sodipodi:type="arc" style="color:#000000;fill:none;stroke:#fce94f;stroke-width:3.69287395;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="path3082-7-2" sodipodi:cx="15.545455" sodipodi:cy="23" sodipodi:rx="8.090909" sodipodi:ry="8.090909" d="M 23.636364,23 A 8.090909,8.090909 0 1 1 7.454546,23 8.090909,8.090909 0 1 1 23.636364,23 z" transform="matrix(0.30023259,-0.36676447,0.39686301,0.49214378,33.178361,44.415899)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 21 KiB

@@ -0,0 +1,83 @@
<?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="64"
height="64"
viewBox="0 0 16.933333 16.933334"
version="1.1"
id="svg8"
sodipodi:docname="ThreadProfileSVGLogo.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="-166.53392"
inkscape:cy="68.194187"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1001"
inkscape:window-x="1791"
inkscape:window-y="-9"
inkscape:window-maximized="1"
units="px" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-280.06665)">
<image
y="280.21786"
x="0.60476506"
id="image4537"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAAA3NCSVQICAjb4U/gAAAEmUlEQVRo ge1az2vjRhiVvT0VSi67IOjKgeaQxRPQMZHZQntZJ9eS0R4CNbS3diFkDblapodCim32D0hLiy8Z 5bQ9+VSoidWEUFiQHJI2FNkpCBwIXkKPcQ+yFc9oRh4pcWyB32kszzfznma+HzN2otfrCXFGctIE 7oqZgEnjg2hmmqa5jbm5uTsy6Ha7xJihEPsVmAmYNBLR8kClUnEbqVTqjgxarZbbSCYpb/Pm5sZr ZzIZt7G8vOw9jP0KzARMGhHzwDiwuLgY3GFhYcH/MPYrMBMwaWA+cHh46DYajYb3kBqex4HV1dUI VrFfgZmASQPzAS/QXl1dBZudnJyMi1FIxH4FsGr08vLSbRwfHwebra2t0b9Q8vt5JRQDrxp99Kjz 548//fzOoXSCqIcg1TzKCrx4v5uTxQiGwXgl/kVnHwjMB7zie+QhIcJMY8J0+UCEhY0ioPbRV+PY Qm/+zdx1C/FDzm2XBUEQhFTij60t1I42ig/lsjuqsPXifWpJ4xkWE3B+fu42zs7OvIeJRIKwGdN1 ajKZHD4B81qNg8pDIvYCpuhIubm5efvBKnL6FSZAUfpJdGVlxXvo3/HJZNK7FxIE4b48OBpiv4Wm SoAVwSaKACLYSRGGoAMwP7CB+cDBwYHbODo68h4+2Jk4GqaaHA9mAiYNzAe828nr62u3Yder1d/r rZZt24NO8/PzQurZs0/kbPSKtG0g1DAuLtptL4mI4u6uASFcL0BO96UIGIJdr1ar1bpN+ca2Bdu2 67WaIIryxsaIG1k/c4QMSu5zHMvRLUvXNAEAWCjwqqCdiU/ffrHxNY07BwLOxG2jVC7RuHOAfSb2 rcDpD8+f75xGmiUIbXSPx4ZhYAIeP/5NfUKyBwAW9goQ9NfUsvT9YlHTQ2VNo+RjL0mK+lpVJMm9 lXCcdx/+cxxyWEEgopCuqjpOHiLTNJHHXnD1ILO8nZND0C8ZOHklX6lU8op0m8RFUS4gs2cyNgob QwJI+kAzTcQKCaKcK/NpIOlLaqWSVxj1B2BvdgZuBeg6QX9vVCSQcxwSjAZB/7U6oniCKIwETwDB ny+QydlRbAj+ijrKwJ1c484FAwEkf8j3EkSFtRlckPwzfNeOYJ07m9FLCQDSnPaS9JSzZ6jOIM1L gC4gneZewqcS/3kgRN804GRAF9BscsfjizZ/egrRt2lxMhgIwBVbVpNzonb7Iuhr/J2P6DxMoMlL YCCA2HSETzPhGMHFDbHrCZ9mwtrnTsneFiLiji8p0+DUfhlV3xBxx5eUabCKLzXuLXzrA2Tw1dUl lfkeut3u32+/36n5LpP/u2zh+PjTLHZsMEqvvvv1aKhDd4AB+6UlfvpEOU0zBlArFNaHqiHLsprF z7/VO53AgUU592X/Et6p7fikinI2m5VlURz86a/TgZ91Xhb1Ec4LINrD65seDmbxw4CczTLPZXKu PEDY3xOgxs7FEA0TJsMoRKbJm8efpOE3nEWpnNveZivFASAy0TpfX8G3An3gJTR1Fs10ezLkAojM hxiWIaA/n4k0CAE2JwBQo1ALg3sdNuK/FqcHsb8X+h/s/sbLpcJe1gAAAABJRU5ErkJggg== "
style="image-rendering:optimizeQuality"
preserveAspectRatio="none"
height="16.933332"
width="16.933332" />
<image
y="280.21786"
x="0.60476506"
id="image835"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAAA3NCSVQICAjb4U/gAAAA+ElEQVRo
ge2ZQQ6EIBAExfgtXu/D9MDG7ALiqISCTdfFCyRdIUAb3LZt08jMdIC3SIBGAjQSoJEAjQRoJEAj
ARoJ0EiARgI0EqCRAI0EaCRAIwGaJXyOVwLnHBfmCcOvgARonN7IYCRAIwEaCdBIgGZ5PLNKb33f
A66rBFKw7WKnApbc67reCJXgvbcMK8vEAtncL4M+IHIrOPwIROnb5075NslquPRnsofcEYdG6vA5
RntOPxVTzcZx3TL8RfYvAmFzGA/m9oRg2VMoXoEOHcqRSvdAANnZaejTxmC5ibNUEbMs+L0qkRkx
aJm7mFbJqkWd7pzh74EdgqxnCcySe50AAAAASUVORK5CYII=
"
style="image-rendering:optimizeQuality"
preserveAspectRatio="none"
height="16.933332"
width="16.933332" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

+4 -3
View File
@@ -91,10 +91,11 @@ class UpdateWorker(QtCore.QThread):
if url:
addondir = moddir + os.sep + name
#print ("found:",name," at ",url)
if not os.path.exists(addondir):
state = 0
else:
if os.path.exists(addondir) and os.listdir(addondir):
# make sure the folder exists and it contains files!
state = 1
else:
state = 0
repos.append([name,url,state])
# querying custom addons
customaddons = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons").GetString("CustomRepositories","").split("\n")
+1
View File
@@ -43,6 +43,7 @@ if FreeCAD.GuiUp:
from ArchWall import *
from ArchFloor import *
from ArchFence import *
from ArchProject import *
from ArchSite import *
from ArchBuilding import *
from ArchStructure import *
+29 -15
View File
@@ -313,7 +313,7 @@ class CommandBuildingPart:
class BuildingPart:
class BuildingPart(ArchIFC.IfcProduct):
"The BuildingPart object"
@@ -326,7 +326,7 @@ class BuildingPart:
self.setProperties(obj)
def setProperties(self,obj):
ArchIFC.setProperties(obj)
ArchIFC.IfcProduct.setProperties(self, obj)
pl = obj.PropertiesList
if not "Height" in pl:
@@ -366,7 +366,7 @@ class BuildingPart:
def onChanged(self,obj,prop):
ArchIFC.onChanged(obj, prop)
ArchIFC.IfcProduct.onChanged(self, obj, prop)
if prop == "Height":
for child in obj.Group:
@@ -483,13 +483,10 @@ class ViewProviderBuildingPart:
vobj.ShowLevel = True
if not "ShowUnit" in pl:
vobj.addProperty("App::PropertyBool","ShowUnit","BuildingPart",QT_TRANSLATE_NOOP("App::Property","If true, show the unit on the level tag"))
if not "SetWorkingPlane" in pl:
vobj.addProperty("App::PropertyBool","SetWorkingPlane","BuildingPart",QT_TRANSLATE_NOOP("App::Property","If true, when activated, the working plane will automatically adapt to this level"))
vobj.SetWorkingPlane = True
if not "OriginOffset" in pl:
vobj.addProperty("App::PropertyBool","OriginOffset","BuildingPart",QT_TRANSLATE_NOOP("App::Property","If true, when activated, Display offset will affect the origin mark too"))
vobj.addProperty("App::PropertyBool","OriginOffset","BuildingPart",QT_TRANSLATE_NOOP("App::Property","If true, display offset will affect the origin mark too"))
if not "ShowLabel" in pl:
vobj.addProperty("App::PropertyBool","ShowLabel","BuildingPart",QT_TRANSLATE_NOOP("App::Property","If true, when activated, the object's label is displayed"))
vobj.addProperty("App::PropertyBool","ShowLabel","BuildingPart",QT_TRANSLATE_NOOP("App::Property","If true, the object's label is displayed"))
vobj.ShowLabel = True
if not "FontName" in pl:
vobj.addProperty("App::PropertyFont","FontName","BuildingPart",QT_TRANSLATE_NOOP("App::Property","The font to be used for texts"))
@@ -497,14 +494,31 @@ class ViewProviderBuildingPart:
if not "FontSize" in pl:
vobj.addProperty("App::PropertyLength","FontSize","BuildingPart",QT_TRANSLATE_NOOP("App::Property","The font size of texts"))
vobj.FontSize = Draft.getParam("textheight",2.0)
if not "ViewData" in pl:
vobj.addProperty("App::PropertyFloatList","ViewData","BuildingPart",QT_TRANSLATE_NOOP("App::Property","Camera position data associated with this object"))
if not "RestoreView" in pl:
vobj.addProperty("App::PropertyBool","RestoreView","BuildingPart",QT_TRANSLATE_NOOP("App::Property","If set, the view stored in this object will be restored on double-click"))
if not "DiffuseColor" in pl:
vobj.addProperty("App::PropertyColorList","DiffuseColor","BuildingPart",QT_TRANSLATE_NOOP("App::Property","The individual face colors"))
# Interaction properties
if not "SetWorkingPlane" in pl:
vobj.addProperty("App::PropertyBool","SetWorkingPlane","Interaction",QT_TRANSLATE_NOOP("App::Property","If true, when activated, the working plane will automatically adapt to this level"))
vobj.SetWorkingPlane = True
if not "AutoWorkingPlane" in pl:
vobj.addProperty("App::PropertyBool","AutoWorkingPlane","BuildingPart",QT_TRANSLATE_NOOP("App::Property","If set to True, the working plane will be kept on Auto mode"))
vobj.addProperty("App::PropertyBool","AutoWorkingPlane","Interaction",QT_TRANSLATE_NOOP("App::Property","If set to True, the working plane will be kept on Auto mode"))
if not "ViewData" in pl:
vobj.addProperty("App::PropertyFloatList","ViewData","Interaction",QT_TRANSLATE_NOOP("App::Property","Camera position data associated with this object"))
vobj.setEditorMode("ViewData",2)
if not "RestoreView" in pl:
vobj.addProperty("App::PropertyBool","RestoreView","Interaction",QT_TRANSLATE_NOOP("App::Property","If set, the view stored in this object will be restored on double-click"))
if not "DoubleClickActivates" in pl:
vobj.addProperty("App::PropertyBool","DoubleClickActivates","Interaction",QT_TRANSLATE_NOOP("App::Property","If True, double-clicking this object in the tree turns it active"))
# inventor saving
if not "SaveInventor" in pl:
vobj.addProperty("App::PropertyBool","SaveInventor","Interaction",QT_TRANSLATE_NOOP("App::Property","If this is enabled, the inventor representation of this object will be saved in the FreeCAD file, allowing to reference it in other file sin lightweight mode."))
if not "SavedInventor" in pl:
vobj.addProperty("App::PropertyFileIncluded","SavedInventor","Interaction",QT_TRANSLATE_NOOP("App::Property","A slot to save the inventor representation of this object, if enabled"))
vobj.setEditorMode("SavedInventor",2)
# children properties
if not "ChildrenOverride" in pl:
vobj.addProperty("App::PropertyBool","ChildrenOverride","Children",QT_TRANSLATE_NOOP("App::Property","If true, show the objects contained in this Building Part will adopt these line, color and transparency settings"))
if not "ChildrenLineWidth" in pl:
@@ -520,6 +534,8 @@ class ViewProviderBuildingPart:
vobj.ChildrenLineColor = (float((c>>24)&0xFF)/255.0,float((c>>16)&0xFF)/255.0,float((c>>8)&0xFF)/255.0,0.0)
if not "ChildrenTransparency" in pl:
vobj.addProperty("App::PropertyPercent","ChildrenTransparency","Children",QT_TRANSLATE_NOOP("App::Property","The transparency of child objects"))
# clip properties
if not "CutView" in pl:
vobj.addProperty("App::PropertyBool","CutView","Clip",QT_TRANSLATE_NOOP("App::Property","Cut the view above this level"))
if not "CutMargin" in pl:
@@ -527,8 +543,6 @@ class ViewProviderBuildingPart:
vobj.CutMargin = 1600
if not "AutoCutView" in pl:
vobj.addProperty("App::PropertyBool","AutoCutView","Clip",QT_TRANSLATE_NOOP("App::Property","Turn cutting on when activating this level"))
if not "SaveInventor" in pl:
vobj.addProperty("App::PropertyBool","SaveInventor","BuildingPart",QT_TRANSLATE_NOOP("App::Property","If this is enabled, the inventor representation of this object will be saved in the FreeCAD file, allowing to reference it in other file sin lightweight mode."))
def onDocumentRestored(self,vobj):
+2 -2
View File
@@ -116,7 +116,7 @@ def addComponents(objectsList,host):
if not isinstance(objectsList,list):
objectsList = [objectsList]
hostType = Draft.getType(host)
if hostType in ["Floor","Building","Site","BuildingPart"]:
if hostType in ["Floor","Building","Site","Project","BuildingPart"]:
for o in objectsList:
host.addObject(o)
elif hostType in ["Wall","Structure","Window","Roof","Stairs","StructuralSystem","Panel","Component"]:
@@ -744,7 +744,7 @@ def pruneIncluded(objectslist,strict=False):
if obj.isDerivedFrom("Part::Feature"):
if not (Draft.getType(obj) in ["Window","Clone","Pipe","Rebar"]):
for parent in obj.InList:
if parent.isDerivedFrom("Part::Feature") and not (Draft.getType(parent) in ["Space","Facebinder","Window","Roof","Clone","Site"]):
if parent.isDerivedFrom("Part::Feature") and not (Draft.getType(parent) in ["Space","Facebinder","Window","Roof","Clone","Site","Project"]):
if not parent.isDerivedFrom("Part::Part2DObject"):
# don't consider 2D objects based on arch elements
if hasattr(parent,"Host") and (parent.Host == obj):
+17 -17
View File
@@ -133,22 +133,20 @@ def removeFromComponent(compobject,subobject):
class Component:
class Component(ArchIFC.IfcProduct):
"The default Arch Component object"
def __init__(self,obj):
def __init__(self, obj):
obj.Proxy = self
Component.setProperties(self,obj)
Component.setProperties(self, obj)
self.Type = "Component"
def setProperties(self,obj):
def setProperties(self, obj):
"Sets the needed properties of this object"
ArchIFC.setProperties(obj)
ArchIFC.IfcProduct.setProperties(self, obj)
pl = obj.PropertiesList
if not "Base" in pl:
@@ -195,9 +193,8 @@ class Component:
#self.MoveWithHost = False
self.Type = "Component"
def onDocumentRestored(self,obj):
Component.setProperties(self,obj)
def onDocumentRestored(self, obj):
Component.setProperties(self, obj)
def execute(self,obj):
@@ -210,24 +207,20 @@ class Component:
obj.Shape = shape
def __getstate__(self):
# for compatibility with 0.17
if hasattr(self,"Type"):
return self.Type
return "Component"
def __setstate__(self,state):
return None
def onBeforeChange(self,obj,prop):
if prop == "Placement":
self.oldPlacement = FreeCAD.Placement(obj.Placement)
def onChanged(self,obj,prop):
ArchIFC.onChanged(obj, prop)
def onChanged(self, obj, prop):
ArchIFC.IfcProduct.onChanged(self, obj, prop)
if prop == "Placement":
if hasattr(self,"oldPlacement"):
@@ -741,12 +734,19 @@ class ViewProviderComponent:
vobj.Proxy = self
self.Object = vobj.Object
self.setProperties(vobj)
def setProperties(self,vobj):
if not "UseMaterialColor" in vobj.PropertiesList:
vobj.addProperty("App::PropertyBool","UseMaterialColor","Component",QT_TRANSLATE_NOOP("App::Property","Use the material color as this object's shape color, if available"))
vobj.UseMaterialColor = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetBool("UseMaterialColor",True)
def updateData(self,obj,prop):
#print(obj.Name," : updating ",prop)
if prop == "Material":
if obj.Material:
if obj.Material and ( (not hasattr(obj.ViewObject,"UseMaterialColor")) or obj.ViewObject.UseMaterialColor):
if hasattr(obj.Material,"Material"):
if 'DiffuseColor' in obj.Material.Material:
if "(" in obj.Material.Material['DiffuseColor']:
+3
View File
@@ -231,6 +231,9 @@ class _ViewProviderFence(ArchComponent.ViewProviderComponent):
def __init__(self, vobj):
ArchComponent.ViewProviderComponent.__init__(self, vobj)
# setProperties of ArchComponent will be overwritten
# thus setProperties from ArchComponent will be explicit called to get the properties
ArchComponent.ViewProviderComponent.setProperties(self, vobj)
self.setProperties(vobj)
def setProperties(self, vobj):
+4 -6
View File
@@ -22,7 +22,7 @@
#* *
#***************************************************************************
import FreeCAD,Draft,ArchCommands, DraftVecUtils
import FreeCAD,Draft,ArchCommands, DraftVecUtils, ArchIFC
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore, QtGui
@@ -121,7 +121,7 @@ Floor creation aborted.") + "\n"
FreeCAD.ActiveDocument.recompute()
class _Floor:
class _Floor(ArchIFC.IfcProduct):
"The Floor object"
@@ -134,6 +134,7 @@ class _Floor:
def setProperties(self,obj):
ArchIFC.IfcProduct.setProperties(self, obj)
pl = obj.PropertiesList
if not "Height" in pl:
obj.addProperty("App::PropertyLength","Height","Floor",QT_TRANSLATE_NOOP("App::Property","The height of this object"))
@@ -142,10 +143,6 @@ class _Floor:
if not hasattr(obj,"Placement"):
# obj can be a Part Feature and already has a placement
obj.addProperty("App::PropertyPlacement","Placement","Base",QT_TRANSLATE_NOOP("App::Property","The placement of this object"))
if not "IfcType" in pl:
obj.addProperty("App::PropertyEnumeration","IfcType","IFC",QT_TRANSLATE_NOOP("App::Property","The type of this object"))
import ArchIFC
obj.IfcType = ArchIFC.IfcTypes
self.Type = "Floor"
def onDocumentRestored(self,obj):
@@ -161,6 +158,7 @@ class _Floor:
return None
def onChanged(self,obj,prop):
ArchIFC.IfcProduct.onChanged(self, obj, prop)
if not hasattr(self,"Object"):
# on restore, self.Object is not there anymore
+157 -153
View File
@@ -9,181 +9,185 @@ else:
return txt
import ArchIFCSchema
IfcTypes = ['Undefined']+[''.join(map(lambda x: x if x.islower() else " "+x, t[3:]))[1:] for t in ArchIFCSchema.IfcProducts.keys()]
def setProperties(obj):
IfcTypes = [''.join(map(lambda x: x if x.islower() else " "+x, t[3:]))[1:] for t in ArchIFCSchema.IfcProducts.keys()]
"Checks and sets all the needed IFC-related properties"
class IfcRoot:
def setProperties(self, obj):
if not "IfcData" in obj.PropertiesList:
obj.addProperty("App::PropertyMap","IfcData","IFC",QT_TRANSLATE_NOOP("App::Property","IFC data"))
if not "IfcType" in obj.PropertiesList:
obj.addProperty("App::PropertyEnumeration","IfcType","IFC",QT_TRANSLATE_NOOP("App::Property","The type of this object"))
obj.IfcType = IfcTypes
if not "IfcType" in obj.PropertiesList:
obj.addProperty("App::PropertyEnumeration","IfcType","IFC",QT_TRANSLATE_NOOP("App::Property","The type of this object"))
obj.IfcType = self.getCanonicalisedIfcTypes()
if not "IfcData" in obj.PropertiesList:
obj.addProperty("App::PropertyMap","IfcData","IFC",QT_TRANSLATE_NOOP("App::Property","IFC data"))
if not "IfcProperties" in obj.PropertiesList:
obj.addProperty("App::PropertyMap","IfcProperties","IFC",QT_TRANSLATE_NOOP("App::Property","IFC properties of this object"))
if not "IfcProperties" in obj.PropertiesList:
obj.addProperty("App::PropertyMap","IfcProperties","IFC",QT_TRANSLATE_NOOP("App::Property","IFC properties of this object"))
self.migrateDeprecatedAttributes(obj)
migrateDeprecatedAttributes(obj)
def onChanged(self, obj, prop):
if prop == "IfcType":
self.setupIfcAttributes(obj)
self.setupIfcComplexAttributes(obj)
if obj.getGroupOfProperty(prop) == "IFC Attributes":
self.setObjIfcAttributeValue(obj, prop, obj.getPropertyByName(prop))
def onChanged(obj, prop):
def setupIfcAttributes(self, obj):
ifcTypeSchema = self.getIfcTypeSchema(obj.IfcType)
if ifcTypeSchema is None:
return
self.purgeUnusedIfcAttributesFromPropertiesList(ifcTypeSchema, obj)
self.addIfcAttributes(ifcTypeSchema, obj)
"Called by Arch object's OnChanged method"
def setupIfcComplexAttributes(self, obj):
ifcTypeSchema = self.getIfcTypeSchema(obj.IfcType)
if ifcTypeSchema is None:
return
IfcData = obj.IfcData
if "complex_attributes" not in IfcData:
IfcData["complex_attributes"] = "{}"
ifcComplexAttributes = json.loads(IfcData["complex_attributes"])
for attribute in ifcTypeSchema["complex_attributes"]:
if attribute["name"] not in ifcComplexAttributes.keys():
ifcComplexAttributes[attribute["name"]] = {}
IfcData["complex_attributes"] = json.dumps(ifcComplexAttributes)
obj.IfcData = IfcData
if prop == "IfcType":
setupIfcAttributes(obj)
if obj.getGroupOfProperty(prop) == "IFC Attributes":
setObjIfcAttributeValue(obj, prop, obj.getPropertyByName(prop))
def getIfcTypeSchema(self, IfcType):
name = "Ifc" + IfcType.replace(" ", "")
if IfcType == "Undefined":
name = "IfcBuildingElementProxy"
if name in self.getIfcSchema():
return self.getIfcSchema()[name]
return None
def getIfcProduct(IfcType):
"Returns an IFC product name from an obj.IfcType"
name = "Ifc" + IfcType.replace(" ", "")
if IfcType == "Undefined":
name = "IfcBuildingElementProxy"
if name in ArchIFCSchema.IfcProducts:
return ArchIFCSchema.IfcProducts[name]
return None
def getIfcSchema(self):
return {}
def getIfcProductAttribute(ifcProduct, name):
"Returns the attributes of a given product"
def getCanonicalisedIfcTypes(self):
schema = self.getIfcSchema()
return [''.join(map(lambda x: x if x.islower() else " "+x, t[3:]))[1:] for t in schema.keys()]
for attribute in ifcProduct["attributes"]:
if attribute["name"].replace(' ', '') == name:
return attribute
return None
def getIfcAttributeSchema(self, ifcTypeSchema, name):
for attribute in ifcTypeSchema["attributes"]:
if attribute["name"].replace(' ', '') == name:
return attribute
return None
def setupIfcAttributes(obj):
def addIfcAttributes(self, ifcTypeSchema, obj):
for attribute in ifcTypeSchema["attributes"]:
if attribute["name"] in obj.PropertiesList \
or attribute["name"] == "RefLatitude" \
or attribute["name"] == "RefLongitude" \
or attribute["name"] == "Name":
continue
self.addIfcAttribute(obj, attribute)
self.addIfcAttributeValueExpressions(obj, attribute)
"Sets the necessary IFC attribute properties for an object"
ifcProduct = getIfcProduct(obj.IfcType)
if ifcProduct is None:
return
purgeUnusedIfcAttributesFromPropertiesList(ifcProduct, obj)
addIfcProductAttributesToObj(ifcProduct, obj)
def addIfcProductAttributesToObj(ifcProduct, obj):
"Adds the necessary attribute properties to an object"
for attribute in ifcProduct["attributes"]:
if attribute["name"] in obj.PropertiesList \
or attribute["name"] == "RefLatitude" \
or attribute["name"] == "RefLongitude":
continue
addIfcProductAttribute(obj, attribute)
addIfcAttributeValueExpressions(obj, attribute)
def addIfcProductAttribute(obj, attribute):
"Adds a given attribute property"
if not hasattr(obj,"IfcData"):
return
IfcData = obj.IfcData
if "attributes" not in IfcData:
IfcData["attributes"] = "{}"
IfcAttributes = json.loads(IfcData["attributes"])
IfcAttributes[attribute["name"]] = attribute
IfcData["attributes"] = json.dumps(IfcAttributes)
obj.IfcData = IfcData
if attribute["is_enum"]:
obj.addProperty("App::PropertyEnumeration", attribute["name"], "IFC Attributes", QT_TRANSLATE_NOOP("App::Property", "Description of IFC attributes are not yet implemented"))
setattr(obj, attribute["name"], attribute["enum_values"])
else:
import ArchIFCSchema
propertyType = "App::" + ArchIFCSchema.IfcTypes[attribute["type"]]["property"]
obj.addProperty(propertyType, attribute["name"], "IFC Attributes", QT_TRANSLATE_NOOP("App::Property", "Description of IFC attributes are not yet implemented"))
def addIfcAttributeValueExpressions(obj, attribute):
"Binds the given attribute properties with expressions"
if not attribute["name"] in obj.PropertiesList:
return
if obj.getGroupOfProperty(attribute["name"]) != "IFC Attributes":
return
if attribute["name"] == "OverallWidth":
if "Length" in obj.PropertiesList:
obj.setExpression("OverallWidth", "Length.Value")
elif "Width" in obj.PropertiesList:
obj.setExpression("OverallWidth", "Width.Value")
elif obj.Shape and (obj.Shape.BoundBox.XLength > obj.Shape.BoundBox.YLength):
obj.setExpression("OverallWidth", "Shape.BoundBox.XLength")
elif obj.Shape:
obj.setExpression("OverallWidth", "Shape.BoundBox.YLength")
elif attribute["name"] == "OverallHeight":
if "Height" in obj.PropertiesList:
obj.setExpression("OverallHeight", "Height.Value")
def addIfcAttribute(self, obj, attribute):
if not hasattr(obj, "IfcData"):
return
IfcData = obj.IfcData
if "attributes" not in IfcData:
IfcData["attributes"] = "{}"
IfcAttributes = json.loads(IfcData["attributes"])
IfcAttributes[attribute["name"]] = attribute
IfcData["attributes"] = json.dumps(IfcAttributes)
obj.IfcData = IfcData
if attribute["is_enum"]:
obj.addProperty("App::PropertyEnumeration", attribute["name"], "IFC Attributes", QT_TRANSLATE_NOOP("App::Property", "Description of IFC attributes are not yet implemented"))
setattr(obj, attribute["name"], attribute["enum_values"])
else:
obj.setExpression("OverallHeight", "Shape.BoundBox.ZLength")
elif attribute["name"] == "ElevationWithFlooring":
if "Shape" in obj.PropertiesList:
import ArchIFCSchema
propertyType = "App::" + ArchIFCSchema.IfcTypes[attribute["type"]]["property"]
obj.addProperty(propertyType, attribute["name"], "IFC Attributes", QT_TRANSLATE_NOOP("App::Property", "Description of IFC attributes are not yet implemented"))
def addIfcAttributeValueExpressions(self, obj, attribute):
if obj.getGroupOfProperty(attribute["name"]) != "IFC Attributes" \
or attribute["name"] not in obj.PropertiesList:
return
if attribute["name"] == "OverallWidth":
if "Length" in obj.PropertiesList:
obj.setExpression("OverallWidth", "Length.Value")
elif "Width" in obj.PropertiesList:
obj.setExpression("OverallWidth", "Width.Value")
elif obj.Shape and (obj.Shape.BoundBox.XLength > obj.Shape.BoundBox.YLength):
obj.setExpression("OverallWidth", "Shape.BoundBox.XLength")
elif obj.Shape:
obj.setExpression("OverallWidth", "Shape.BoundBox.YLength")
elif attribute["name"] == "OverallHeight":
if "Height" in obj.PropertiesList:
obj.setExpression("OverallHeight", "Height.Value")
else:
obj.setExpression("OverallHeight", "Shape.BoundBox.ZLength")
elif attribute["name"] == "ElevationWithFlooring" and "Shape" in obj.PropertiesList:
obj.setExpression("ElevationWithFlooring", "Shape.BoundBox.ZMin")
elif attribute["name"] == "Elevation":
if "Placement" in obj.PropertiesList:
elif attribute["name"] == "Elevation" and "Placement" in obj.PropertiesList:
obj.setExpression("Elevation", "Placement.Base.z")
elif attribute["name"] == "NominalDiameter":
if "Diameter" in obj.PropertiesList:
elif attribute["name"] == "NominalDiameter" and "Diameter" in obj.PropertiesList:
obj.setExpression("NominalDiameter", "Diameter.Value")
elif attribute["name"] == "BarLength":
if "Length" in obj.PropertiesList:
elif attribute["name"] == "BarLength" and "Length" in obj.PropertiesList:
obj.setExpression("BarLength", "Length.Value")
elif attribute["name"] == "RefElevation":
if "Elevation" in obj.PropertiesList:
elif attribute["name"] == "RefElevation" and "Elevation" in obj.PropertiesList:
obj.setExpression("RefElevation", "Elevation.Value")
elif attribute["name"] == "LongName":
obj.LongName = obj.Label
elif attribute["name"] == "LongName":
obj.LongName = obj.Label
def setObjIfcAttributeValue(obj, attributeName, value):
"Sets the value of a given attribute property"
IfcData = obj.IfcData
if "attributes" not in IfcData:
IfcData["attributes"] = "{}"
IfcAttributes = json.loads(IfcData["attributes"])
if isinstance(value, FreeCAD.Units.Quantity):
value = float(value)
if not attributeName in IfcAttributes:
IfcAttributes[attributeName] = {}
IfcAttributes[attributeName]["value"] = value
IfcData["attributes"] = json.dumps(IfcAttributes)
obj.IfcData = IfcData
def setObjIfcAttributeValue(self, obj, attributeName, value):
IfcData = obj.IfcData
if "attributes" not in IfcData:
IfcData["attributes"] = "{}"
IfcAttributes = json.loads(IfcData["attributes"])
if isinstance(value, FreeCAD.Units.Quantity):
value = float(value)
if not attributeName in IfcAttributes:
IfcAttributes[attributeName] = {}
IfcAttributes[attributeName]["value"] = value
IfcData["attributes"] = json.dumps(IfcAttributes)
obj.IfcData = IfcData
def purgeUnusedIfcAttributesFromPropertiesList(ifcProduct, obj):
"Removes unused attribute properties"
for property in obj.PropertiesList:
if obj.getGroupOfProperty(property) != "IFC Attributes":
continue
ifcProductAttribute = getIfcProductAttribute(ifcProduct, property)
if ifcProductAttribute is None or ifcProductAttribute["is_enum"] is True:
obj.removeProperty(property)
def setObjIfcComplexAttributeValue(self, obj, attributeName, value):
IfcData = obj.IfcData
IfcAttributes = json.loads(IfcData["complex_attributes"])
IfcAttributes[attributeName] = value
IfcData["complex_attributes"] = json.dumps(IfcAttributes)
obj.IfcData = IfcData
def migrateDeprecatedAttributes(obj):
"Fixes obsolete properties"
def getObjIfcComplexAttribute(self, obj, attributeName):
return json.loads(obj.IfcData["complex_attributes"])[attributeName]
if "Role" in obj.PropertiesList:
r = obj.Role
obj.removeProperty("Role")
if r in IfcTypes:
obj.IfcType = r
FreeCAD.Console.PrintMessage("Upgrading "+obj.Label+" Role property to IfcType\n")
def purgeUnusedIfcAttributesFromPropertiesList(self, ifcTypeSchema, obj):
for property in obj.PropertiesList:
if obj.getGroupOfProperty(property) != "IFC Attributes":
continue
ifcAttribute = self.getIfcAttributeSchema(ifcTypeSchema, property)
if ifcAttribute is None or ifcAttribute["is_enum"] is True:
obj.removeProperty(property)
if "IfcRole" in obj.PropertiesList:
r = obj.IfcRole
obj.removeProperty("IfcRole")
if r in IfcTypes:
obj.IfcType = r
FreeCAD.Console.PrintMessage("Upgrading "+obj.Label+" IfcRole property to IfcType\n")
if "IfcAttributes"in obj.PropertiesList:
obj.IfcData = obj.IfcAttributes
obj.removeProperty("IfcAttributes")
def migrateDeprecatedAttributes(self, obj):
if "Role" in obj.PropertiesList:
r = obj.Role
obj.removeProperty("Role")
if r in IfcTypes:
obj.IfcType = r
FreeCAD.Console.PrintMessage("Upgrading "+obj.Label+" Role property to IfcType\n")
if "IfcRole" in obj.PropertiesList:
r = obj.IfcRole
obj.removeProperty("IfcRole")
if r in IfcTypes:
obj.IfcType = r
FreeCAD.Console.PrintMessage("Upgrading "+obj.Label+" IfcRole property to IfcType\n")
if "IfcAttributes"in obj.PropertiesList:
obj.IfcData = obj.IfcAttributes
obj.removeProperty("IfcAttributes")
class IfcProduct(IfcRoot):
def getIfcSchema(self):
return ArchIFCSchema.IfcProducts
class IfcContext(IfcRoot):
def getIfcSchema(self):
return ArchIFCSchema.IfcContexts
+4
View File
@@ -3,6 +3,10 @@ import FreeCAD, os, json
ifcVersions = ["IFC4", "IFC2X3"]
IfcVersion = ifcVersions[FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetInt("IfcVersion",0)]
with open(os.path.join(FreeCAD.getResourceDir(), "Mod", "Arch", "Presets",
"ifc_contexts_" + IfcVersion + ".json")) as f:
IfcContexts = json.load(f)
with open(os.path.join(FreeCAD.getResourceDir(), "Mod", "Arch", "Presets",
"ifc_products_" + IfcVersion + ".json")) as f:
IfcProducts = json.load(f)
+71
View File
@@ -0,0 +1,71 @@
import FreeCAD, ArchIFC
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtGui
class IfcContextView:
def setEdit(self, viewObject, mode):
# What does mode do?
FreeCADGui.Control.showDialog(IfcContextUI(viewObject.Object))
return True
class IfcContextUI:
def __init__(self, object):
self.object = object
self.lineEditObjects = []
self.createBaseLayout()
self.createMapConversionFormLayout()
self.prefillMapConversionForm()
self.form = self.baseWidget
def accept(self):
data = {}
for lineEdit in self.lineEditObjects:
data[lineEdit.objectName()] = lineEdit.text()
ArchIFC.IfcRoot.setObjIfcComplexAttributeValue(self, self.object, "RepresentationContexts", data)
return True
def createBaseLayout(self):
self.baseWidget = QtGui.QWidget()
self.baseLayout = QtGui.QVBoxLayout(self.baseWidget)
def createMapConversionFormLayout(self):
self.baseLayout.addWidget(self.createLabel("Target Coordinate Reference System"))
self.baseLayout.addLayout(self.createFormEntry("name", "Name"))
self.baseLayout.addLayout(self.createFormEntry("description", "Description"))
self.baseLayout.addLayout(self.createFormEntry("geodetic_datum", "Geodetic datum"))
self.baseLayout.addLayout(self.createFormEntry("vertical_datum", "Vertical datum"))
self.baseLayout.addLayout(self.createFormEntry("map_projection", "Map projection"))
self.baseLayout.addLayout(self.createFormEntry("map_zone", "Map zone"))
self.baseLayout.addLayout(self.createFormEntry("map_unit", "Map unit"))
self.baseLayout.addWidget(self.createLabel("Map Conversion"))
self.baseLayout.addLayout(self.createFormEntry("eastings", "Eastings"))
self.baseLayout.addLayout(self.createFormEntry("northings", "Northings"))
self.baseLayout.addLayout(self.createFormEntry("orthogonal_height", "Orthogonal height"))
self.baseLayout.addLayout(self.createFormEntry("true_north", "True north (anti-clockwise from +Y)"))
self.baseLayout.addLayout(self.createFormEntry("scale", "Scale"))
def prefillMapConversionForm(self):
data = ArchIFC.IfcRoot.getObjIfcComplexAttribute(self, self.object, "RepresentationContexts")
for lineEdit in self.lineEditObjects:
if lineEdit.objectName() in data.keys():
lineEdit.setText(data[lineEdit.objectName()])
def createFormEntry(self, name, label):
layout = QtGui.QHBoxLayout(self.baseWidget)
layout.addWidget(self.createLabel(label))
layout.addWidget(self.createLineEdit(name))
return layout
def createLabel(self, value):
label = QtGui.QLabel(self.baseWidget)
label.setText(QtGui.QApplication.translate("Arch", value, None))
return label
def createLineEdit(self, name):
lineEdit = QtGui.QLineEdit(self.baseWidget)
lineEdit.setObjectName(name)
self.lineEditObjects.append(lineEdit)
return lineEdit
+10
View File
@@ -825,6 +825,11 @@ class PanelView:
def __init__(self, obj):
obj.Proxy = self
# setProperties of ArchComponent will be overwritten
# thus setProperties from ArchComponent will be explicit called to get the properties
ArchComponent.ViewProviderComponent.setProperties(self, vobj)
self.setProperties(obj)
obj.X = 10
obj.Y = 10
@@ -924,6 +929,11 @@ class PanelCut(Draft._DraftObject):
def __init__(self, obj):
Draft._DraftObject.__init__(self,obj)
obj.Proxy = self
# setProperties of ArchComponent will be overwritten
# thus setProperties from ArchComponent will be explicit called to get the properties
ArchComponent.ViewProviderComponent.setProperties(self, vobj)
self.setProperties(obj)
def setProperties(self,obj):
+126
View File
@@ -0,0 +1,126 @@
# -*- coding: utf8 -*-
#***************************************************************************
#* *
#* Copyright (c) 2011 *
#* Yorik van Havre <[email protected]> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
import FreeCAD,Draft,ArchComponent,ArchCommands,math,re,datetime,ArchIFC,ArchIFCView
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore, QtGui
from DraftTools import translate
from PySide.QtCore import QT_TRANSLATE_NOOP
else:
def translate(ctxt,txt):
return txt
def QT_TRANSLATE_NOOP(ctxt,txt):
return txt
## @package ArchProject
# \ingroup ARCH
# \brief The Project object and tools
#
# This module provides tools to build Project objects.
__title__="FreeCAD Project"
__author__ = "Yorik van Havre"
__url__ = "http://www.freecadweb.org"
def makeProject(sites=None, name="Project"):
'''makeProject(sites): creates a project aggregating the list of sites.'''
if not FreeCAD.ActiveDocument:
return FreeCAD.Console.PrintError("No active document. Aborting\n")
import Part
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Project")
obj.Label = translate("Arch", name)
_Project(obj)
if FreeCAD.GuiUp:
_ViewProviderProject(obj.ViewObject)
if sites:
obj.Group = sites
return obj
class _CommandProject:
"the Arch Project command definition"
def GetResources(self):
return {'Pixmap' : 'Arch_Project',
'MenuText': QT_TRANSLATE_NOOP("Arch_Project", "Project"),
'Accel': "P, O",
'ToolTip': QT_TRANSLATE_NOOP("Arch_Project", "Creates a project entity aggregating the selected sites.")}
def IsActive(self):
return not FreeCAD.ActiveDocument is None
def Activated(self):
selection = FreeCADGui.Selection.getSelection()
siteobj = []
for obj in selection:
if hasattr(obj, "IfcType") and obj.IfcType == "Site":
siteobj.append(obj)
ss = "[ "
for o in siteobj:
ss += "FreeCAD.ActiveDocument." + o.Name + ", "
ss += "]"
FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create Project"))
FreeCADGui.addModule("Arch")
FreeCADGui.doCommand("obj = Arch.makeProject("+ss+")")
FreeCADGui.addModule("Draft")
FreeCADGui.doCommand("Draft.autogroup(obj)")
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
class _Project(ArchIFC.IfcContext):
def __init__(self, obj):
obj.Proxy = self
self.setProperties(obj)
obj.IfcType = "Project"
def setProperties(self, obj):
ArchIFC.IfcContext.setProperties(self, obj)
pl = obj.PropertiesList
if not hasattr(obj,"Group"):
obj.addExtension("App::GroupExtensionPython", self)
self.Type = "Project"
def onDocumentRestored(self, obj):
self.setProperties(obj)
class _ViewProviderProject(ArchIFCView.IfcContextView):
def __init__(self,vobj):
vobj.Proxy = self
vobj.addExtension("Gui::ViewProviderGroupExtensionPython", self)
def getIcon(self):
import Arch_rc
return ":/icons/Arch_Project_Tree.svg"
if FreeCAD.GuiUp:
FreeCADGui.addCommand('Arch_Project', _CommandProject())
+1 -1
View File
@@ -298,7 +298,7 @@ def getSVG(section, renderMode="Wireframe", allOn=False, showHidden=False, scale
svgcache += render.getHiddenSVG(linewidth="SVGLINEWIDTH")
svgcache += '</g>\n'
# print(render.info())
section.Proxy.svgcache = [svgcache,renderMode,showHidden,showFill]
section.Proxy.svgcache = [svgcache,renderMode,showHidden,showFill,fillSpaces]
else:
if not svgcache:
+3 -4
View File
@@ -521,7 +521,7 @@ Site creation aborted.") + "\n"
class _Site:
class _Site(ArchIFC.IfcProduct):
"The Site object"
@@ -533,8 +533,7 @@ class _Site:
def setProperties(self,obj):
import ArchIFC
ArchIFC.setProperties(obj)
ArchIFC.IfcProduct.setProperties(self, obj)
pl = obj.PropertiesList
if not "Terrain" in pl:
@@ -638,7 +637,7 @@ class _Site:
def onChanged(self,obj,prop):
ArchIFC.onChanged(obj, prop)
ArchIFC.IfcProduct.onChanged(self, obj, prop)
if prop == "Terrain":
if obj.Terrain:
if FreeCAD.GuiUp:
+5
View File
@@ -896,6 +896,11 @@ class _ViewProviderStructure(ArchComponent.ViewProviderComponent):
def __init__(self,vobj):
ArchComponent.ViewProviderComponent.__init__(self,vobj)
# setProperties of ArchComponent will be overwritten
# thus setProperties from ArchComponent will be explicit called to get the properties
ArchComponent.ViewProviderComponent.setProperties(self, vobj)
self.setProperties(vobj)
vobj.ShapeColor = ArchCommands.getDefaultColor("Structure")
+17 -10
View File
@@ -521,13 +521,13 @@ class _Wall(ArchComponent.Component):
"The Wall object"
def __init__(self,obj):
def __init__(self, obj):
ArchComponent.Component.__init__(self,obj)
ArchComponent.Component.__init__(self, obj)
self.setProperties(obj)
obj.IfcType = "Wall"
def setProperties(self,obj):
def setProperties(self, obj):
lp = obj.PropertiesList
if not "Length" in lp:
@@ -750,12 +750,10 @@ class _Wall(ArchComponent.Component):
obj.Area = obj.Length.Value * obj.Height.Value
def onBeforeChange(self,obj,prop):
if prop == "Length":
self.oldLength = obj.Length.Value
def onChanged(self,obj,prop):
def onChanged(self, obj, prop):
if prop == "Length":
if obj.Base and obj.Length.Value and hasattr(self,"oldLength") and (self.oldLength != None) and (self.oldLength != obj.Length.Value):
if obj.Base.isDerivedFrom("Part::Feature"):
@@ -804,6 +802,8 @@ class _Wall(ArchComponent.Component):
# TODO currently layers were not supported when len(basewires) > 0
width = 0
widths = obj.OverrideWidth
if obj.OverrideWidth:
if obj.OverrideWidth[0]:
width = obj.OverrideWidth[0]
@@ -811,7 +811,7 @@ class _Wall(ArchComponent.Component):
if obj.Width:
width = obj.Width.Value
else:
print("Width or Widths Of Wall [0] should not be 0")
print("Width or OverrideWidth[0] should not be 0")
return
height = obj.Height.Value
@@ -888,9 +888,12 @@ class _Wall(ArchComponent.Component):
if (len(self.basewires) == 1) and layers:
self.basewires = [self.basewires[0] for l in layers]
layeroffset = 0
baseface = None
for i,wire in enumerate(self.basewires):
edgeNum = len(wire.Edges)
e = wire.Edges[0]
if isinstance(e.Curve,Part.Circle):
dvec = e.Vertexes[0].Point.sub(e.Curve.Center)
@@ -911,7 +914,7 @@ class _Wall(ArchComponent.Component):
dvec2 = DraftVecUtils.scaleTo(dvec,off)
wire = DraftGeomUtils.offsetWire(wire,dvec2)
w2 = DraftGeomUtils.offsetWire(wire,dvec,False, False, obj.OverrideWidth)
w2 = DraftGeomUtils.offsetWire(wire,dvec,False, False, widths)
w1 = Part.Wire(Part.__sortEdges__(wire.Edges))
sh = DraftGeomUtils.bind(w1,w2)
@@ -928,7 +931,7 @@ class _Wall(ArchComponent.Component):
dvec2 = DraftVecUtils.scaleTo(dvec,off)
wire = DraftGeomUtils.offsetWire(wire,dvec2)
w2 = DraftGeomUtils.offsetWire(wire,dvec,False, False, obj.OverrideWidth)
w2 = DraftGeomUtils.offsetWire(wire,dvec,False, False, widths)
w1 = Part.Wire(Part.__sortEdges__(wire.Edges))
sh = DraftGeomUtils.bind(w1,w2)
@@ -944,12 +947,16 @@ class _Wall(ArchComponent.Component):
else:
dvec.multiply(width/2) ## TODO width Value should be of no use (width/2), width Direction remains 'in use'
overrideWidthHalfen = [i/2 for i in obj.OverrideWidth]
overrideWidthHalfen = [i/2 for i in widths]
w1 = DraftGeomUtils.offsetWire(wire,dvec,False, False, overrideWidthHalfen)
dvec = dvec.negative()
w2 = DraftGeomUtils.offsetWire(wire,dvec,False, False, overrideWidthHalfen)
sh = DraftGeomUtils.bind(w1,w2)
del widths[0:edgeNum]
if sh:
sh.fix(0.1,0,1) # fixes self-intersecting wires
f = Part.Face(sh)
+5
View File
@@ -7,10 +7,14 @@ SET(Arch_SRCS
InitGui.py
ArchComponent.py
ArchIFC.py
ArchIFCView.py
ArchIFCSchema.py
ArchProject.py
ArchWall.py
importIFC.py
importIFClegacy.py
importIFCHelper.py
exportIFCHelper.py
Arch.py
ArchBuilding.py
ArchFloor.py
@@ -62,6 +66,7 @@ SET(Arch_presets
Presets/ifc_products_IFC4.json
Presets/ifc_types_IFC2X3.json
Presets/ifc_types_IFC4.json
Presets/ifc_contexts_IFC4.json
)
SOURCE_GROUP("" FILES ${Arch_SRCS})
+1 -4
View File
@@ -34,7 +34,7 @@ class ArchWorkbench(Workbench):
# arch tools
self.archtools = ["Arch_Wall","Arch_Structure","Arch_Rebar","Arch_BuildingPart",
"Arch_Floor","Arch_Building","Arch_Site","Arch_Reference",
"Arch_Project", "Arch_Site", "Arch_Building", "Arch_Floor", "Arch_Reference",
"Arch_Window","Arch_Roof","Arch_AxisTools",
"Arch_SectionPlane","Arch_Space","Arch_Stairs",
"Arch_PanelTools","Arch_Equipment",
@@ -64,9 +64,6 @@ class ArchWorkbench(Workbench):
FreeCADGui.addCommand('Arch_RebarTools', RebarGroupCommand())
self.archtools[2] = "Arch_RebarTools"
# setup Draft_Edit command
import DraftEdit
FreeCADGui.addCommand('Draft_Edit',DraftEdit.Edit())
# draft tools
self.drafttools = ["Draft_Line","Draft_Wire","Draft_Circle","Draft_Arc","Draft_Ellipse",
+146
View File
@@ -0,0 +1,146 @@
{
"IfcProject": {
"is_abstract": false,
"parent": "IfcContext",
"attributes": [
{
"name": "GlobalId",
"type": "IfcGloballyUniqueId",
"is_enum": false,
"enum_values": []
},
{
"name": "Name",
"type": "IfcLabel",
"is_enum": false,
"enum_values": []
},
{
"name": "Description",
"type": "IfcText",
"is_enum": false,
"enum_values": []
},
{
"name": "ObjectType",
"type": "IfcLabel",
"is_enum": false,
"enum_values": []
},
{
"name": "LongName",
"type": "IfcLabel",
"is_enum": false,
"enum_values": []
},
{
"name": "Phase",
"type": "IfcLabel",
"is_enum": false,
"enum_values": []
}
],
"complex_attributes": [
{
"name": "OwnerHistory",
"type": "IfcOwnerHistory"
},
{
"name": "IsNestedBy",
"type": "IfcRelNests"
},
{
"name": "IsDecomposedBy",
"type": "IfcRelAggregates"
},
{
"name": "RepresentationContexts",
"type": "IfcRepresentationContext"
},
{
"name": "UnitsInContext",
"type": "IfcUnitAssignment"
},
{
"name": "IsDefinedBy",
"type": "IfcRelDefinesByProperties"
},
{
"name": "Declares",
"type": "IfcRelDeclares"
}
]
},
"IfcProjectLibrary": {
"is_abstract": false,
"parent": "IfcContext",
"attributes": [
{
"name": "GlobalId",
"type": "IfcGloballyUniqueId",
"is_enum": false,
"enum_values": []
},
{
"name": "Name",
"type": "IfcLabel",
"is_enum": false,
"enum_values": []
},
{
"name": "Description",
"type": "IfcText",
"is_enum": false,
"enum_values": []
},
{
"name": "ObjectType",
"type": "IfcLabel",
"is_enum": false,
"enum_values": []
},
{
"name": "LongName",
"type": "IfcLabel",
"is_enum": false,
"enum_values": []
},
{
"name": "Phase",
"type": "IfcLabel",
"is_enum": false,
"enum_values": []
}
],
"complex_attributes": [
{
"name": "OwnerHistory",
"type": "IfcOwnerHistory"
},
{
"name": "IsNestedBy",
"type": "IfcRelNests"
},
{
"name": "IsDecomposedBy",
"type": "IfcRelAggregates"
},
{
"name": "RepresentationContexts",
"type": "IfcRepresentationContext"
},
{
"name": "UnitsInContext",
"type": "IfcUnitAssignment"
},
{
"name": "IsDefinedBy",
"type": "IfcRelDefinesByProperties"
},
{
"name": "Declares",
"type": "IfcRelDeclares"
}
]
}
}
File diff suppressed because it is too large Load Diff
+2
View File
@@ -5,6 +5,7 @@
<file>icons/Arch_Cell.svg</file>
<file>icons/Arch_Wall.svg</file>
<file>icons/Arch_Site.svg</file>
<file>icons/Arch_Project.svg</file>
<file>icons/Arch_Structure.svg</file>
<file>icons/Arch_Add.svg</file>
<file>icons/Arch_Remove.svg</file>
@@ -21,6 +22,7 @@
<file>icons/Arch_Floor_Tree.svg</file>
<file>icons/Arch_SectionPlane_Tree.svg</file>
<file>icons/Arch_Site_Tree.svg</file>
<file>icons/Arch_Project_Tree.svg</file>
<file>icons/Arch_Structure_Tree.svg</file>
<file>icons/Arch_Structure_Clone.svg</file>
<file>icons/Arch_Window_Tree.svg</file>
@@ -0,0 +1,423 @@
<?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="svg2980"
sodipodi:version="0.32"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="ifc_project_icon.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<title
id="title4553">ifc_project_icon</title>
<defs
id="defs2982">
<linearGradient
inkscape:collect="always"
id="linearGradient1491">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop1487" />
<stop
style="stop-color:#fce94f;stop-opacity:1"
offset="1"
id="stop1489" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient1460">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop1456" />
<stop
style="stop-color:#fce94f;stop-opacity:1"
offset="1"
id="stop1458" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient1452">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop1448" />
<stop
style="stop-color:#fce94f;stop-opacity:1"
offset="1"
id="stop1450" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient1371">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop1367" />
<stop
style="stop-color:#fce94f;stop-opacity:1"
offset="1"
id="stop1369" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient1212">
<stop
style="stop-color:#9f8201;stop-opacity:1"
offset="0"
id="stop1208" />
<stop
style="stop-color:#fce94f;stop-opacity:1"
offset="1"
id="stop1210" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient966">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop962" />
<stop
style="stop-color:#fce94f;stop-opacity:1"
offset="1"
id="stop964" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient958">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop954" />
<stop
style="stop-color:#fce94f;stop-opacity:1"
offset="1"
id="stop956" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient1584">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop1580" />
<stop
style="stop-color:#fce94f;stop-opacity:1"
offset="1"
id="stop1582" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient3794">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop3796" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop3798" />
</linearGradient>
<linearGradient
id="linearGradient3864">
<stop
id="stop3866"
offset="0"
style="stop-color:#71b2f8;stop-opacity:1;" />
<stop
id="stop3868"
offset="1"
style="stop-color:#002795;stop-opacity:1;" />
</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="perspective2988" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3794"
id="radialGradient3800"
cx="1"
cy="45"
fx="1"
fy="45"
r="41"
gradientTransform="matrix(0.93348213,-2.2905276e-8,0,0.28687573,0.06651751,32.090592)"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1584"
id="linearGradient1586"
x1="19.742287"
y1="29.617214"
x2="16.630623"
y2="5.6647563"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient958"
id="linearGradient960"
x1="42.720432"
y1="35.358803"
x2="38.797985"
y2="12.301081"
gradientUnits="userSpaceOnUse"
gradientTransform="rotate(29.953188,22.410187,2.0303151)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient966"
id="linearGradient968"
x1="38.753258"
y1="11.986131"
x2="36.959591"
y2="4.3561206"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.86036595,0.4957957,-0.65446032,1.1357004,4.8924107,-11.874215)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient958"
id="linearGradient1017"
gradientUnits="userSpaceOnUse"
gradientTransform="rotate(29.953188,22.410187,2.0303151)"
x1="42.720432"
y1="35.358803"
x2="38.797985"
y2="12.301081" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1212"
id="linearGradient1214"
x1="35.502228"
y1="43.943478"
x2="25.338087"
y2="20.853832"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1371"
id="linearGradient1373"
x1="103.49044"
y1="57.973423"
x2="91.800392"
y2="9.8313513"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1371"
id="linearGradient1403"
gradientUnits="userSpaceOnUse"
x1="106.64566"
y1="32.015091"
x2="83.025734"
y2="16.70879"
gradientTransform="matrix(0.71299585,0,0,0.71299585,-38.159919,7.6652554)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1452"
id="linearGradient1454"
x1="25.694189"
y1="41.841251"
x2="17.957205"
y2="35.542679"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1460"
id="linearGradient1462"
x1="29.591785"
y1="38.03183"
x2="28.189938"
y2="32.499073"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1491"
id="linearGradient1493"
x1="35.284328"
y1="12.935562"
x2="29.851774"
y2="10.693736"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.9632948"
inkscape:cx="13.992731"
inkscape:cy="39.787963"
inkscape:current-layer="g1015"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="1051"
inkscape:window-x="1791"
inkscape:window-y="-9"
inkscape:snap-bbox="true"
inkscape:snap-nodes="false"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid2991"
empspacing="2"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata2985">
<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>ifc_project_icon</dc:title>
<dc:creator>
<cc:Agent>
<dc:title>[bitacovir] Rafael Moya</dc:title>
</cc:Agent>
</dc:creator>
<dc:title>Part_Box</dc:title>
<dc:date>2019-06-16</dc:date>
<dc:relation />
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier />
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license
rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/">https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:contributor>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/publicdomain/zero/1.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
</cc:License>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g1015"
transform="matrix(1.4025327,0,0,1.4025327,-12.5084,-9.9751934)">
<path
style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.16908914;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
d="M 33.762019,29.98086 C 25.043358,23.889681 17.89608,18.865025 17.879176,18.814958 c -0.01691,-0.05007 0.197559,-0.313039 0.476582,-0.584381 0.878355,-0.854175 1.765285,-1.182233 3.196257,-1.182233 1.536913,0 2.775433,0.302228 5.677307,1.385393 2.559942,0.955533 3.863647,1.258501 6.105455,1.418843 l 1.314957,0.09405 0.676355,0.42569 c 0.371999,0.23413 1.950871,1.249591 3.508603,2.256581 1.557732,1.006989 3.139841,2.027163 3.515804,2.267053 0.407256,0.259862 0.727776,0.530464 0.792951,0.669459 0.06018,0.128313 0.373111,0.88006 0.695442,1.670552 0.928392,2.276847 1.391575,2.997958 3.059536,4.763285 2.162232,2.288437 3.252103,3.90544 3.639217,5.399359 0.200416,0.773427 0.172894,1.821207 -0.06289,2.394268 -0.197991,0.481212 -0.696176,1.267387 -0.801293,1.264491 -0.03265,-9.27e-4 -7.192795,-4.985328 -15.91145,-11.076508 z"
id="path1108"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="fill:url(#linearGradient1403);fill-opacity:1;stroke:#302b00;stroke-width:1.42599171;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 27.079201,14.206157 c -7.3491,5.068907 -9.808395,11.28394 -10.687974,17.868066 v 11.101568 l 31.24788,-0.190782 0.05433,-10.910786 c 0.06718,-7.621033 -5.002286,-12.874 -10.632294,-17.868066 z m 20.509768,28.922286 -31.112796,0.126725 -4.733346,3.761331 0.04177,3.636001 h 40.497334 v -3.889448 z"
id="path1265-5" />
<path
style="fill:url(#linearGradient1493);stroke:#302b00;stroke-width:1.42599165;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
d="m 27.239239,13.981979 c 1.23915,-5.8754621 8.21462,-5.4405771 9.55166,0 z"
id="path1220-87"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<rect
style="opacity:1;fill:url(#linearGradient1454);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.62589371;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="rect1431"
width="9.002841"
height="10.222729"
x="17.366549"
y="32.418114" />
<path
style="fill:none;stroke:#fce94f;stroke-width:1.42599165;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 27.725189,15.641754 8.81324,0.003 c 6.940872,5.302711 9.686672,11.546987 9.674182,15.867818 l 0.01925,12.395919 4.609275,3.539053 0.0095,1.787896 -37.693861,-0.0023 0.0049,-1.597929 4.64051,-3.599752 0.113104,-12.478863 c 0.96778,-6.426734 3.59727,-11.70258 9.567,-15.618951 z"
id="path1216-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccc" />
<rect
style="opacity:1;fill:url(#linearGradient1462);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.75087309;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="rect1431-2"
width="10.440099"
height="10.222729"
x="26.796108"
y="32.629475" />
<path
style="fill:none;stroke:#302b00;stroke-width:1.42599165;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 16.575149,32.276223 h 31.07164"
id="path1196-4"
inkscape:connector-curvature="0" />
<circle
style="opacity:1;fill:#302b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.07927084;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="path1242-1"
cx="21.528547"
cy="37.260105"
r="2.6079915" />
<circle
style="opacity:1;fill:#302b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.07927084;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="path1242-8-2"
cx="32.098705"
cy="37.294384"
r="2.6079915" />
<circle
style="opacity:1;fill:#302b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.07927084;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="path1242-3-4"
cx="42.29948"
cy="37.32428"
r="2.6079915" />
<path
style="fill:none;stroke:#302b00;stroke-width:1.84060574;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 16.30258,43.183831 H 47.823829"
id="path1196-4-2"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#fce94f;stroke-width:1.3768388;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 17.506414,30.800931 H 46.472936"
id="path1196-4-9"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#302b00;stroke-width:1.42599165;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 31.382129,14.083052 c -3.13613,4.970362 -4.81717,10.954296 -4.98681,17.991026 v 10.781139"
id="path1192-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;stroke:#302b00;stroke-width:1.42599165;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 33.300129,14.150434 c 2.58579,5.068087 4.38829,10.79545 4.52649,17.923644 l -0.15344,10.781139"
id="path1194-4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

@@ -0,0 +1,435 @@
<?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="svg2980"
sodipodi:version="0.32"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="ifc_Project_Tree.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<title
id="title4553">ifc_project_tree</title>
<defs
id="defs2982">
<linearGradient
inkscape:collect="always"
id="linearGradient904">
<stop
style="stop-color:#babdb6;stop-opacity:1"
offset="0"
id="stop900" />
<stop
style="stop-color:#ffffff;stop-opacity:1"
offset="1"
id="stop902" />
</linearGradient>
<linearGradient
id="linearGradient896"
inkscape:collect="always">
<stop
id="stop892"
offset="0"
style="stop-color:#888a85;stop-opacity:1" />
<stop
id="stop894"
offset="1"
style="stop-color:#ffffff;stop-opacity:1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient1460">
<stop
style="stop-color:#888a85;stop-opacity:1"
offset="0"
id="stop1456" />
<stop
style="stop-color:#d3d7cf;stop-opacity:1"
offset="1"
id="stop1458" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient1452">
<stop
style="stop-color:#888a85;stop-opacity:1"
offset="0"
id="stop1448" />
<stop
style="stop-color:#ffffff;stop-opacity:1"
offset="1"
id="stop1450" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient1371">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop1367" />
<stop
style="stop-color:#fce94f;stop-opacity:1"
offset="1"
id="stop1369" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient1212">
<stop
style="stop-color:#9f8201;stop-opacity:1"
offset="0"
id="stop1208" />
<stop
style="stop-color:#fce94f;stop-opacity:1"
offset="1"
id="stop1210" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient966">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop962" />
<stop
style="stop-color:#fce94f;stop-opacity:1"
offset="1"
id="stop964" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient958">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop954" />
<stop
style="stop-color:#fce94f;stop-opacity:1"
offset="1"
id="stop956" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient1584">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop1580" />
<stop
style="stop-color:#fce94f;stop-opacity:1"
offset="1"
id="stop1582" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient3794">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop3796" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop3798" />
</linearGradient>
<linearGradient
id="linearGradient3864">
<stop
id="stop3866"
offset="0"
style="stop-color:#71b2f8;stop-opacity:1;" />
<stop
id="stop3868"
offset="1"
style="stop-color:#002795;stop-opacity:1;" />
</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="perspective2988" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3794"
id="radialGradient3800"
cx="1"
cy="45"
fx="1"
fy="45"
r="41"
gradientTransform="matrix(0.93348213,-2.2905276e-8,0,0.28687573,0.06651751,32.090592)"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1584"
id="linearGradient1586"
x1="19.742287"
y1="29.617214"
x2="16.630623"
y2="5.6647563"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient958"
id="linearGradient960"
x1="42.720432"
y1="35.358803"
x2="38.797985"
y2="12.301081"
gradientUnits="userSpaceOnUse"
gradientTransform="rotate(29.953188,22.410187,2.0303151)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient966"
id="linearGradient968"
x1="38.753258"
y1="11.986131"
x2="36.959591"
y2="4.3561206"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.86036595,0.4957957,-0.65446032,1.1357004,4.8924107,-11.874215)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient958"
id="linearGradient1017"
gradientUnits="userSpaceOnUse"
gradientTransform="rotate(29.953188,22.410187,2.0303151)"
x1="42.720432"
y1="35.358803"
x2="38.797985"
y2="12.301081" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1212"
id="linearGradient1214"
x1="35.502228"
y1="43.943478"
x2="25.338087"
y2="20.853832"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1371"
id="linearGradient1373"
x1="103.49044"
y1="57.973423"
x2="91.800392"
y2="9.8313513"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient896"
id="linearGradient1403"
gradientUnits="userSpaceOnUse"
x1="106.64566"
y1="32.015091"
x2="80.061317"
y2="27.380676"
gradientTransform="matrix(0.71299585,0,0,0.71299585,-38.159919,7.6652554)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1452"
id="linearGradient1454"
x1="25.947823"
y1="40.234905"
x2="17.87266"
y2="37.06448"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1460"
id="linearGradient1462"
x1="33.903557"
y1="37.440018"
x2="28.189938"
y2="32.499073"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient904"
id="linearGradient906"
x1="34.81163"
y1="13.296743"
x2="30.571222"
y2="11.436762"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="8.4333724"
inkscape:cx="5.7127805"
inkscape:cy="30.61729"
inkscape:current-layer="g1015"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="1051"
inkscape:window-x="1791"
inkscape:window-y="-9"
inkscape:snap-bbox="true"
inkscape:snap-nodes="false"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid2991"
empspacing="2"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata2985">
<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>ifc_project_tree</dc:title>
<dc:creator>
<cc:Agent>
<dc:title>[bitacovir] Rafael Moya</dc:title>
</cc:Agent>
</dc:creator>
<dc:title>Part_Box</dc:title>
<dc:date>2019-06-16</dc:date>
<dc:relation />
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier />
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license
rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/">https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title></dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/publicdomain/zero/1.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
</cc:License>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g1015"
transform="matrix(1.4025327,0,0,1.4025327,-12.5084,-9.9751934)">
<path
style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.16908914;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
d="M 33.762019,29.98086 C 25.043358,23.889681 17.89608,18.865025 17.879176,18.814958 c -0.01691,-0.05007 0.197559,-0.313039 0.476582,-0.584381 0.878355,-0.854175 1.765285,-1.182233 3.196257,-1.182233 1.536913,0 2.775433,0.302228 5.677307,1.385393 2.559942,0.955533 3.863647,1.258501 6.105455,1.418843 l 1.314957,0.09405 0.676355,0.42569 c 0.371999,0.23413 1.950871,1.249591 3.508603,2.256581 1.557732,1.006989 3.139841,2.027163 3.515804,2.267053 0.407256,0.259862 0.727776,0.530464 0.792951,0.669459 0.06018,0.128313 0.373111,0.88006 0.695442,1.670552 0.928392,2.276847 1.391575,2.997958 3.059536,4.763285 2.162232,2.288437 3.252103,3.90544 3.639217,5.399359 0.200416,0.773427 0.172894,1.821207 -0.06289,2.394268 -0.197991,0.481212 -0.696176,1.267387 -0.801293,1.264491 -0.03265,-9.27e-4 -7.192795,-4.985328 -15.91145,-11.076508 z"
id="path1108"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="fill:url(#linearGradient1403);fill-opacity:1;stroke:#2e3436;stroke-width:1.42599171;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 27.079201,14.206157 c -7.3491,5.068907 -9.808395,11.28394 -10.687974,17.868066 v 11.101568 l 31.24788,-0.190782 0.05433,-10.910786 c 0.06718,-7.621033 -5.002286,-12.874 -10.632294,-17.868066 z m 20.509768,28.922286 -31.112796,0.126725 -4.733346,3.761331 0.04177,3.636001 h 40.497334 v -3.889448 z"
id="path1265-5" />
<path
style="fill:url(#linearGradient906);stroke:#2e3436;stroke-width:1.42599165;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
d="m 27.239239,13.981979 c 1.23915,-5.8754621 8.21462,-5.4405771 9.55166,0 z"
id="path1220-87"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<rect
style="opacity:1;fill:url(#linearGradient1454);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.62589371;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="rect1431"
width="9.002841"
height="10.222729"
x="17.366549"
y="32.418114" />
<path
style="fill:none;stroke:#ffffff;stroke-width:1.42599165;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 27.725189,15.641754 8.81324,0.003 c 6.940872,5.302711 9.686672,11.546987 9.674182,15.867818 l 0.01925,12.395919 4.609275,3.539053 0.0095,1.787896 -37.693861,-0.0023 0.0049,-1.597929 4.64051,-3.599752 0.113104,-12.478863 c 0.96778,-6.426734 3.59727,-11.70258 9.567,-15.618951 z"
id="path1216-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccc" />
<rect
style="opacity:1;fill:url(#linearGradient1462);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.75087309;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="rect1431-2"
width="10.440099"
height="10.222729"
x="26.796108"
y="32.629475" />
<circle
style="opacity:1;fill:#2e3436;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.07927084;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="path1242-1"
cx="21.528547"
cy="37.260105"
r="2.6079915" />
<circle
style="opacity:1;fill:#2e3436;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.07927084;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="path1242-8-2"
cx="32.098705"
cy="37.294384"
r="2.6079915" />
<circle
style="opacity:1;fill:#2e3436;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.07927084;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="path1242-3-4"
cx="42.29948"
cy="37.32428"
r="2.6079915" />
<path
style="fill:none;stroke:#ffffff;stroke-width:1.3768388;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 17.506414,30.800931 H 46.472936"
id="path1196-4-9"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#2e3436;stroke-width:1.42599165;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 31.382129,14.083052 c -3.13613,4.970362 -4.81717,10.954296 -4.98681,17.991026 v 10.781139"
id="path1192-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;stroke:#2e3436;stroke-width:1.42599165;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 33.300129,14.150434 c 2.58579,5.068087 4.38829,10.79545 4.52649,17.923644 l -0.15344,10.781139"
id="path1194-4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;stroke:#2e3436;stroke-width:1.42599165;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 16.575149,32.276223 h 31.07164"
id="path1196-4"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#2e3436;stroke-width:1.85104859;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 16.30258,43.183831 H 48.182521"
id="path1196-4-2"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

+14 -1
View File
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>446</width>
<height>792</height>
<height>811</height>
</rect>
</property>
<property name="windowTitle">
@@ -217,6 +217,19 @@
</property>
</widget>
</item>
<item>
<widget class="Gui::PrefCheckBox" name="checkBox_6">
<property name="toolTip">
<string>If this is checked, when an Arch object has a material, the object will take the color of the material. This can be overridden for each object.</string>
</property>
<property name="text">
<string>Use material color as shape color</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
+15 -12
View File
@@ -43,6 +43,7 @@ from DraftGeomUtils import vec
from importIFC import recycler
from importIFC import dd2dms
from importIFC import decode
import exportIFCHelper
## @package exportIFC
@@ -94,7 +95,6 @@ DATA;
#8=IFCCARTESIANPOINT((0.,0.,0.));
#9=IFCAXIS2PLACEMENT3D(#8,#7,#6);
#10=IFCDIRECTION((0.,1.,0.));
#11=IFCGEOMETRICREPRESENTATIONCONTEXT('Plan','Model',3,1.E-05,#9,#10);
#12=IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0);
#13=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.);
#14=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.);
@@ -103,7 +103,6 @@ DATA;
#17=IFCMEASUREWITHUNIT(IFCPLANEANGLEMEASURE(0.017453292519943295),#16);
#18=IFCCONVERSIONBASEDUNIT(#12,.PLANEANGLEUNIT.,'DEGREE',#17);
#19=IFCUNITASSIGNMENT((#13,#14,#15,#18));
#20=IFCPROJECT('$projectid',#5,'$project',$,$,$,$,(#11),#19);
ENDSEC;
END-ISO-10303-21;
"""
@@ -111,7 +110,7 @@ END-ISO-10303-21;
# ************************************************************************************************
# ********** duplicate methods ****************
# TODO red rid of this duplicate
# TODO get rid of this duplicate
def getPreferences():
@@ -196,8 +195,6 @@ def export(exportList,filename,colors=None):
template = template.replace("$company",FreeCAD.ActiveDocument.Company)
template = template.replace("$email",email)
template = template.replace("$now",str(int(time.time())))
template = template.replace("$projectid",FreeCAD.ActiveDocument.Uid[:22].replace("-","_"))
template = template.replace("$project",FreeCAD.ActiveDocument.Name)
template = template.replace("$filename",os.path.basename(filename))
template = template.replace("$timestamp",str(time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime())))
if hasattr(ifcopenshell,"version"):
@@ -212,12 +209,7 @@ def export(exportList,filename,colors=None):
global ifcfile, surfstyles, clones, sharedobjects, profiledefs, shapedefs
ifcfile = ifcopenshell.open(templatefile)
history = ifcfile.by_type("IfcOwnerHistory")[0]
context = ifcfile.by_type("IfcGeometricRepresentationContext")[0]
project = ifcfile.by_type("IfcProject")[0]
objectslist = Draft.getGroupContents(exportList,walls=True,addgroups=True)
if(Draft.getObjectsOfType(objectslist, "Site")): # we assume one site and one representation context only
trueNorthX = math.tan(-Draft.getObjectsOfType(objectslist, "Site")[0].Declination.getValueAs(FreeCAD.Units.Radian))
context.TrueNorth.DirectionRatios = (trueNorthX, 1., 1.)
annotations = []
for obj in objectslist:
if obj.isDerivedFrom("Part::Part2DObject"):
@@ -234,6 +226,16 @@ def export(exportList,filename,colors=None):
objectslist = [obj for obj in objectslist if Draft.getType(obj) not in ["Dimension","Material","MaterialContainer","WorkingPlaneProxy"]]
if FULL_PARAMETRIC:
objectslist = Arch.getAllChildren(objectslist)
contextCreator = exportIFCHelper.ContextCreator(ifcfile, objectslist)
context = contextCreator.model_view_subcontext
project = contextCreator.project
objectslist = [obj for obj in objectslist if obj != contextCreator.project_object]
if Draft.getObjectsOfType(objectslist, "Site"): # we assume one site and one representation context only
trueNorthX = math.tan(-Draft.getObjectsOfType(objectslist, "Site")[0].Declination.getValueAs(FreeCAD.Units.Radian))
contextCreator.model_context.TrueNorth.DirectionRatios = (trueNorthX, 1., 1.)
products = {} # { Name: IfcEntity, ... }
subproducts = {} # { Name: IfcEntity, ... } for storing additions/subtractions and other types of subcomponents of a product
surfstyles = {} # { (r,g,b): IfcEntity, ... }
@@ -262,6 +264,7 @@ def export(exportList,filename,colors=None):
#print(objectslist)
# testing if more than one site selected (forbidden in IFC)
# TODO: Moult: This is not forbidden in IFC.
if len(Draft.getObjectsOfType(objectslist,"Site")) > 1:
FreeCAD.Console.PrintError("More than one site is selected, which is forbidden by IFC standards. Please export only one site by IFC file.\n")
@@ -593,7 +596,7 @@ def export(exportList,filename,colors=None):
#if DEBUG : print(" adding ifc attributes")
props = []
for key in obj.IfcData:
if not (key in ["attributes","IfcUID","FlagForceBrep"]):
if not (key in ["attributes", "complex_attributes", "IfcUID", "FlagForceBrep"]):
# (deprecated) properties in IfcData dict are stored as "key":"type(value)"
@@ -872,7 +875,7 @@ def export(exportList,filename,colors=None):
# sites
for site in Draft.getObjectsOfType(objectslist,"Site"):
for site in exportIFCHelper.getObjectsOfIfcType(objectslist, "Site"):
objs = Draft.getGroupContents(site,walls=True,addgroups=True)
objs = Arch.pruneIncluded(objs)
children = []
+141
View File
@@ -0,0 +1,141 @@
import FreeCAD, Draft, json, ifcopenshell, math
def getObjectsOfIfcType(objects, ifcType):
results = []
for object in objects:
if hasattr(object,"IfcType"):
if object.IfcType == ifcType:
results.append(object)
return results
class SIUnitCreator:
def __init__(self, file, text, type):
self.prefixes = ["EXA", "PETA", "TERA", "GIGA", "MEGA", "KILO", "HECTO",
"DECA", "DECI", "CENTI", "MILLI", "MICRO", "NANO", "PICO", "FEMTO",
"ATTO"]
self.unitNames = ["AMPERE", "BECQUEREL", "CANDELA", "COULOMB",
"CUBIC_METRE", "DEGREE CELSIUS", "FARAD", "GRAM", "GRAY", "HENRY",
"HERTZ", "JOULE", "KELVIN", "LUMEN", "LUX", "MOLE", "NEWTON", "OHM",
"PASCAL", "RADIAN", "SECOND", "SIEMENS", "SIEVERT", "SQUARE METRE",
"METRE", "STERADIAN", "TESLA", "VOLT", "WATT", "WEBER"]
self.text = text
self.SIUnit = file.createIfcSIUnit(None, type, self.getSIPrefix(), self.getSIUnitName())
def getSIPrefix(self):
for prefix in self.prefixes:
if prefix in self.text.upper():
return prefix
return None
def getSIUnitName(self):
for unitName in self.unitNames:
if unitName in self.text.upper():
return unitName
return None
class ContextCreator:
def __init__(self, file, objects):
self.file = file
self.objects = objects
self.project_object = self.getProjectObject()
self.project_data = self.getProjectObjectData()
self.model_context = self.createGeometricRepresentationContext()
self.model_view_subcontext = self.createGeometricRepresentationSubContext()
self.target_crs = self.createTargetCRS()
self.map_conversion = self.createMapConversion()
self.project = self.createProject()
def createGeometricRepresentationContext(self):
return self.file.createIfcGeometricRepresentationContext(
None, "Model",
3, 1.0E-05,
self.file.by_type("IfcAxis2Placement3D")[0],
self.createTrueNorth())
def createGeometricRepresentationSubContext(self):
return self.file.createIfcGeometricRepresentationSubContext(
"Body", "Model",
None, None, None, None,
self.model_context, None, "MODEL_VIEW", None)
def createTargetCRS(self):
try:
SIUnit = SIUnitCreator(self.file, self.project_data["map_unit"], "LENGTHUNIT")
return self.file.createIfcProjectedCRS(
self.project_data["name"],
self.project_data["description"],
self.project_data["geodetic_datum"],
self.project_data["vertical_datum"],
self.project_data["map_projection"],
self.project_data["map_zone"],
SIUnit.SIUnit
)
except:
return None
def createMapConversion(self):
try:
return self.file.createIfcMapConversion(
self.model_context, self.target_crs,
float(self.project_data["eastings"]),
float(self.project_data["northings"]),
float(self.project_data["orthogonal_height"]),
self.calculateXAxisAbscissa(),
self.calculateXAxisOrdinate(),
float(self.project_data["scale"])
)
except:
return None
def createTrueNorth(self):
return self.file.createIfcDirection(
(self.calculateXAxisAbscissa(), self.calculateXAxisOrdinate(), 0.))
def calculateXAxisAbscissa(self):
if "true_north" in self.project_data:
return math.cos(math.radians(float(self.project_data["true_north"]) + 90))
return 0.
def calculateXAxisOrdinate(self):
if "true_north" in self.project_data:
return math.sin(math.radians(float(self.project_data["true_north"]) + 90))
return 1.
def createProject(self):
if not self.project_object:
return self.createAutomaticProject()
return self.createCustomProject()
def createAutomaticProject(self):
return self.file.createIfcProject(
self.getProjectGUID(),
self.file.by_type("IfcOwnerHistory")[0],
FreeCAD.ActiveDocument.Name, None,
None, None, None, [self.model_context],
self.file.by_type("IfcUnitAssignment")[0])
def createCustomProject(self):
return self.file.createIfcProject(
self.getProjectGUID(),
self.file.by_type("IfcOwnerHistory")[0],
self.project_object.Label, self.project_object.Description,
self.project_object.ObjectType, self.project_object.LongName,
self.project_object.Phase,
[self.model_context],
self.file.by_type("IfcUnitAssignment")[0])
def getProjectGUID(self):
# TODO: Do not generate a new one each time, but at least this one
# conforms to the community consensus on how a GUID is generated.
return ifcopenshell.guid.new()
def getProjectObject(self):
try:
return getObjectsOfIfcType(self.objects, "Project")[0]
except:
return None
def getProjectObjectData(self):
if not self.project_object:
return {}
return json.loads(self.project_object.IfcData['complex_attributes'])["RepresentationContexts"]
+78 -68
View File
@@ -38,6 +38,7 @@ import Draft
import Arch
import DraftVecUtils
import ArchIFCSchema
import importIFCHelper
## @package importIFC
# \ingroup ARCH
@@ -173,7 +174,7 @@ def dms2dd(degrees, minutes, seconds, milliseconds=0):
# ************************************************************************************************
# ********** duplicate methods ****************
# TODO red rid of this duplicate
# TODO get rid of this duplicate
def getPreferences():
"""retrieves IFC preferences"""
@@ -403,6 +404,9 @@ def insert(filename,docname,skip=[],only=[],root=None):
import FreeCADGui
FreeCADGui.ActiveDocument.activeView().viewAxonometric()
projectImporter = importIFCHelper.ProjectImporter(ifcfile, objects)
projectImporter.execute()
# handle IFC products
for product in products:
@@ -623,53 +627,55 @@ def insert(filename,docname,skip=[],only=[],root=None):
# full Arch objects
for freecadtype,ifctypes in typesmap.items():
if ptype in ifctypes:
if clone:
obj = getattr(Arch,"make"+freecadtype)(name=name)
obj.CloneOf = clone
if shape:
if shape.Solids:
s1 = shape.Solids[0]
else:
s1 = shape
if clone.Shape.Solids:
s2 = clone.Shape.Solids[0]
else:
s1 = clone.Shape
if hasattr(s1,"CenterOfMass") and hasattr(s2,"CenterOfMass"):
v = s1.CenterOfMass.sub(s2.CenterOfMass)
if product.Representation:
r = getRotation(product.Representation.Representations[0].Items[0].MappingTarget)
if not r.isNull():
v = v.add(s2.CenterOfMass)
v = v.add(r.multVec(s2.CenterOfMass.negative()))
obj.Placement.Rotation = r
obj.Placement.move(v)
else:
print("failed to compute placement ",)
else:
obj = getattr(Arch,"make"+freecadtype)(baseobj=baseobj,name=name)
if freecadtype in ["Wall","Structure"] and baseobj and baseobj.isDerivedFrom("Part::Extrusion"):
# remove intermediary extrusion for types that can extrude themselves
obj.Base = baseobj.Base
obj.Placement = obj.Placement.multiply(baseobj.Placement)
obj.Height = baseobj.Dir.Length
obj.Normal = FreeCAD.Vector(baseobj.Dir).normalize()
bn = baseobj.Name
FreeCAD.ActiveDocument.removeObject(bn)
if (freecadtype in ["Structure","Wall"]) and not baseobj:
# remove sizes to prevent auto shape creation for types that don't require a base object
obj.Height = 0
obj.Width = 0
obj.Length = 0
if store:
sharedobjects[store] = obj
if ptype == "IfcBuildingStorey":
if product.Elevation:
obj.Placement.Base.z = product.Elevation * getScaling(ifcfile)
if ptype not in ifctypes:
continue
if clone:
obj = getattr(Arch,"make"+freecadtype)(name=name)
obj.CloneOf = clone
if shape:
if shape.Solids:
s1 = shape.Solids[0]
else:
s1 = shape
if clone.Shape.Solids:
s2 = clone.Shape.Solids[0]
else:
s1 = clone.Shape
if hasattr(s1,"CenterOfMass") and hasattr(s2,"CenterOfMass"):
v = s1.CenterOfMass.sub(s2.CenterOfMass)
if product.Representation:
r = getRotation(product.Representation.Representations[0].Items[0].MappingTarget)
if not r.isNull():
v = v.add(s2.CenterOfMass)
v = v.add(r.multVec(s2.CenterOfMass.negative()))
obj.Placement.Rotation = r
obj.Placement.move(v)
else:
print("failed to compute placement ",)
else:
obj = getattr(Arch,"make"+freecadtype)(baseobj=baseobj,name=name)
if freecadtype in ["Wall","Structure"] and baseobj and baseobj.isDerivedFrom("Part::Extrusion"):
# remove intermediary extrusion for types that can extrude themselves
obj.Base = baseobj.Base
obj.Placement = obj.Placement.multiply(baseobj.Placement)
obj.Height = baseobj.Dir.Length
obj.Normal = FreeCAD.Vector(baseobj.Dir).normalize()
bn = baseobj.Name
FreeCAD.ActiveDocument.removeObject(bn)
if (freecadtype in ["Structure","Wall"]) and not baseobj:
# remove sizes to prevent auto shape creation for types that don't require a base object
obj.Height = 0
obj.Width = 0
obj.Length = 0
if store:
sharedobjects[store] = obj
break
if ptype == "IfcBuildingStorey":
if product.Elevation:
obj.Placement.Base.z = product.Elevation * getScaling(ifcfile)
break
if not obj:
obj = Arch.makeComponent(baseobj,name=name)
@@ -704,6 +710,8 @@ def insert(filename,docname,skip=[],only=[],root=None):
# setting IFC attributes
for attribute in ArchIFCSchema.IfcProducts[product.is_a()]["attributes"]:
if attribute["name"] == "Name":
continue
#print("attribute:",attribute["name"])
if hasattr(product, attribute["name"]) and getattr(product, attribute["name"]) and hasattr(obj,attribute["name"]):
#print("Setting attribute",attribute["name"],"to",getattr(product, attribute["name"]))
@@ -1025,23 +1033,25 @@ def insert(filename,docname,skip=[],only=[],root=None):
# additions
for host,children in additions.items():
if host in objects.keys():
cobs = []
for child in children:
if child in objects.keys():
if child not in swallowed: # don't add objects already in groups
cobs.append(objects[child])
if cobs:
if DEBUG and first:
print("")
first = False
if DEBUG and (len(cobs) > 10) and (not(Draft.getType(objects[host]) in ["Site","Building","Floor","BuildingPart"])):
# avoid huge fusions
print("more than 10 shapes to add: skipping.")
else:
if DEBUG: print(" adding",len(cobs), "object(s) to", objects[host].Label)
Arch.addComponents(cobs,objects[host])
if DEBUG: FreeCAD.ActiveDocument.recompute()
if host not in objects.keys():
continue
cobs = []
for child in children:
if child in objects.keys() \
and child not in swallowed: # don't add objects already in groups
cobs.append(objects[child])
if not cobs:
continue
if DEBUG and first:
print("")
first = False
if DEBUG and (len(cobs) > 10) and (not(Draft.getType(objects[host]) in ["Site","Building","Floor","BuildingPart","Project"])):
# avoid huge fusions
print("more than 10 shapes to add: skipping.")
else:
if DEBUG: print(" adding",len(cobs), "object(s) to", objects[host].Label)
Arch.addComponents(cobs,objects[host])
if DEBUG: FreeCAD.ActiveDocument.recompute()
if DEBUG and first: print("done.")
@@ -1051,7 +1061,7 @@ def insert(filename,docname,skip=[],only=[],root=None):
for obj in objects.values():
if obj.isDerivedFrom("Part::Feature"):
if obj.Shape.isNull() and not(Draft.getType(obj) in ["Site"]):
if obj.Shape.isNull() and not(Draft.getType(obj) in ["Site","Project"]):
Arch.rebuildArchShape(obj)
FreeCAD.ActiveDocument.recompute()
@@ -1195,9 +1205,9 @@ def insert(filename,docname,skip=[],only=[],root=None):
if hasattr(objects[o],"Material"):
# the reason behind ...
# there are files around in which the material color is different from the shape color
# all viewers use the shape color wheras in FreeCAD the shape color will be
# overwritten by the material coloer (if there is a material with a color)
# in such a case FreeCAD shows different color than all common ifc viewers
# all viewers use the shape color whereas in FreeCAD the shape color will be
# overwritten by the material color (if there is a material with a color).
# In such a case FreeCAD shows a different color than all common ifc viewers
# https://forum.freecadweb.org/viewtopic.php?f=39&t=38440
col = objects[o].ViewObject.ShapeColor[:3]
dig = 5
@@ -1673,7 +1683,7 @@ class recycler:
else:
if isinstance(pvalue,float) and pvalue < 0.000000001: # remove the exp notation that some bim apps hate
pvalue = 0
c = self.ifcfile.createIfcPropertySingleValue(name,None,ifcfile.create_entity(ptype,pvalue),None)
c = self.ifcfile.createIfcPropertySingleValue(name,None,self.ifcfile.create_entity(ptype,pvalue),None)
if self.compress:
self.propertysinglevalues[key] = c
return c
+70
View File
@@ -0,0 +1,70 @@
import Arch, ArchIFC, math
class ProjectImporter:
def __init__(self, file, objects):
self.file = file
self.objects = objects
def execute(self):
self.project = self.file.by_type("IfcProject")[0]
self.object = Arch.makeProject()
self.objects[self.project.id()] = self.object
self.setAttributes()
self.setComplexAttributes()
def setAttributes(self):
for property in self.object.PropertiesList:
if hasattr(self.project, property) and getattr(self.project, property):
setattr(self.object, property, getattr(self.project, property))
def setComplexAttributes(self):
try:
mapConversion = self.project.RepresentationContexts[0].HasCoordinateOperation[0]
data = self.extractTargetCRSData(mapConversion.TargetCRS)
data.update(self.extractMapConversionData(mapConversion))
ArchIFC.IfcRoot.setObjIfcComplexAttributeValue(self, self.object, "RepresentationContexts", data)
except:
# This scenario occurs validly in IFC2X3, as the mapConversion does
# not exist
return
def extractTargetCRSData(self, targetCRS):
mappings = {
"name": "Name",
"description": "Description",
"geodetic_datum": "GeodeticDatum",
"vertical_datum": "VerticalDatum",
"map_projection": "MapProjection",
"map_zone": "MapZone"
}
data = {}
for attributeName, ifcName in mappings.items():
data[attributeName] = str(getattr(targetCRS, ifcName))
if targetCRS.MapUnit.Prefix:
data["map_unit"] = targetCRS.MapUnit.Prefix.title() + targetCRS.MapUnit.Name.lower()
else:
data["map_unit"] = targetCRS.MapUnit.Name.title()
return data
def extractMapConversionData(self, mapConversion):
mappings = {
"eastings": "Eastings",
"northings": "Northings",
"orthogonal_height": "OrthogonalHeight",
"x_axis_abscissa": "XAxisAbscissa",
"x_axis_ordinate": "XAxisOrdinate",
"scale": "Scale"
}
data = {}
for attributeName, ifcName in mappings.items():
data[attributeName] = str(getattr(mapConversion, ifcName))
data["true_north"] = str(self.calculateTrueNorthAngle(
mapConversion.XAxisAbscissa, mapConversion.XAxisOrdinate))
return data
def calculateTrueNorthAngle(self, x, y):
return round(math.degrees(math.atan2(y, x)) - 90, 6)
+146 -153
View File
File diff suppressed because it is too large Load Diff
+19 -5
View File
@@ -27,16 +27,24 @@ __title__="FreeCAD Draft Edit Tool"
__author__ = "Yorik van Havre, Werner Mayer, Martin Burbaum, Ken Cline, Dmitry Chigrin"
__url__ = "http://www.freecadweb.org"
import FreeCAD, FreeCADGui, Draft, DraftTools, math
import FreeCAD
import Draft
import math
from FreeCAD import Vector
from DraftTrackers import *
from PySide import QtCore
from PySide.QtCore import QT_TRANSLATE_NOOP
from DraftTools import translate
# Do not import GUI-related modules if GUI is not there
if FreeCAD.GuiUp:
import FreeCADGui
import DraftTools
from DraftTrackers import *
from PySide import QtCore
from PySide.QtCore import QT_TRANSLATE_NOOP
from DraftTools import translate
class Edit():
"The Draft_Edit FreeCAD command definition"
def __init__(self):
@@ -1125,3 +1133,9 @@ class Edit():
self.obj.TagPosition = self.invpl.multVec(v)
else:
self.obj.Group[self.editing-1].Placement.Base = self.invpl.multVec(v)
if FreeCAD.GuiUp:
# setup command
FreeCADGui.addCommand('Draft_Edit', Edit())
+43 -46
View File
@@ -34,10 +34,9 @@ __url__ = ["http://www.freecadweb.org"]
# toolbars and task panels, and Qt-dependent utilities such as
# a delayed (todo) commit system
'''
This is the GUI part of the Draft module.
"""This is the GUI part of the Draft module.
Report to Draft.py for info
'''
"""
import six
@@ -128,12 +127,13 @@ inCommandShortcuts = {
class todo:
''' static todo class, delays execution of functions. Use todo.delay
"""static todo class, delays execution of functions. Use todo.delay
to schedule geometry manipulation that would crash coin if done in the
event callback'''
event callback
'''List of (function, argument) pairs to be executed by
QtCore.QTimer.singleShot(0,doTodo).'''
List of (function, argument) pairs to be executed by
QtCore.QTimer.singleShot(0,doTodo).
"""
itinerary = []
commitlist = []
afteritinerary = []
@@ -283,7 +283,7 @@ class DraftBaseWidget(QtGui.QWidget):
return QtGui.QWidget.eventFilter(self, widget, event)
class DraftDockWidget(DraftBaseWidget):
"custom Widget that emits a resized() signal when resized"
"""custom Widget that emits a resized() signal when resized"""
def __init__(self,parent = None):
QtGui.QWidget.__init__(self,parent)
def resizeEvent(self,event):
@@ -295,7 +295,7 @@ class DraftDockWidget(DraftBaseWidget):
QtGui.QWidget.changeEvent(self,event)
class DraftLineEdit(QtGui.QLineEdit):
"custom QLineEdit widget that has the power to catch Escape keypress"
"""custom QLineEdit widget that has the power to catch Escape keypress"""
def __init__(self, parent=None):
QtGui.QLineEdit.__init__(self, parent)
def keyPressEvent(self, event):
@@ -336,7 +336,7 @@ class DraftTaskPanel:
return False
class DraftToolBar:
"main draft Toolbar"
"""main draft Toolbar"""
def __init__(self):
self.tray = None
self.sourceCmd = None
@@ -508,7 +508,7 @@ class DraftToolBar:
layout.addWidget(cb)
def setupToolBar(self,task=False):
"sets the draft toolbar up"
"""sets the draft toolbar up"""
# command
@@ -753,7 +753,7 @@ class DraftToolBar:
#QtCore.QObject.connect(self.STrackValue,QtCore.SIGNAL("returnPressed()"),self.checkSTrack)
def setupTray(self):
"sets draft tray buttons up"
"""sets draft tray buttons up"""
self.wplabel = self._pushbutton("wplabel", self.toptray, icon='Draft_SelectPlane',hide=False,width=120)
defaultWP = Draft.getParam("defaultWP",0)
@@ -947,7 +947,7 @@ class DraftToolBar:
else:
# create a dummy task to block the UI during the works
class dummy:
"an empty dialog"
"""an empty dialog"""
def __init__(self,extra=None):
if extra:
if isinstance(extra,list):
@@ -972,7 +972,7 @@ class DraftToolBar:
self.setTitle(title,icon)
def redraw(self):
"utility function that is performed after each clicked point"
"""utility function that is performed after each clicked point"""
self.checkLocal()
def setFocus(self,f=None):
@@ -1356,7 +1356,7 @@ class DraftToolBar:
self.delButton.setChecked(not(addmode))
def checkLocal(self):
"checks if x,y,z coords must be displayed as local or global"
"""checks if x,y,z coords must be displayed as local or global"""
self.labelx.setText(translate("draft", "Global X"))
self.labely.setText(translate("draft", "Global Y"))
self.labelz.setText(translate("draft", "Global Z"))
@@ -1408,14 +1408,14 @@ class DraftToolBar:
p.SetBool("OffsetCopyMode",bool(val))
def relocate(self):
"relocates the right-aligned buttons depending on the toolbar size"
"""relocates the right-aligned buttons depending on the toolbar size"""
if self.baseWidget.geometry().width() < 400:
self.layout.setDirection(QtGui.QBoxLayout.TopToBottom)
else:
self.layout.setDirection(QtGui.QBoxLayout.LeftToRight)
def makeDumbTask(self,extra=None,callback=None):
"create a dumb taskdialog to prevent deleting the temp object"
"""create a dumb taskdialog to prevent deleting the temp object"""
class TaskPanel:
def __init__(self,extra=None,callback=None):
if extra:
@@ -1431,7 +1431,7 @@ class DraftToolBar:
FreeCADGui.Control.showDialog(panel)
def setGridSize(self,text):
"sets the Draft grid to the given grid size"
"""sets the Draft grid to the given grid size"""
try:
q = FreeCAD.Units.Quantity(text)
except:
@@ -1442,7 +1442,7 @@ class DraftToolBar:
FreeCADGui.Snapper.setGrid()
def setMainline(self,val):
"sets the grid main lines"
"""sets the grid main lines"""
if val > 1:
Draft.setParam("gridEvery",val)
if hasattr(FreeCADGui,"Snapper"):
@@ -1456,7 +1456,7 @@ class DraftToolBar:
#---------------------------------------------------------------------------
def getcol(self):
"opens a color picker dialog"
"""opens a color picker dialog"""
oldColor = self.color
self.color=QtGui.QColorDialog.getColor()
if not QtGui.QColor.isValid(self.color): #user canceled
@@ -1480,7 +1480,7 @@ class DraftToolBar:
i.ViewObject.PointColor = col
def getfacecol(self):
"opens a color picker dialog"
"""opens a color picker dialog"""
oldColor = self.facecolor
self.facecolor=QtGui.QColorDialog.getColor()
if not QtGui.QColor.isValid(self.facecolor): #user canceled
@@ -1546,7 +1546,7 @@ class DraftToolBar:
self.updateSnapper()
def validatePoint(self):
"function for checking and sending numbers entered manually"
"""function for checking and sending numbers entered manually"""
if self.sourceCmd or self.pointcallback:
if (self.labelRadius.isVisible()):
try:
@@ -1673,7 +1673,7 @@ class DraftToolBar:
def finish(self):
"finish button action"
"""finish button action"""
if self.sourceCmd:
self.sourceCmd.finish(False)
if self.cancel:
@@ -1683,27 +1683,27 @@ class DraftToolBar:
FreeCADGui.ActiveDocument.resetEdit()
def escape(self):
"escapes the current command"
"""escapes the current command"""
self.continueMode = False
if not self.taskmode:
self.continueCmd.setChecked(False)
self.finish()
def closeLine(self):
"close button action"
"""close button action"""
self.sourceCmd.finish(True)
FreeCADGui.ActiveDocument.resetEdit()
def wipeLine(self):
"wipes existing segments of a line"
"""wipes existing segments of a line"""
self.sourceCmd.wipe()
def orientWP(self):
"reorients the current working plane"
"""reorients the current working plane"""
self.sourceCmd.orientWP()
def selectEdge(self):
"allows the dimension command to select an edge"
"""allows the dimension command to select an edge"""
if hasattr(self.sourceCmd,"selectEdge"):
self.sourceCmd.selectEdge()
@@ -1726,15 +1726,14 @@ class DraftToolBar:
self.sourceCmd.selectHandler("alignToWP")
def undoSegment(self):
"undo last line segment"
"""undo last line segment"""
if hasattr(self.sourceCmd,"undolast"):
self.sourceCmd.undolast()
def checkSpecialChars(self,txt):
'''
checks for special characters in the entered coords that must be
"""checks for special characters in the entered coords that must be
treated as shortcuts
'''
"""
# in-command shortcut definitions
#Relative
@@ -1840,7 +1839,7 @@ class DraftToolBar:
self.updateSnapper()
def updateSnapper(self):
"updates the snapper track line if applicable"
"""updates the snapper track line if applicable"""
if hasattr(FreeCADGui,"Snapper"):
if FreeCADGui.Snapper.trackLine:
if FreeCADGui.Snapper.trackLine.Visible:
@@ -1863,10 +1862,9 @@ class DraftToolBar:
self.textValue.setText(tstr)
def sendText(self):
'''
this function sends the entered text to the active draft command
"""this function sends the entered text to the active draft command
if enter has been pressed twice. Otherwise it blanks the line.
'''
"""
if self.textline == len(self.textbuffer):
if self.textline:
if not self.currEditText:
@@ -1884,7 +1882,7 @@ class DraftToolBar:
self.setCurrentText('')
def lineUp(self):
"displays previous line in text editor"
"""displays previous line in text editor"""
if self.textline:
if self.textline == len(self.textbuffer):
self.textbuffer.append(self.textValue.text())
@@ -1897,7 +1895,7 @@ class DraftToolBar:
self.textValue.setText(self.textbuffer[self.textline])
def displayPoint(self, point=None, last=None, plane=None, mask=None):
"this function displays the passed coords in the x, y, and z widgets"
"""this function displays the passed coords in the x, y, and z widgets"""
if self.taskmode and (not self.isTaskOn):
return
@@ -1966,7 +1964,7 @@ class DraftToolBar:
def getDefaultColor(self,type,rgb=False):
"gets color from the preferences or toolbar"
"""gets color from the preferences or toolbar"""
r = 0
g = 0
b = 0
@@ -1997,7 +1995,7 @@ class DraftToolBar:
return (r,g,b)
def cross(self,on=True):
"deprecated"
"""deprecated"""
pass
def toggleConstrMode(self,checked):
@@ -2045,7 +2043,7 @@ class DraftToolBar:
FreeCADGui.runCommand("Draft_SelectPlane")
def popupMenu(self,llist,ilist=None,pos=None):
"pops up a menu filled with the given list"
"""pops up a menu filled with the given list"""
self.groupmenu = QtGui.QMenu()
for i,l in enumerate(llist):
if ilist:
@@ -2363,7 +2361,7 @@ class FacebinderTaskPanel:
return int(QtGui.QDialogButtonBox.Ok)
def update(self):
'fills the treewidget'
"""fills the treewidget"""
self.tree.clear()
if self.obj:
for f in self.obj.Faces:
@@ -2439,8 +2437,7 @@ class FacebinderTaskPanel:
class ScaleTaskPanel:
'''A Task Panel for the Scale tool'''
"""A Task Panel for the Scale tool"""
def __init__(self):
self.sourceCmd = None
@@ -2628,7 +2625,7 @@ class ShapeStringTaskPanel:
self.setPoint(origin)
def action(self,arg):
"scene event handler"
"""scene event handler"""
import DraftTools
if arg["Type"] == "SoKeyboardEvent":
if arg["Key"] == "ESCAPE":
@@ -2648,7 +2645,7 @@ class ShapeStringTaskPanel:
self.task.sbZ.setProperty('rawValue',point.z)
def createObject(self):
"creates object in the current doc"
"""creates object in the current doc"""
dquote = '"'
if sys.version_info.major < 3: # Python3: no more unicode
String = 'u' + dquote + str(self.task.leString.text().encode('unicode_escape')) + dquote
+10 -40
View File
@@ -31,14 +31,13 @@ def translate(ctx,txt):
def QT_TRANSLATE_NOOP(ctx,txt):
return txt
"This module contains everything related to Draft Layers"
"""This module contains everything related to Draft Layers"""
def makeLayer(name=None,linecolor=None,drawstyle=None,shapecolor=None,transparency=None):
'''makeLayer([name,linecolor,drawstyle,shapecolor,transparency]):
creates a Layer object in the active document'''
"""makeLayer([name,linecolor,drawstyle,shapecolor,transparency]):
creates a Layer object in the active document
"""
if not FreeCAD.ActiveDocument:
FreeCAD.Console.PrintError(translate("draft","No active document. Aborting")+"\n")
return
@@ -63,9 +62,7 @@ def makeLayer(name=None,linecolor=None,drawstyle=None,shapecolor=None,transparen
def getLayerContainer():
'''getLayerContainer(): returns a group object to put layers in'''
"""getLayerContainer(): returns a group object to put layers in"""
for obj in FreeCAD.ActiveDocument.Objects:
if obj.Name == "LayerContainer":
return obj
@@ -78,17 +75,14 @@ def getLayerContainer():
class CommandLayer():
"The Draft_Layer FreeCAD command"
"""The Draft_Layer FreeCAD command"""
def GetResources(self):
return {'Pixmap' : 'Draft_VisGroup',
'MenuText': QT_TRANSLATE_NOOP("Draft_Layer", "Layer"),
'ToolTip' : QT_TRANSLATE_NOOP("Draft_Layer", "Adds a layer")}
def Activated(self):
import FreeCADGui
FreeCAD.ActiveDocument.openTransaction("Create Layer")
FreeCADGui.addModule("Draft")
@@ -99,31 +93,25 @@ class CommandLayer():
class Layer:
"The Draft Layer object"
"""The Draft Layer object"""
def __init__(self,obj):
self.Type = "Layer"
obj.Proxy = self
self.Object = obj
self.setProperties(obj)
def onDocumentRestored(self,obj):
self.setProperties(obj)
def setProperties(self,obj):
if not "Group" in obj.PropertiesList:
obj.addProperty("App::PropertyLinkList","Group","Layer",QT_TRANSLATE_NOOP("App::Property","The objects that are part of this layer"))
def __getstate__(self):
return self.Type
def __setstate__(self,state):
if state:
self.Type = state
@@ -131,7 +119,6 @@ class Layer:
pass
def addObject(self,obj,child):
g = obj.Group
if not child in g:
g.append(child)
@@ -139,11 +126,9 @@ class Layer:
class ViewProviderLayer:
"A View Provider for the Layer object"
"""A View Provider for the Layer object"""
def __init__(self,vobj):
vobj.addProperty("App::PropertyBool","OverrideChildren","Layer",QT_TRANSLATE_NOOP("App::Property","If on, the child objects of this layer will match its visual aspects"))
vobj.addProperty("App::PropertyColor","LineColor","Layer",QT_TRANSLATE_NOOP("App::Property","The line color of the children of this layer"))
vobj.addProperty("App::PropertyColor","ShapeColor","Layer",QT_TRANSLATE_NOOP("App::Property","The shape color of the children of this layer"))
@@ -164,14 +149,12 @@ class ViewProviderLayer:
vobj.Proxy = self
def getIcon(self):
if hasattr(self,"icondata"):
return self.icondata
import Draft_rc
return ":/icons/Draft_VisGroup.svg"
def attach(self,vobj):
self.Object = vobj.Object
from pivy import coin
sep = coin.SoGroup()
@@ -179,37 +162,29 @@ class ViewProviderLayer:
return
def claimChildren(self):
if hasattr(self,"Object") and hasattr(self.Object,"Group"):
return self.Object.Group
def getDisplayModes(self, vobj):
return ["Default"]
def getDefaultDisplayMode(self):
return "Default"
def setDisplayMode(self, mode):
return mode
def __getstate__(self):
return None
def __setstate__(self,state):
return None
def updateData(self,obj,prop):
if prop == "Group":
self.onChanged(obj.ViewObject,"LineColor")
def onChanged(self,vobj,prop):
if hasattr(vobj,"OverrideChildren") and vobj.OverrideChildren:
if hasattr(vobj,"Object")and hasattr(vobj.Object,"Group"):
for o in vobj.Object.Group:
@@ -249,15 +224,12 @@ class ViewProviderLayer:
self.icondata = ba.data().decode("latin1")
def canDragObject(self,obj):
return True
def canDragObjects(self):
return True
def dragObject(self,vobj,otherobj):
if hasattr(vobj.Object,"Group"):
if otherobj in vobj.Object.Group:
g = vobj.Object.Group
@@ -309,8 +281,7 @@ class ViewProviderLayer:
class LayerContainer:
"The Layer Container"
"""The Layer Container"""
def __init__(self,obj):
@@ -335,8 +306,7 @@ class LayerContainer:
class ViewProviderLayerContainer:
"A View Provider for the Layer Container"
"""A View Provider for the Layer Container"""
def __init__(self,vobj):
File diff suppressed because it is too large Load Diff
+54 -54
View File
@@ -39,7 +39,7 @@ from pivy import coin
class Tracker:
"A generic Draft Tracker, to be used by other specific trackers"
"""A generic Draft Tracker, to be used by other specific trackers"""
def __init__(self,dotted=False,scolor=None,swidth=None,children=[],ontop=False,name=None):
global Part, DraftGeomUtils
import Part, DraftGeomUtils
@@ -111,7 +111,7 @@ class Tracker:
sg.insertChild(self.switch,0)
class snapTracker(Tracker):
"A Snap Mark tracker, used by tools that support snapping"
"""A Snap Mark tracker, used by tools that support snapping"""
def __init__(self):
color = coin.SoBaseColor()
color.rgb = FreeCADGui.draftToolBar.getDefaultColor("snap")
@@ -141,7 +141,7 @@ class snapTracker(Tracker):
class lineTracker(Tracker):
"A Line tracker, used by the tools that need to draw temporary lines"
"""A Line tracker, used by the tools that need to draw temporary lines"""
def __init__(self,dotted=False,scolor=None,swidth=None,ontop=False):
line = coin.SoLineSet()
line.numVertices.setValue(2)
@@ -150,7 +150,7 @@ class lineTracker(Tracker):
Tracker.__init__(self,dotted,scolor,swidth,[self.coords,line],ontop,name="lineTracker")
def p1(self,point=None):
"sets or gets the first point of the line"
"""sets or gets the first point of the line"""
if point:
if self.coords.point.getValues()[0].getValue() != tuple(point):
self.coords.point.set1Value(0,point.x,point.y,point.z)
@@ -158,7 +158,7 @@ class lineTracker(Tracker):
return Vector(self.coords.point.getValues()[0].getValue())
def p2(self,point=None):
"sets or gets the second point of the line"
"""sets or gets the second point of the line"""
if point:
if self.coords.point.getValues()[-1].getValue() != tuple(point):
self.coords.point.set1Value(1,point.x,point.y,point.z)
@@ -166,13 +166,13 @@ class lineTracker(Tracker):
return Vector(self.coords.point.getValues()[-1].getValue())
def getLength(self):
"returns the length of the line"
"""returns the length of the line"""
p1 = Vector(self.coords.point.getValues()[0].getValue())
p2 = Vector(self.coords.point.getValues()[-1].getValue())
return (p2.sub(p1)).Length
class rectangleTracker(Tracker):
"A Rectangle tracker, used by the rectangle tool"
"""A Rectangle tracker, used by the rectangle tool"""
def __init__(self,dotted=False,scolor=None,swidth=None,face=False):
self.origin = Vector(0,0,0)
line = coin.SoLineSet()
@@ -192,13 +192,13 @@ class rectangleTracker(Tracker):
self.v = FreeCAD.DraftWorkingPlane.v
def setorigin(self,point):
"sets the base point of the rectangle"
"""sets the base point of the rectangle"""
self.coords.point.set1Value(0,point.x,point.y,point.z)
self.coords.point.set1Value(4,point.x,point.y,point.z)
self.origin = point
def update(self,point):
"sets the opposite (diagonal) point of the rectangle"
"""sets the opposite (diagonal) point of the rectangle"""
diagonal = point.sub(self.origin)
inpoint1 = self.origin.add(DraftVecUtils.project(diagonal,self.v))
inpoint2 = self.origin.add(DraftVecUtils.project(diagonal,self.u))
@@ -217,40 +217,40 @@ class rectangleTracker(Tracker):
self.v = self.u.cross(norm)
def p1(self,point=None):
"sets or gets the base point of the rectangle"
"""sets or gets the base point of the rectangle"""
if point:
self.setorigin(point)
else:
return Vector(self.coords.point.getValues()[0].getValue())
def p2(self):
"gets the second point (on u axis) of the rectangle"
"""gets the second point (on u axis) of the rectangle"""
return Vector(self.coords.point.getValues()[3].getValue())
def p3(self,point=None):
"sets or gets the opposite (diagonal) point of the rectangle"
"""sets or gets the opposite (diagonal) point of the rectangle"""
if point:
self.update(point)
else:
return Vector(self.coords.point.getValues()[2].getValue())
def p4(self):
"gets the fourth point (on v axis) of the rectangle"
"""gets the fourth point (on v axis) of the rectangle"""
return Vector(self.coords.point.getValues()[1].getValue())
def getSize(self):
"returns (length,width) of the rectangle"
"""returns (length,width) of the rectangle"""
p1 = Vector(self.coords.point.getValues()[0].getValue())
p2 = Vector(self.coords.point.getValues()[2].getValue())
diag = p2.sub(p1)
return ((DraftVecUtils.project(diag,self.u)).Length,(DraftVecUtils.project(diag,self.v)).Length)
def getNormal(self):
"returns the normal of the rectangle"
"""returns the normal of the rectangle"""
return (self.u.cross(self.v)).normalize()
def isInside(self,point):
"returns True if the given point is inside the rectangle"
"""returns True if the given point is inside the rectangle"""
vp = point.sub(self.p1())
uv = self.p2().sub(self.p1())
vv = self.p4().sub(self.p1())
@@ -264,7 +264,7 @@ class rectangleTracker(Tracker):
return False
class dimTracker(Tracker):
"A Dimension tracker, used by the dimension tool"
"""A Dimension tracker, used by the dimension tool"""
def __init__(self,dotted=False,scolor=None,swidth=None):
line = coin.SoLineSet()
line.numVertices.setValue(4)
@@ -308,7 +308,7 @@ class dimTracker(Tracker):
self.coords.point.setValues(0,4,points)
class bsplineTracker(Tracker):
"A bspline tracker"
"""A bspline tracker"""
def __init__(self,dotted=False,scolor=None,swidth=None,points = []):
self.bspline = None
self.points = points
@@ -375,7 +375,7 @@ class bsplineTracker(Tracker):
FreeCAD.Console.PrintWarning("bsplineTracker.recompute() failed to read-in Inventor string\n")
#######################################
class bezcurveTracker(Tracker):
"A bezcurve tracker"
"""A bezcurve tracker"""
def __init__(self,dotted=False,scolor=None,swidth=None,points = []):
self.bezcurve = None
self.points = points
@@ -459,7 +459,7 @@ class bezcurveTracker(Tracker):
#######################################
class arcTracker(Tracker):
"An arc tracker"
"""An arc tracker"""
def __init__(self,dotted=False,scolor=None,swidth=None,start=0,end=math.pi*2,normal=None):
self.circle = None
self.startangle = math.degrees(start)
@@ -477,35 +477,35 @@ class arcTracker(Tracker):
Tracker.__init__(self,dotted,scolor,swidth,[self.trans, self.sep],name="arcTracker")
def getDeviation(self):
"returns a deviation vector that represents the base of the circle"
"""returns a deviation vector that represents the base of the circle"""
import Part
c = Part.makeCircle(1,Vector(0,0,0),self.normal)
return c.Vertexes[0].Point
def setCenter(self,cen):
"sets the center point"
"""sets the center point"""
self.trans.translation.setValue([cen.x,cen.y,cen.z])
def setRadius(self,rad):
"sets the radius"
"""sets the radius"""
self.trans.scaleFactor.setValue([rad,rad,rad])
def getRadius(self):
"returns the current radius"
"""returns the current radius"""
return self.trans.scaleFactor.getValue()[0]
def setStartAngle(self,ang):
"sets the start angle"
"""sets the start angle"""
self.startangle = math.degrees(ang)
self.recompute()
def setEndAngle(self,ang):
"sets the end angle"
"""sets the end angle"""
self.endangle = math.degrees(ang)
self.recompute()
def getAngle(self,pt):
"returns the angle of a given vector in radians"
"""returns the angle of a given vector in radians"""
c = self.trans.translation.getValue()
center = Vector(c[0],c[1],c[2])
rad = pt.sub(center)
@@ -514,25 +514,25 @@ class arcTracker(Tracker):
return(a)
def getAngles(self):
"returns the start and end angles in degrees"
"""returns the start and end angles in degrees"""
return(self.startangle,self.endangle)
def setStartPoint(self,pt):
"sets the start angle from a point"
"""sets the start angle from a point"""
self.setStartAngle(-self.getAngle(pt))
def setEndPoint(self,pt):
"sets the end angle from a point"
"""sets the end angle from a point"""
self.setEndAngle(-self.getAngle(pt))
def setApertureAngle(self,ang):
"sets the end angle by giving the aperture angle"
"""sets the end angle by giving the aperture angle"""
ap = math.degrees(ang)
self.endangle = self.startangle + ap
self.recompute()
def setBy3Points(self,p1,p2,p3):
"sets the arc by three points"
"""sets the arc by three points"""
import Part
try:
arc=Part.ArcOfCircle(p1,p2,p3)
@@ -619,7 +619,7 @@ class ghostTracker(Tracker):
Tracker.__init__(self,dotted,scolor,swidth,children=self.children,name="ghostTracker")
def update(self,obj):
"recreates the ghost from a new object"
"""recreates the ghost from a new object"""
obj.ViewObject.show()
self.finalize()
sep = self.getNode(obj)
@@ -628,23 +628,23 @@ class ghostTracker(Tracker):
obj.ViewObject.hide()
def move(self,delta):
"moves the ghost to a given position, relative from its start position"
"""moves the ghost to a given position, relative from its start position"""
self.trans.translation.setValue([delta.x,delta.y,delta.z])
def rotate(self,axis,angle):
"rotates the ghost of a given angle"
"""rotates the ghost of a given angle"""
self.trans.rotation.setValue(coin.SbVec3f(DraftVecUtils.tup(axis)),angle)
def center(self,point):
"sets the rotation/scale center of the ghost"
"""sets the rotation/scale center of the ghost"""
self.trans.center.setValue(point.x,point.y,point.z)
def scale(self,delta):
"scales the ghost by the given factor"
"""scales the ghost by the given factor"""
self.trans.scaleFactor.setValue([delta.x,delta.y,delta.z])
def getNode(self,obj):
"returns a coin node representing the given object"
"""returns a coin node representing the given object"""
import Part
if isinstance(obj,Part.Shape):
return self.getNodeLight(obj)
@@ -654,7 +654,7 @@ class ghostTracker(Tracker):
return self.getNodeFull(obj)
def getNodeFull(self,obj):
"gets a coin node which is a full copy of the current representation"
"""gets a coin node which is a full copy of the current representation"""
sep = coin.SoSeparator()
try:
sep.addChild(obj.ViewObject.RootNode.copy())
@@ -671,7 +671,7 @@ class ghostTracker(Tracker):
return sep
def getNodeLight(self,shape):
"extract a lighter version directly from a shape"
"""extract a lighter version directly from a shape"""
# error-prone
sep = coin.SoSeparator()
try:
@@ -706,7 +706,7 @@ class ghostTracker(Tracker):
self.trans.setMatrix(m)
class editTracker(Tracker):
"A node edit tracker"
"""A node edit tracker"""
def __init__(self,pos=Vector(0,0,0),name=None,idx=0,objcol=None,\
marker=FreeCADGui.getMarkerIndex("quad", 9),inactive=False):
color = coin.SoBaseColor()
@@ -746,7 +746,7 @@ class editTracker(Tracker):
self.set(self.get().add(delta))
class PlaneTracker(Tracker):
"A working plane tracker"
"""A working plane tracker"""
def __init__(self):
# getting screen distance
p1 = Draft.get3DView().getPoint((100,100))
@@ -794,7 +794,7 @@ class PlaneTracker(Tracker):
self.on()
class wireTracker(Tracker):
"A wire tracker"
"""A wire tracker"""
def __init__(self,wire):
self.line = coin.SoLineSet()
self.closed = DraftGeomUtils.isReallyClosed(wire)
@@ -827,7 +827,7 @@ class wireTracker(Tracker):
self.coords.point.set1Value(i,[p.x,p.y,p.z])
class gridTracker(Tracker):
"A grid tracker"
"""A grid tracker"""
def __init__(self):
col = self.getGridColor()
pick = coin.SoPickStyle()
@@ -873,7 +873,7 @@ class gridTracker(Tracker):
return [r, g, b]
def update(self):
"redraws the grid"
"""redraws the grid"""
# resize the grid to make sure it fits an exact pair number of main lines
numlines = self.numlines//self.mainlines//2*2*self.mainlines
bound = (numlines//2)*self.space
@@ -927,14 +927,14 @@ class gridTracker(Tracker):
self.update()
def reset(self):
"resets the grid according to preferences settings"
"""resets the grid according to preferences settings"""
self.space = Draft.getParam("gridSpacing",1)
self.mainlines = Draft.getParam("gridEvery",10)
self.numlines = Draft.getParam("gridSize",100)
self.update()
def set(self):
"moves and rotates the grid according to the current WP"
"""moves and rotates the grid according to the current WP"""
self.reset()
Q = FreeCAD.DraftWorkingPlane.getRotation().Rotation.Q
P = FreeCAD.DraftWorkingPlane.position
@@ -943,7 +943,7 @@ class gridTracker(Tracker):
self.on()
def getClosestNode(self,point):
"returns the closest node from the given point"
"""returns the closest node from the given point"""
# get the 2D coords.
# point = FreeCAD.DraftWorkingPlane.projectPoint(point)
pt = FreeCAD.DraftWorkingPlane.getLocalCoords(point)
@@ -953,7 +953,7 @@ class gridTracker(Tracker):
return pt
class boxTracker(Tracker):
"A box tracker, can be based on a line object"
"""A box tracker, can be based on a line object"""
def __init__(self,line=None,width=0.1,height=1,shaded=False):
self.trans = coin.SoTransform()
m = coin.SoMaterial()
@@ -1024,7 +1024,7 @@ class boxTracker(Tracker):
return self.cube.depth.getValue()
class radiusTracker(Tracker):
"A tracker that displays a transparent sphere to inicate a radius"
"""A tracker that displays a transparent sphere to inicate a radius"""
def __init__(self,position=FreeCAD.Vector(0,0,0),radius=1):
self.trans = coin.SoTransform()
self.trans.translation.setValue([position.x,position.y,position.z])
@@ -1048,7 +1048,7 @@ class radiusTracker(Tracker):
self.sphere.radius.setValue(arg2)
class archDimTracker(Tracker):
"A wrapper around a Sketcher dim"
"""A wrapper around a Sketcher dim"""
def __init__(self,p1=FreeCAD.Vector(0,0,0),p2=FreeCAD.Vector(1,0,0),mode=1):
import SketcherGui
self.dimnode = coin.SoType.fromName("SoDatumLabel").createInstance()
@@ -1063,7 +1063,7 @@ class archDimTracker(Tracker):
Tracker.__init__(self,children=[self.dimnode],name="archDimTracker")
def setString(self,text=None):
"sets the dim string to the given value or auto value"
"""sets the dim string to the given value or auto value"""
self.dimnode.param1.setValue(.5)
p1 = Vector(self.dimnode.pnts.getValues()[0].getValue())
p2 = Vector(self.dimnode.pnts.getValues()[-1].getValue())
@@ -1083,7 +1083,7 @@ class archDimTracker(Tracker):
self.dimnode.datumtype.setValue(mode)
def p1(self,point=None):
"sets or gets the first point of the dim"
"""sets or gets the first point of the dim"""
if point:
self.dimnode.pnts.set1Value(0,point.x,point.y,point.z)
self.setString()
@@ -1091,7 +1091,7 @@ class archDimTracker(Tracker):
return Vector(self.dimnode.pnts.getValues()[0].getValue())
def p2(self,point=None):
"sets or gets the second point of the dim"
"""sets or gets the second point of the dim"""
if point:
self.dimnode.pnts.set1Value(1,point.x,point.y,point.z)
self.setString()
+2 -2
View File
@@ -347,7 +347,7 @@ def angle(u, v=Vector(1, 0, 0), normal=Vector(0, 0, 1)):
dp = u.dot(v)/ll
# Due to rounding errors, the dot product could be outside
# the range [-1, 1], so let's force it to be withing this range.
# the range [-1, 1], so let's force it to be within this range.
if dp < -1:
dp = -1
elif dp > 1:
@@ -785,7 +785,7 @@ def removeDoubles(vlist):
Finding duplicated vectors tests for `equality` which depends
on the `precision` parameter in the parameter database.
Paramaters
Parameters
----------
vlist : list of Base::Vector3
List with vectors.
-4
View File
@@ -65,7 +65,6 @@ class DraftWorkbench(Workbench):
# Import Draft tools, icons
try:
import os, Draft_rc, DraftTools, DraftGui
import DraftEdit
from DraftTools import translate
FreeCADGui.addLanguagePath(":/translations")
FreeCADGui.addIconPath(":/icons")
@@ -73,9 +72,6 @@ class DraftWorkbench(Workbench):
print(inst)
FreeCAD.Console.PrintError("Error: Initializing one or more of the Draft modules failed, Draft will not work as expected.\n")
# setup commands
FreeCADGui.addCommand('Draft_Edit', DraftEdit.Edit())
# setup menus
self.cmdList = ["Draft_Line", "Draft_Wire", "Draft_Circle",
"Draft_ArcTools", "Draft_Ellipse",
+88 -55
View File
@@ -4,11 +4,15 @@
#
# This module provides the plane class which provides a virtual working plane
# in FreeCAD and a couple of utility functions.
"""
"""@package WorkingPlane
\ingroup DRAFT
\brief This module handles the working plane and grid of the Draft Workbench.
This module provides the plane class which provides a virtual working plane
in FreeCAD and a couple of utility functions.
The Working Plane is mostly intended to be used in the Draft Workbench
to draw 2D objects.
The working plane is mostly intended to be used in the Draft Workbench
to draw 2D objects in various orientations, not only in the standard XY,
YZ, and XZ planes.
"""
# ***************************************************************************
@@ -37,6 +41,7 @@ to draw 2D objects.
import FreeCAD, math, DraftVecUtils
from FreeCAD import Vector
from FreeCAD import Console as FCC
__title__ = "FreeCAD Working Plane utility"
__author__ = "Ken Cline"
@@ -61,13 +66,15 @@ class plane:
A vector that is supposed to be perpendicular to `u` and `v`;
it is helpful although redundant.
position : Base::Vector3
A point throught which the plane goes through,
A point, which the plane goes through,
that helps define the working plane.
stored : bool
A placeholder for a stored state.
"""
def __init__(self, u=Vector(1, 0, 0), v=Vector(0, 1, 0), w=Vector(0, 0, 1), pos=Vector(0, 0, 0)):
def __init__(self,
u=Vector(1, 0, 0), v=Vector(0, 1, 0), w=Vector(0, 0, 1),
pos=Vector(0, 0, 0)):
"""Initialize the working plane.
Parameters
@@ -98,7 +105,11 @@ class plane:
def __repr__(self):
"""Show the string representation of the object."""
return "Workplane x="+str(DraftVecUtils.rounded(self.u))+" y="+str(DraftVecUtils.rounded(self.v))+" z="+str(DraftVecUtils.rounded(self.axis))
text = "Workplane"
text += " x=" + str(DraftVecUtils.rounded(self.u))
text += " y=" + str(DraftVecUtils.rounded(self.v))
text += " z=" + str(DraftVecUtils.rounded(self.axis))
return text
def copy(self):
"""Return a new plane that is a copy of the present object."""
@@ -148,7 +159,7 @@ class plane:
The points are as follows
* `p` is an arbitraty point outside the plane.
* `p` is an arbitrary point outside the plane.
* `c` is a known point on the plane,
for example, `plane.position`.
* `x` is the intercept on the plane from `p` in
@@ -198,7 +209,8 @@ class plane:
**Note:** for 2D these trigonometric operations
produce the full `|xp|` distance.
"""
if direction == None: direction = self.axis
if direction is None:
direction = self.axis
return direction.dot(self.position.sub(p))
def projectPoint(self, p, direction=None):
@@ -257,7 +269,7 @@ class plane:
if not direction:
direction = self.axis
t = Vector(direction)
#t.normalize()
# t.normalize()
a = round(t.getAngle(self.axis), DraftVecUtils.precision())
pp = round((math.pi)/2, DraftVecUtils.precision())
if a == pp:
@@ -314,8 +326,8 @@ class plane:
offsetVector.multiply(offset)
self.position = point.add(offsetVector)
self.weak = False
# FreeCAD.Console.PrintMessage("(position = " + str(self.position) + ")\n")
# FreeCAD.Console.PrintMessage("Current workplane: x="+str(DraftVecUtils.rounded(self.u))+" y="+str(DraftVecUtils.rounded(self.v))+" z="+str(DraftVecUtils.rounded(self.axis))+"\n")
# FCC.PrintMessage("(position = " + str(self.position) + ")\n")
# FCC.PrintMessage(self.__repr__() + "\n")
def alignToPointAndAxis_SVG(self, point, axis, offset=0):
"""Align the working plane to a point and an axis (vector).
@@ -387,50 +399,51 @@ class plane:
self.u = axis.negative().cross(ref_vec)
self.u.normalize()
self.v = DraftVecUtils.rotate(self.u, math.pi/2, self.axis)
#projcase = "Case new"
# projcase = "Case new"
elif ((abs(axis.y) > abs(axis.z)) and (abs(axis.z) >= abs(axis.x))):
ref_vec = Vector(1.0, 0.0, 0.0)
self.u = axis.negative().cross(ref_vec)
self.u.normalize()
self.v = DraftVecUtils.rotate(self.u, math.pi/2, self.axis)
#projcase = "Y>Z, View Y"
# projcase = "Y>Z, View Y"
elif ((abs(axis.y) >= abs(axis.x)) and (abs(axis.x) > abs(axis.z))):
ref_vec = Vector(0.0, 0., 1.0)
self.u = axis.cross(ref_vec)
self.u.normalize()
self.v = DraftVecUtils.rotate(self.u, math.pi/2, self.axis)
#projcase = "ehem. XY, Case XY"
# projcase = "ehem. XY, Case XY"
elif ((abs(axis.x) > abs(axis.z)) and (abs(axis.z) >= abs(axis.y))):
self.u = axis.cross(ref_vec)
self.u.normalize()
self.v = DraftVecUtils.rotate(self.u, math.pi/2, self.axis)
#projcase = "X>Z, View X"
# projcase = "X>Z, View X"
elif ((abs(axis.z) >= abs(axis.y)) and (abs(axis.y) > abs(axis.x))):
ref_vec = Vector(1.0, 0., 0.0)
self.u = axis.cross(ref_vec)
self.u.normalize()
self.v = DraftVecUtils.rotate(self.u, math.pi/2, self.axis)
#projcase = "Y>X, Case YZ"
# projcase = "Y>X, Case YZ"
else:
self.u = axis.negative().cross(ref_vec)
self.u.normalize()
self.v = DraftVecUtils.rotate(self.u, math.pi/2, self.axis)
#projcase = "else"
# projcase = "else"
#spat_vec = self.u.cross(self.v)
#spat_res = spat_vec.dot(axis)
#FreeCAD.Console.PrintMessage(projcase + " spat Prod = " + str(spat_res) + "\n")
# spat_vec = self.u.cross(self.v)
# spat_res = spat_vec.dot(axis)
# FCC.PrintMessage(projcase + " spat Prod = " + str(spat_res) + "\n")
offsetVector = Vector(axis); offsetVector.multiply(offset)
offsetVector = Vector(axis)
offsetVector.multiply(offset)
self.position = point.add(offsetVector)
self.weak = False
# FreeCAD.Console.PrintMessage("(position = " + str(self.position) + ")\n")
# FreeCAD.Console.PrintMessage("Current workplane: x="+str(DraftVecUtils.rounded(self.u))+" y="+str(DraftVecUtils.rounded(self.v))+" z="+str(DraftVecUtils.rounded(self.axis))+"\n")
# FCC.PrintMessage("(position = " + str(self.position) + ")\n")
# FCC.PrintMessage(self.__repr__() + "\n")
def alignToCurve(self, shape, offset=0):
"""Align plane to curve. NOT YET IMPLEMENTED.
@@ -453,10 +466,10 @@ class plane:
if shape.isNull():
return False
elif shape.ShapeType == 'Edge':
#??? TODO: process curve here. look at shape.edges[0].Curve
# ??? TODO: process curve here. look at shape.edges[0].Curve
return False
elif shape.ShapeType == 'Wire':
#??? TODO: determine if edges define a plane
# ??? TODO: determine if edges define a plane
return False
else:
return False
@@ -490,7 +503,7 @@ class plane:
v1.normalize()
v2.normalize()
v3.normalize()
#print v1,v2,v3
# print(v1,v2,v3)
self.u = v1
self.v = v2
self.axis = v3
@@ -519,7 +532,7 @@ class plane:
Returns
-------
bool
`True` if the operation was succesful, and `False` if the shape
`True` if the operation was successful, and `False` if the shape
is not a `'Face'`.
See Also
@@ -528,7 +541,9 @@ class plane:
"""
# Set face to the unique selected face, if found
if shape.ShapeType == 'Face':
self.alignToPointAndAxis(shape.Faces[0].CenterOfMass, shape.Faces[0].normalAt(0, 0), offset)
self.alignToPointAndAxis(shape.Faces[0].CenterOfMass,
shape.Faces[0].normalAt(0, 0),
offset)
import DraftGeomUtils
q = DraftGeomUtils.getQuad(shape)
if q:
@@ -570,7 +585,7 @@ class plane:
Returns
-------
bool
`True` if the operation was succesful, and `False` otherwise.
`True` if the operation was successful, and `False` otherwise.
"""
import Part
w = Part.makePolygon([p1, p2, p3, p1])
@@ -597,7 +612,7 @@ class plane:
Returns
-------
bool
`True` if the operation was succesful, and `False` otherwise.
`True` if the operation was successful, and `False` otherwise.
It returns `False` if the selection has no elements,
or if it has more than one element,
or if the object is not derived from `'Part::Feature'`
@@ -625,12 +640,13 @@ class plane:
if len(sex) == 0:
return False
elif len(sex) == 1:
if not sex[0].Object.isDerivedFrom("Part::Feature") \
or not sex[0].Object.Shape:
if (not sex[0].Object.isDerivedFrom("Part::Feature")
or not sex[0].Object.Shape):
return False
return self.alignToCurve(sex[0].Object.Shape, offset) \
or self.alignToFace(sex[0].Object.Shape, offset) \
or (len(sex[0].SubObjects) == 1 and self.alignToFace(sex[0].SubObjects[0], offset))
return (self.alignToFace(sex[0].Object.Shape, offset)
or (len(sex[0].SubObjects) == 1
and self.alignToFace(sex[0].SubObjects[0], offset))
or self.alignToCurve(sex[0].Object.Shape, offset))
else:
# len(sex) > 2, look for point and line, three points, etc.
return False
@@ -673,12 +689,19 @@ class plane:
try:
import FreeCADGui
from pivy import coin
rot = FreeCADGui.ActiveDocument.ActiveView.getCameraNode().getField("orientation").getValue()
upvec = Vector(rot.multVec(coin.SbVec3f(0, 1, 0)).getValue())
vdir = FreeCADGui.ActiveDocument.ActiveView.getViewDirection()
if (vdir.getAngle(self.axis) > 0.001) and (vdir.getAngle(self.axis) < 3.14159):
# don't change the WP if it is already perpendicular to the current view
self.alignToPointAndAxis(Vector(0, 0, 0), vdir.negative(), 0, upvec)
view = FreeCADGui.ActiveDocument.ActiveView
camera = view.getCameraNode()
rot = camera.getField("orientation").getValue()
coin_up = coin.SbVec3f(0, 1, 0)
upvec = Vector(rot.multVec(coin_up).getValue())
vdir = view.getViewDirection()
# The angle is between 0 and 180 degrees.
angle = vdir.getAngle(self.axis)
if (angle > 0.001) and (angle < 3.14159):
# don't change the plane if it is already
# perpendicular to the current view
self.alignToPointAndAxis(Vector(0, 0, 0),
vdir.negative(), 0, upvec)
except:
pass
self.weak = True
@@ -709,8 +732,9 @@ class plane:
# Arch active container
if FreeCAD.GuiUp:
import FreeCADGui
if FreeCADGui.ActiveDocument.ActiveView:
a = FreeCADGui.ActiveDocument.ActiveView.getActiveObject("Arch")
view = FreeCADGui.ActiveDocument.ActiveView
if view:
a = view.getActiveObject("Arch")
if a:
p = a.Placement.inverse().multiply(p)
return p
@@ -744,9 +768,10 @@ class plane:
0.0, 0.0, 0.0, 1.0)
p = FreeCAD.Placement(m)
# Arch active container if based on App Part
#if FreeCAD.GuiUp:
# if FreeCAD.GuiUp:
# import FreeCADGui
# a = FreeCADGui.ActiveDocument.ActiveView.getActiveObject("Arch")
# view = FreeCADGui.ActiveDocument.ActiveView
# a = view.getActiveObject("Arch")
# if a:
# p = a.Placement.inverse().multiply(p)
return p
@@ -761,9 +786,10 @@ class plane:
"""
n = self.axis
# Arch active container if based on App Part
#if FreeCAD.GuiUp:
# if FreeCAD.GuiUp:
# import FreeCADGui
# a = FreeCADGui.ActiveDocument.ActiveView.getActiveObject("Arch")
# view = FreeCADGui.ActiveDocument.ActiveView
# a = view.getActiveObject("Arch")
# if a:
# n = a.Placement.inverse().Rotation.multVec(n)
return n
@@ -818,7 +844,6 @@ class plane:
Restores the attributes `u`, `v`, `axis`, `position` and `weak`
from `stored`, and set `stored` to `None`.
"""
"restores a previously saved plane state, if exists"
if self.stored:
self.u = self.stored[0]
self.v = self.stored[1]
@@ -1071,22 +1096,30 @@ class plane:
def isOrtho(self):
"""Return True if the plane axes are orthogonal with the global axes.
Orthogonal means that the angle between `u` and the global axis `+X`
Orthogonal means that the angle between `u` and the global axis `+Y`
is a multiple of 90 degrees, meaning 0, -90, 90, -180, 180,
-270, 270, or 360 degrees.
And similarly for `v` and `axis` with `+Y` and `+Z`, respectively.
And similarly for `v` and `axis`.
All three axes should be orthogonal to the `+Y` axis.
Due to rounding errors, the angle difference is rounded
to 6 decimal digits to do the test.
Returns
-------
bool
Returns `True` if all three `u`, `v`, and `axis`
are orthogonal with their respective global axes `+X`, `+Y`,
and `+Z`.
are orthogonal with the global axis `+Y`.
Otherwise it returns `False`.
"""
if round(self.u.getAngle(Vector(0, 1, 0)), 6) in [0, -1.570796, 1.570796, -3.141593, 3.141593, -4.712389, 4.712389, 6.283185]:
if round(self.v.getAngle(Vector(0, 1, 0)), 6) in [0, -1.570796, 1.570796, -3.141593, 3.141593, -4.712389, 4.712389, 6.283185]:
if round(self.axis.getAngle(Vector(0, 1, 0)), 6) in [0, -1.570796, 1.570796, -3.141593, 3.141593, -4.712389, 4.712389, 6.283185]:
ortho = [0, -1.570796, 1.570796,
-3.141593, 3.141593,
-4.712389, 4.712389, 6.283185]
# Shouldn't the angle difference be calculated with
# the other global axes `+X` and `+Z` as well?
if round(self.u.getAngle(Vector(0, 1, 0)), 6) in ortho:
if round(self.v.getAngle(Vector(0, 1, 0)), 6) in ortho:
if round(self.axis.getAngle(Vector(0, 1, 0)), 6) in ortho:
return True
return False
+191 -60
View File
@@ -1,45 +1,80 @@
# -*- coding: utf8 -*-
#***************************************************************************
#* *
#* Copyright (c) 2009 Yorik van Havre <[email protected]> *
#* *
#* 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 *
#* *
#***************************************************************************
"FreeCAD Draft Workbench - DWG importer/exporter"
## @package importDWG
# \ingroup DRAFT
# \brief DWG file importer & exporter
#
# This module provides support for importing and exporting Autodesk DWG files.
# This module is only a thin layer that uses the ODA (formerly Teigha) File
# Converter application to convert to/from DXF. Then the real work is done by
# importDXF
'''
@package importDWG
ingroup DRAFT
\brief DWG file importer & exporter
This module provides support for importing and exporting Autodesk DWG files.
This module is only a thin layer that uses the ODA (formerly Teigha) File
Converter application to convert to/from DXF. Then the real work is done by
importDXF
The converter may be called
/usr/bin/TeighaFileConverter
/usr/bin/ODAFileConverter
Test files
https://knowledge.autodesk.com/support/autocad/downloads/
caas/downloads/content/autocad-sample-files.html
'''
# Check code quality with
# flake8 --ignore=E226,E266,E401,W503
# ***************************************************************************
# * *
# * Copyright (c) 2009 Yorik van Havre <[email protected]> *
# * *
# * 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 *
# * *
# ***************************************************************************
# TODO: use subprocess.popen() instead of subprocess.call()
import six
import FreeCAD
from FreeCAD import Console as FCC
if FreeCAD.GuiUp:
from DraftTools import translate
else:
def translate(context, txt):
return txt
# Save the native open function to avoid collisions
if open.__module__ == '__builtin__':
pythonopen = open # to distinguish python built-in open function from the one declared here
pythonopen = open
def open(filename):
"called when freecad opens a file."
"""Open filename and parse using importDXF.open().
Parameters
----------
filename : str
The path to the filename to be opened.
Returns
-------
App::Document
The new FreeCAD document object created, with the parsed information.
"""
dxf = convertToDxf(filename)
if dxf:
import importDXF
@@ -47,27 +82,79 @@ def open(filename):
return doc
return
def insert(filename,docname):
"called when freecad imports a file"
def insert(filename, docname):
"""Imports a file using importDXF.insert().
If no document exist, it is created.
Parameters
----------
filename : str
The path to the filename to be opened.
docname : str
The name of the active App::Document if one exists, or
of the new one created.
Returns
-------
App::Document
The active FreeCAD document, or the document created if none exists,
with the parsed information.
"""
dxf = convertToDxf(filename)
if dxf:
import importDXF
doc = importDXF.insert(dxf,docname)
# Warning: function doesn't return?
doc = importDXF.insert(dxf, docname)
return doc
return
def export(objectslist,filename):
"called when freecad exports a file"
import importDXF,os,tempfile
def export(objectslist, filename):
"""Export the DWG file with a given list of objects.
The objects are exported with importDXF.export().
Then the result is converted to DWG.
Parameters
----------
exportList : list
List of document objects to export.
filename : str
Path to the new file.
Returns
-------
str
The same `filename` input.
"""
import importDXF, os, tempfile
outdir = tempfile.mkdtemp()
dxf = outdir + os.sep + os.path.splitext(os.path.basename(filename))[0] + ".dxf"
importDXF.export(objectslist,dxf)
convertToDwg(dxf,filename)
_basename = os.path.splitext(os.path.basename(filename))[0]
dxf = outdir + os.sep + _basename + ".dxf"
importDXF.export(objectslist, dxf)
convertToDwg(dxf, filename)
return filename
def getTeighaConverter():
import FreeCAD,os,platform
"finds the Teigha Converter executable"
"""Find the ODA (formerly Teigha) executable.
It searches the FreeCAD parameters database, then searches for common
paths in Linux and Windows systems.
Parameters
----------
None
Returns
-------
str
The full path of the converter executable
'/usr/bin/TeighaFileConverter'
"""
import FreeCAD, os, platform
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
p = p.GetString("TeighaFileConverter")
if p:
@@ -78,55 +165,99 @@ def getTeighaConverter():
teigha = None
if platform.system() == "Linux":
teigha = "/usr/bin/TeighaFileConverter"
if not os.path.exists(teigha):
teigha = "/usr/bin/ODAFileConverter"
elif platform.system() == "Windows":
odadir = os.path.expandvars("%ProgramFiles%\ODA")
if os.path.exists(odadir):
subdirs = os.walk(odadir).next()[1]
for sub in subdirs:
t = odadir + os.sep + sub + os.sep + "TeighaFileConverter.exe"
t = (odadir + os.sep + sub + os.sep
+ "TeighaFileConverter.exe")
t = os.path.join(odadir, sub, "TeighaFileConverter.exe")
if os.path.exists(t):
teigha = t
if teigha:
if os.path.exists(teigha):
return teigha
from DraftTools import translate
FreeCAD.Console.PrintMessage(translate("draft","ODA (formerly Teigha) File Converter not found, DWG support is disabled")+"\n")
_msg = ("ODA (formerly Teigha) File Converter not found, "
"DWG support is disabled")
FCC.PrintMessage(translate("draft", _msg) + "\n")
return None
def convertToDxf(dwgfilename):
"converts a DWG file to DXF"
import os,tempfile,subprocess,sys #import os,tempfile
"""Convert a DWG file to a DXF file.
If the converter is found it is used, otherwise the convesion fails.
Parameters
----------
dwgfilename : str
The input filename.
Returns
-------
str
The new file produced.
"""
import os, tempfile, subprocess, sys
teigha = getTeighaConverter()
if teigha:
indir = os.path.dirname(dwgfilename)
outdir = tempfile.mkdtemp()
basename = os.path.basename(dwgfilename)
cmdline = '"%s" "%s" "%s" "ACAD2000" "DXF" "0" "1" "%s"' % (teigha, indir, outdir, basename)
print("Converting: " + cmdline)
cmdline = ('"%s" "%s" "%s" "ACAD2000" "DXF" "0" "1" "%s"'
% (teigha, indir, outdir, basename))
FCC.PrintMessage(translate("ImportDWG", "Converting: ")
+ cmdline + "\n")
if six.PY2:
if isinstance(cmdline,six.text_type):
if isinstance(cmdline, six.text_type):
encoding = sys.getfilesystemencoding()
cmdline = cmdline.encode(encoding)
subprocess.call(cmdline, shell=True) #os.system(cmdline)
subprocess.call(cmdline, shell=True) # os.system(cmdline)
result = outdir + os.sep + os.path.splitext(basename)[0] + ".dxf"
if os.path.exists(result):
print("Conversion successful")
FCC.PrintMessage(translate("ImportDWG",
"Conversion successful") + "\n")
return result
else:
print("Error during DWG to DXF conversion. Try moving the DWG file to a directory path")
print("without spaces and non-english characters, or try saving to a lower DWG version")
_msg = ("Error during DWG to DXF conversion. "
"Try moving the DWG file to a directory path\n"
"without spaces and non-english characters, "
"or try saving to a lower DWG version.")
FCC.PrintMessage(translate("ImportDWG", _msg) + "\n")
return None
def convertToDwg(dxffilename,dwgfilename):
"converts a DXF file to DWG"
import os,subprocess #import os
def convertToDwg(dxffilename, dwgfilename):
"""Convert a DXF file to a DWG file.
If the converter is found it is used, otherwise the convesion fails.
Parameters
----------
dxffilename : str
The input DXF file
dwgfilename : str
The output DWG file
Returns
-------
str
The same `dwgfilename` file path.
"""
import os, subprocess
teigha = getTeighaConverter()
if teigha:
indir = os.path.dirname(dxffilename)
outdir = os.path.dirname(dwgfilename)
basename = os.path.basename(dxffilename)
cmdline = '"%s" "%s" "%s" "ACAD2000" "DWG" "0" "1" "%s"' % (teigha, indir, outdir, basename)
print("converting " + cmdline)
subprocess.call(cmdline, shell=True) #os.system(cmdline)
cmdline = ('"%s" "%s" "%s" "ACAD2000" "DWG" "0" "1" "%s"'
% (teigha, indir, outdir, basename))
FCC.PrintMessage(translate("ImportDWG", "Converting: ")
+ cmdline + "\n")
subprocess.call(cmdline, shell=True) # os.system(cmdline)
return dwgfilename
return None
+1 -84
View File
@@ -743,7 +743,6 @@ class svgHandler(xml.sax.ContentHandler):
ret = msgBox.exec_()
if ret == QtGui.QMessageBox.Yes:
self.svgdpi = 96.0
<<<<<<< HEAD
else:
self.svgdpi = 90.0
if ret:
@@ -751,88 +750,6 @@ class svgHandler(xml.sax.ContentHandler):
FCC.PrintMessage(translate("ImportSVG", _qst) + "\n")
FCC.PrintMessage("*** User specified "
+ str(self.svgdpi) + " dpi ***\n")
=======
if 'style' in data:
if not data['style']:
pass#empty style attribute stops inheriting from parent
else:
content = data['style'].replace(' ','')
content = content.split(';')
for i in content:
pair = i.split(':')
if len(pair)>1: data[pair[0]]=pair[1]
for k in ['x','y','x1','y1','x2','y2','r','rx','ry','cx','cy','width','height']:
if k in data:
data[k] = getsize(data[k][0],'css'+str(self.svgdpi))
for k in ['fill','stroke','stroke-width','font-size']:
if k in data:
if isinstance(data[k],list):
if data[k][0].lower().startswith("rgb("):
data[k] = ",".join(data[k])
else:
data[k]=data[k][0]
# extracting style info
self.fill = None
self.color = None
self.width = None
self.text = None
if name == 'svg':
m=FreeCAD.Matrix()
if not self.disableUnitScaling:
if 'width' in data and 'height' in data and \
'viewBox' in data:
vbw=float(data['viewBox'][2])
vbh=float(data['viewBox'][3])
w=attrs.getValue('width')
h=attrs.getValue('height')
self.viewbox=(vbw,vbh)
if len(self.grouptransform)==0:
unitmode='mm'+str(self.svgdpi)
else: #nested svg element
unitmode='css'+str(self.svgdpi)
abw = getsize(w,unitmode)
abh = getsize(h,unitmode)
sx=abw/vbw
sy=abh/vbh
preservearstr=' '.join(data.get('preserveAspectRatio',[])).lower()
uniformscaling = round(sx/sy,5) == 1
if uniformscaling:
m.scale(Vector(sx,sy,1))
else:
FreeCAD.Console.PrintWarning('Scaling Factors do not match!!!\n')
if preservearstr.startswith('none'):
m.scale(Vector(sx,sy,1))
else: #preserve the aspect ratio
if preservearstr.endswith('slice'):
sxy=max(sx,sy)
else:
sxy=min(sx,sy)
m.scale(Vector(sxy,sxy,1))
elif len(self.grouptransform)==0:
#fallback to current dpi
m.scale(Vector(25.4/self.svgdpi,25.4/self.svgdpi,1))
self.grouptransform.append(m)
if 'fill' in data:
if data['fill'][0] != 'none':
self.fill = getcolor(data['fill'])
if 'stroke' in data:
if data['stroke'][0] != 'none':
self.color = getcolor(data['stroke'])
if 'stroke-width' in data:
if data['stroke-width'] != 'none':
self.width = getsize(data['stroke-width'],'css'+str(self.svgdpi))
if 'transform' in data:
m = self.getMatrix(attrs.getValue('transform'))
if name == "g":
self.grouptransform.append(m)
else:
self.transform = m
>>>>>>> 6d64c2b2c6bc64ce21e7c2f4ed7e1ab2c8991f8e
else:
self.svgdpi = 96.0
FCC.PrintMessage(_msg + "\n")
@@ -1569,7 +1486,7 @@ class svgHandler(xml.sax.ContentHandler):
obj.ViewObject.TextColor = (0.0, 0.0, 0.0, 0.0)
def endElement(self, name):
"""Finish procesing the element indicated by the name.
"""Finish processing the element indicated by the name.
Parameters
----------
+1 -1
View File
@@ -51,7 +51,7 @@ FreeCAD.addExportType("FEM mesh Z88 (*i1.txt)", "feminout.importZ88Mesh")
FreeCAD.addImportType("FEM result Z88 displacements (*o2.txt)", "feminout.importZ88O2Results")
if("BUILD_FEM_VTK" in FreeCAD.__cmake__):
if "BUILD_FEM_VTK" in FreeCAD.__cmake__:
FreeCAD.addImportType("FEM result VTK (*.vtk *.vtu)", "feminout.importVTKResults")
FreeCAD.addExportType("FEM result VTK (*.vtk *.vtu)", "feminout.importVTKResults")
+2 -1
View File
@@ -33,8 +33,9 @@ import FreeCAD
import FreeCADGui
class FemWorkbench (Workbench):
class FemWorkbench(Workbench):
"Fem workbench object"
def __init__(self):
self.__class__.Icon = FreeCAD.getResourceDir() + "Mod/Fem/Resources/icons/FemWorkbench.svg"
self.__class__.MenuText = "FEM"
+110 -110
View File
@@ -35,8 +35,8 @@ def makeAnalysis(
doc,
name="Analysis"
):
'''makeAnalysis(document, [name]):
makes a Fem Analysis object'''
"""makeAnalysis(document, [name]):
makes a Fem Analysis object"""
obj = doc.addObject("Fem::FemAnalysis", name)
return obj
@@ -46,8 +46,8 @@ def makeConstraintBearing(
doc,
name="ConstraintBearing"
):
'''makeConstraintBearing(document, [name]):
makes a Fem ConstraintBearing object'''
"""makeConstraintBearing(document, [name]):
makes a Fem ConstraintBearing object"""
obj = doc.addObject("Fem::ConstraintBearing", name)
return obj
@@ -56,8 +56,8 @@ def makeConstraintBodyHeatSource(
doc,
name="ConstraintBodyHeatSource"
):
'''makeConstraintBodyHeatSource(document, [name]):
makes a Fem ConstraintBodyHeatSource object'''
"""makeConstraintBodyHeatSource(document, [name]):
makes a Fem ConstraintBodyHeatSource object"""
obj = doc.addObject("Fem::ConstraintPython", name)
from femobjects import _FemConstraintBodyHeatSource
_FemConstraintBodyHeatSource.Proxy(obj)
@@ -71,8 +71,8 @@ def makeConstraintContact(
doc,
name="ConstraintContact"
):
'''makeConstraintContact(document, [name]):
makes a Fem ConstraintContact object'''
"""makeConstraintContact(document, [name]):
makes a Fem ConstraintContact object"""
obj = doc.addObject("Fem::ConstraintContact", name)
return obj
@@ -81,8 +81,8 @@ def makeConstraintDisplacement(
doc,
name="ConstraintDisplacement"
):
'''makeConstraintDisplacement(document, [name]):
makes a Fem ConstraintDisplacement object'''
"""makeConstraintDisplacement(document, [name]):
makes a Fem ConstraintDisplacement object"""
obj = doc.addObject("Fem::ConstraintDisplacement", name)
return obj
@@ -91,8 +91,8 @@ def makeConstraintElectrostaticPotential(
doc,
name="ConstraintElectrostaticPotential"
):
'''makeConstraintElectrostaticPotential(document, [name]):
makes a Fem ElectrostaticPotential object'''
"""makeConstraintElectrostaticPotential(document, [name]):
makes a Fem ElectrostaticPotential object"""
obj = doc.addObject("Fem::ConstraintPython", name)
from femobjects import _FemConstraintElectrostaticPotential
_FemConstraintElectrostaticPotential.Proxy(obj)
@@ -106,8 +106,8 @@ def makeConstraintFixed(
doc,
name="ConstraintFixed"
):
'''makeConstraintFixed(document, [name]):
makes a Fem ConstraintFixed object'''
"""makeConstraintFixed(document, [name]):
makes a Fem ConstraintFixed object"""
obj = doc.addObject("Fem::ConstraintFixed", name)
return obj
@@ -116,8 +116,8 @@ def makeConstraintFlowVelocity(
doc,
name="ConstraintFlowVelocity"
):
'''makeConstraintFlowVelocity(document, [name]):
makes a Fem ConstraintFlowVelocity object'''
"""makeConstraintFlowVelocity(document, [name]):
makes a Fem ConstraintFlowVelocity object"""
obj = doc.addObject("Fem::ConstraintPython", name)
from femobjects import _FemConstraintFlowVelocity
_FemConstraintFlowVelocity.Proxy(obj)
@@ -131,8 +131,8 @@ def makeConstraintFluidBoundary(
doc,
name="ConstraintFluidBoundary"
):
'''makeConstraintFluidBoundary(document, name):
makes a Fem ConstraintFluidBoundary object'''
"""makeConstraintFluidBoundary(document, name):
makes a Fem ConstraintFluidBoundary object"""
obj = doc.addObject("Fem::ConstraintFluidBoundary", name)
return obj
@@ -141,8 +141,8 @@ def makeConstraintForce(
doc,
name="ConstraintForce"
):
'''makeConstraintForce(document, [name]):
makes a Fem ConstraintForce object'''
"""makeConstraintForce(document, [name]):
makes a Fem ConstraintForce object"""
obj = doc.addObject("Fem::ConstraintForce", name)
return obj
@@ -151,8 +151,8 @@ def makeConstraintGear(
doc,
name="ConstraintGear"
):
'''makeConstraintGear(document, [name]):
makes a Fem ConstraintGear object'''
"""makeConstraintGear(document, [name]):
makes a Fem ConstraintGear object"""
obj = doc.addObject("Fem::ConstraintGear", name)
return obj
@@ -161,8 +161,8 @@ def makeConstraintHeatflux(
doc,
name="ConstraintHeatflux"
):
'''makeConstraintHeatflux(document, [name]):
makes a Fem ConstraintHeatflux object'''
"""makeConstraintHeatflux(document, [name]):
makes a Fem ConstraintHeatflux object"""
obj = doc.addObject("Fem::ConstraintHeatflux", name)
return obj
@@ -171,8 +171,8 @@ def makeConstraintInitialFlowVelocity(
doc,
name="ConstraintInitialFlowVelocity"
):
'''makeConstraintInitialFlowVelocity(document, [name]):
makes a Fem ConstraintInitialFlowVelocity object'''
"""makeConstraintInitialFlowVelocity(document, [name]):
makes a Fem ConstraintInitialFlowVelocity object"""
obj = doc.addObject("Fem::ConstraintPython", name)
from femobjects import _FemConstraintInitialFlowVelocity
_FemConstraintInitialFlowVelocity.Proxy(obj)
@@ -186,8 +186,8 @@ def makeConstraintInitialTemperature(
doc,
name="ConstraintInitialTemperature"
):
'''makeConstraintInitialTemperature(document, name):
makes a Fem ConstraintInitialTemperature object'''
"""makeConstraintInitialTemperature(document, name):
makes a Fem ConstraintInitialTemperature object"""
obj = doc.addObject("Fem::ConstraintInitialTemperature", name)
return obj
@@ -196,8 +196,8 @@ def makeConstraintPlaneRotation(
doc,
name="ConstraintPlaneRotation"
):
'''makeConstraintPlaneRotation(document, [name]):
makes a Fem ConstraintPlaneRotation object'''
"""makeConstraintPlaneRotation(document, [name]):
makes a Fem ConstraintPlaneRotation object"""
obj = doc.addObject("Fem::ConstraintPlaneRotation", name)
return obj
@@ -206,8 +206,8 @@ def makeConstraintPressure(
doc,
name="ConstraintPressure"
):
'''makeConstraintPressure(document, [name]):
makes a Fem ConstraintPressure object'''
"""makeConstraintPressure(document, [name]):
makes a Fem ConstraintPressure object"""
obj = doc.addObject("Fem::ConstraintPressure", name)
return obj
@@ -216,8 +216,8 @@ def makeConstraintPulley(
doc,
name="ConstraintPulley"
):
'''makeConstraintPulley(document, [name]):
makes a Fem ConstraintPulley object'''
"""makeConstraintPulley(document, [name]):
makes a Fem ConstraintPulley object"""
obj = doc.addObject("Fem::ConstraintPulley", name)
return obj
@@ -226,8 +226,8 @@ def makeConstraintSelfWeight(
doc,
name="ConstraintSelfWeight"
):
'''makeConstraintSelfWeight(document, [name]):
creates an self weight object to define a gravity load'''
"""makeConstraintSelfWeight(document, [name]):
creates an self weight object to define a gravity load"""
obj = doc.addObject("Fem::ConstraintPython", name)
from femobjects import _FemConstraintSelfWeight
_FemConstraintSelfWeight._FemConstraintSelfWeight(obj)
@@ -243,8 +243,8 @@ def makeConstraintTemperature(
doc,
name="ConstraintTemperature"
):
'''makeConstraintTemperature(document, [name]):
makes a Fem ConstraintTemperature object'''
"""makeConstraintTemperature(document, [name]):
makes a Fem ConstraintTemperature object"""
obj = doc.addObject("Fem::ConstraintTemperature", name)
return obj
@@ -253,8 +253,8 @@ def makeConstraintTransform(
doc,
name="ConstraintTransform"
):
'''makeConstraintTransform(document, [name]):
makes a Fem ConstraintTransform object'''
"""makeConstraintTransform(document, [name]):
makes a Fem ConstraintTransform object"""
obj = doc.addObject("Fem::ConstraintTransform", name)
return obj
@@ -264,8 +264,8 @@ def makeElementFluid1D(
doc,
name="ElementFluid1D"
):
'''makeElementFluid1D(document, [name]):
creates an 1D fluid element object to define 1D flow'''
"""makeElementFluid1D(document, [name]):
creates an 1D fluid element object to define 1D flow"""
obj = doc.addObject("Fem::FeaturePython", name)
from femobjects import _FemElementFluid1D
_FemElementFluid1D._FemElementFluid1D(obj)
@@ -277,13 +277,13 @@ def makeElementFluid1D(
def makeElementGeometry1D(
doc,
sectiontype='Rectangular',
sectiontype="Rectangular",
width=10.0,
height=25.0,
name="ElementGeometry1D"
):
'''makeElementGeometry1D(document, [width], [height], [name]):
creates an 1D geometry element object to define a cross section'''
"""makeElementGeometry1D(document, [width], [height], [name]):
creates an 1D geometry element object to define a cross section"""
obj = doc.addObject("Fem::FeaturePython", name)
from femobjects import _FemElementGeometry1D
_FemElementGeometry1D._FemElementGeometry1D(obj)
@@ -309,8 +309,8 @@ def makeElementGeometry2D(
thickness=20.0,
name="ElementGeometry2D"
):
'''makeElementGeometry2D(document, [thickness], [name]):
creates an 2D geometry element object to define a plate thickness'''
"""makeElementGeometry2D(document, [thickness], [name]):
creates an 2D geometry element object to define a plate thickness"""
obj = doc.addObject("Fem::FeaturePython", name)
from femobjects import _FemElementGeometry2D
_FemElementGeometry2D._FemElementGeometry2D(obj)
@@ -325,8 +325,8 @@ def makeElementRotation1D(
doc,
name="ElementRotation1D"
):
'''makeElementRotation1D(document, [name]):
creates an 1D geometry rotation element object to rotate a 1D cross section'''
"""makeElementRotation1D(document, [name]):
creates an 1D geometry rotation element object to rotate a 1D cross section"""
obj = doc.addObject("Fem::FeaturePython", name)
from femobjects import _FemElementRotation1D
_FemElementRotation1D._FemElementRotation1D(obj)
@@ -341,12 +341,12 @@ def makeMaterialFluid(
doc,
name="FluidMaterial"
):
'''makeMaterialFluid(document, [name]):
makes a FEM Material for fluid'''
"""makeMaterialFluid(document, [name]):
makes a FEM Material for fluid"""
obj = doc.addObject("App::MaterialObjectPython", name)
from femobjects import _FemMaterial
_FemMaterial._FemMaterial(obj)
obj.Category = 'Fluid'
obj.Category = "Fluid"
if FreeCAD.GuiUp:
from femguiobjects import _ViewProviderFemMaterial
_ViewProviderFemMaterial._ViewProviderFemMaterial(obj.ViewObject)
@@ -358,8 +358,8 @@ def makeMaterialMechanicalNonlinear(
base_material,
name="MechanicalMaterialNonlinear"
):
'''makeMaterialMechanicalNonlinear(document, base_material, [name]):
creates a nonlinear material object'''
"""makeMaterialMechanicalNonlinear(document, base_material, [name]):
creates a nonlinear material object"""
obj = doc.addObject("Fem::FeaturePython", name)
from femobjects import _FemMaterialMechanicalNonlinear
_FemMaterialMechanicalNonlinear._FemMaterialMechanicalNonlinear(obj)
@@ -376,8 +376,8 @@ def makeMaterialReinforced(
doc,
name="MaterialReinforced"
):
'''makeMaterialReinforced(document, [matrix_material], [reinforcement_material], [name]):
creates a reinforced material object'''
"""makeMaterialReinforced(document, [matrix_material], [reinforcement_material], [name]):
creates a reinforced material object"""
obj = doc.addObject("App::MaterialObjectPython", name)
from femobjects import _FemMaterialReinforced
_FemMaterialReinforced._FemMaterialReinforced(obj)
@@ -391,12 +391,12 @@ def makeMaterialSolid(
doc,
name="MechanicalSolidMaterial"
):
'''makeMaterialSolid(document, [name]):
makes a FEM Material for solid'''
"""makeMaterialSolid(document, [name]):
makes a FEM Material for solid"""
obj = doc.addObject("App::MaterialObjectPython", name)
from femobjects import _FemMaterial
_FemMaterial._FemMaterial(obj)
obj.Category = 'Solid'
obj.Category = "Solid"
if FreeCAD.GuiUp:
from femguiobjects import _ViewProviderFemMaterial
_ViewProviderFemMaterial._ViewProviderFemMaterial(obj.ViewObject)
@@ -409,8 +409,8 @@ def makeMeshBoundaryLayer(
base_mesh,
name="MeshBoundaryLayer"
):
'''makeMeshBoundaryLayer(document, base_mesh, [name]):
creates a FEM mesh BoundaryLayer object to define boundary layer properties'''
"""makeMeshBoundaryLayer(document, base_mesh, [name]):
creates a FEM mesh BoundaryLayer object to define boundary layer properties"""
obj = doc.addObject("Fem::FeaturePython", name)
from femobjects import _FemMeshBoundaryLayer
_FemMeshBoundaryLayer._FemMeshBoundaryLayer(obj)
@@ -430,8 +430,8 @@ def makeMeshGmsh(
doc,
name="MeshGmsh"
):
'''makeMeshGmsh(document, [name]):
makes a Gmsh FEM mesh object'''
"""makeMeshGmsh(document, [name]):
makes a Gmsh FEM mesh object"""
obj = doc.addObject("Fem::FemMeshObjectPython", name)
from femobjects import _FemMeshGmsh
_FemMeshGmsh._FemMeshGmsh(obj)
@@ -447,8 +447,8 @@ def makeMeshGroup(
use_label=False,
name="MeshGroup"
):
'''makeMeshGroup(document, base_mesh, [use_label], [name]):
creates a FEM mesh region object to define properties for a region of a FEM mesh'''
"""makeMeshGroup(document, base_mesh, [use_label], [name]):
creates a FEM mesh region object to define properties for a region of a FEM mesh"""
obj = doc.addObject("Fem::FeaturePython", name)
from femobjects import _FemMeshGroup
_FemMeshGroup._FemMeshGroup(obj)
@@ -469,8 +469,8 @@ def makeMeshNetgen(
doc,
name="MeshNetgen"
):
'''makeMeshNetgen(document, [name]):
makes a Fem MeshShapeNetgenObject object'''
"""makeMeshNetgen(document, [name]):
makes a Fem MeshShapeNetgenObject object"""
obj = doc.addObject("Fem::FemMeshShapeNetgenObject", name)
return obj
@@ -481,8 +481,8 @@ def makeMeshRegion(
element_length=0.0,
name="MeshRegion"
):
'''makeMeshRegion(document, base_mesh, [element_length], [name]):
creates a FEM mesh region object to define properties for a region of a FEM mesh'''
"""makeMeshRegion(document, base_mesh, [element_length], [name]):
creates a FEM mesh region object to define properties for a region of a FEM mesh"""
obj = doc.addObject("Fem::FeaturePython", name)
from femobjects import _FemMeshRegion
_FemMeshRegion._FemMeshRegion(obj)
@@ -503,7 +503,7 @@ def makeMeshResult(
doc,
name="MeshResult"
):
'''makeMeshResult(document, name): makes a Fem MeshResult object'''
"""makeMeshResult(document, name): makes a Fem MeshResult object"""
obj = doc.addObject("Fem::FemMeshObjectPython", name)
from femobjects import _FemMeshResult
_FemMeshResult._FemMeshResult(obj)
@@ -518,9 +518,9 @@ def makeResultMechanical(
doc,
name="MechanicalResult"
):
'''makeResultMechanical(document, [name]):
creates an mechanical result object to hold FEM results'''
obj = doc.addObject('Fem::FemResultObjectPython', name)
"""makeResultMechanical(document, [name]):
creates an mechanical result object to hold FEM results"""
obj = doc.addObject("Fem::FemResultObjectPython", name)
from femobjects import _FemResultMechanical
_FemResultMechanical._FemResultMechanical(obj)
if FreeCAD.GuiUp:
@@ -534,8 +534,8 @@ def makePostVtkFilterClipRegion(
base_vtk_result,
name="VtkFilterClipRegion"
):
'''makePostVtkFilterClipRegion(document, base_vtk_result, [name]):
creates an FEM post processing region clip filter object (vtk based)'''
"""makePostVtkFilterClipRegion(document, base_vtk_result, [name]):
creates an FEM post processing region clip filter object (vtk based)"""
obj = doc.addObject("Fem::FemPostClipFilter", name)
tmp_filter_list = base_vtk_result.Filter
tmp_filter_list.append(obj)
@@ -549,8 +549,8 @@ def makePostVtkFilterClipScalar(
base_vtk_result,
name="VtkFilterClipScalar"
):
'''makePostVtkFilterClipScalar(document, base_vtk_result, [name]):
creates an FEM post processing scalar clip filter object (vtk based)'''
"""makePostVtkFilterClipScalar(document, base_vtk_result, [name]):
creates an FEM post processing scalar clip filter object (vtk based)"""
obj = doc.addObject("Fem::FemPostScalarClipFilter", name)
tmp_filter_list = base_vtk_result.Filter
tmp_filter_list.append(obj)
@@ -564,8 +564,8 @@ def makePostVtkFilterCutFunction(
base_vtk_result,
name="VtkFilterCutFunction"
):
'''makePostVtkFilterCutFunction(document, base_vtk_result, [name]):
creates an FEM post processing cut function filter object (vtk based)'''
"""makePostVtkFilterCutFunction(document, base_vtk_result, [name]):
creates an FEM post processing cut function filter object (vtk based)"""
obj = doc.addObject("Fem::FemPostClipFilter", name)
tmp_filter_list = base_vtk_result.Filter
tmp_filter_list.append(obj)
@@ -579,8 +579,8 @@ def makePostVtkFilterWarp(
base_vtk_result,
name="VtkFilterWarp"
):
'''makePostVtkFilterWarp(document, base_vtk_result, [name]):
creates an FEM post processing warp filter object (vtk based)'''
"""makePostVtkFilterWarp(document, base_vtk_result, [name]):
creates an FEM post processing warp filter object (vtk based)"""
obj = doc.addObject("Fem::FemPostWarpVectorFilter", name)
tmp_filter_list = base_vtk_result.Filter
tmp_filter_list.append(obj)
@@ -593,8 +593,8 @@ def makePostVtkResult(
doc, base_result,
name="VtkResult"
):
'''makePostVtkResult(document, base_result [name]):
creates an FEM post processing result object (vtk based) to hold FEM results'''
"""makePostVtkResult(document, base_result [name]):
creates an FEM post processing result object (vtk based) to hold FEM results"""
obj = doc.addObject("Fem::FemPostPipeline", name)
obj.load(base_result)
return obj
@@ -605,10 +605,10 @@ def makeEquationElasticity(
doc,
base_solver
):
'''makeEquationElasticity(document, base_solver):
creates a FEM elasticity equation for a solver'''
"""makeEquationElasticity(document, base_solver):
creates a FEM elasticity equation for a solver"""
obj = doc.SolverElmer.addObject(
doc.SolverElmer.Proxy.createEquation(doc.SolverElmer.Document, 'Elasticity')
doc.SolverElmer.Proxy.createEquation(doc.SolverElmer.Document, "Elasticity")
)[0]
return obj
@@ -617,10 +617,10 @@ def makeEquationElectrostatic(
doc,
base_solver
):
'''makeEquationElectrostatic(document, base_solver):
creates a FEM electrostatic equation for a solver'''
"""makeEquationElectrostatic(document, base_solver):
creates a FEM electrostatic equation for a solver"""
obj = doc.SolverElmer.addObject(
doc.SolverElmer.Proxy.createEquation(doc.SolverElmer.Document, 'Electrostatic')
doc.SolverElmer.Proxy.createEquation(doc.SolverElmer.Document, "Electrostatic")
)[0]
return obj
@@ -629,10 +629,10 @@ def makeEquationFlow(
doc,
base_solver
):
'''makeEquationFlow(document, base_solver):
creates a FEM flow equation for a solver'''
"""makeEquationFlow(document, base_solver):
creates a FEM flow equation for a solver"""
obj = doc.SolverElmer.addObject(
doc.SolverElmer.Proxy.createEquation(doc.SolverElmer.Document, 'Flow')
doc.SolverElmer.Proxy.createEquation(doc.SolverElmer.Document, "Flow")
)[0]
return obj
@@ -641,10 +641,10 @@ def makeEquationFluxsolver(
doc,
base_solver
):
'''makeEquationFluxsolver(document, base_solver):
creates a FEM fluxsolver equation for a solver'''
"""makeEquationFluxsolver(document, base_solver):
creates a FEM fluxsolver equation for a solver"""
obj = doc.SolverElmer.addObject(
doc.SolverElmer.Proxy.createEquation(doc.SolverElmer.Document, 'Fluxsolver')
doc.SolverElmer.Proxy.createEquation(doc.SolverElmer.Document, "Fluxsolver")
)[0]
return obj
@@ -653,10 +653,10 @@ def makeEquationHeat(
doc,
base_solver
):
'''makeEquationHeat(document, base_solver):
creates a FEM heat equation for a solver'''
"""makeEquationHeat(document, base_solver):
creates a FEM heat equation for a solver"""
obj = doc.SolverElmer.addObject(
doc.SolverElmer.Proxy.createEquation(doc.SolverElmer.Document, 'Heat')
doc.SolverElmer.Proxy.createEquation(doc.SolverElmer.Document, "Heat")
)[0]
return obj
@@ -665,8 +665,8 @@ def makeSolverCalculixCcxTools(
doc,
name="CalculiXccxTools"
):
'''makeSolverCalculixCcxTools(document, [name]):
makes a Calculix solver object for the ccx tools module'''
"""makeSolverCalculixCcxTools(document, [name]):
makes a Calculix solver object for the ccx tools module"""
obj = doc.addObject("Fem::FemSolverObjectPython", name)
from femobjects import _FemSolverCalculix
_FemSolverCalculix._FemSolverCalculix(obj)
@@ -680,8 +680,8 @@ def makeSolverCalculix(
doc,
name="SolverCalculiX"
):
'''makeSolverCalculix(document, [name]):
makes a Calculix solver object'''
"""makeSolverCalculix(document, [name]):
makes a Calculix solver object"""
import femsolver.calculix.solver
obj = femsolver.calculix.solver.create(doc, name)
return obj
@@ -691,8 +691,8 @@ def makeSolverElmer(
doc,
name="SolverElmer"
):
'''makeSolverElmer(document, [name]):
makes a Elmer solver object'''
"""makeSolverElmer(document, [name]):
makes a Elmer solver object"""
import femsolver.elmer.solver
obj = femsolver.elmer.solver.create(doc, name)
return obj
@@ -702,21 +702,21 @@ def makeSolverZ88(
doc,
name="SolverZ88"
):
'''makeSolverZ88(document, [name]):
makes a Z88 solver object'''
"""makeSolverZ88(document, [name]):
makes a Z88 solver object"""
import femsolver.z88.solver
obj = femsolver.z88.solver.create(doc, name)
return obj
'''
"""
# get the supportedTypes
App.newDocument()
module = 'Fem'
FreeCADGui.doCommand('import ' + module)
module = "Fem"
FreeCADGui.doCommand("import " + module)
for s in sorted(App.ActiveDocument.supportedTypes()):
if s.startswith(module):
print(s)
'''
"""
## @}
+2 -2
View File
@@ -58,7 +58,7 @@ False if TestSolverFrameWork.__name__ else True
# in tearDown method to not close the document
'''
"""
# examples from within FreeCAD:
# all FEM tests
import Test, TestFem
@@ -277,4 +277,4 @@ doc = FreeCAD.open(app_home + 'data/examples/FemCalculixCantilever3D_newSolver.F
doc = FreeCAD.open(app_home + 'data/examples/Fem.FCStd')
doc = FreeCAD.open(app_home + 'data/examples/Fem2.FCStd')
'''
"""
File diff suppressed because it is too large Load Diff
+311 -276
View File
@@ -30,6 +30,7 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
import femtools.femutils as femutils
if FreeCAD.GuiUp:
import FreeCADGui
import FemGui
@@ -37,304 +38,338 @@ if FreeCAD.GuiUp:
class CommandManager(object):
def __init__(self):
self.resources = {
'Pixmap': 'FemWorkbench',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Fem_Command", "Default Fem Command MenuText"),
'Accel': "",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Fem_Command", "Default Fem Command ToolTip")
}
# FIXME add option description
self.is_active = None
self.selobj = None
self.selobj2 = None
self.active_analysis = None
def GetResources(self):
return self.resources
def __init__(self):
self.resources = {
"Pixmap": "FemWorkbench",
"MenuText": QtCore.QT_TRANSLATE_NOOP("Fem_Command", "Default Fem Command MenuText"),
"Accel": "",
"ToolTip": QtCore.QT_TRANSLATE_NOOP("Fem_Command", "Default Fem Command ToolTip")
}
# FIXME add option description
self.is_active = None
self.selobj = None
self.selobj2 = None
self.active_analysis = None
def IsActive(self):
if not self.is_active:
active = False
elif self.is_active == 'allways':
active = True
elif self.is_active == 'with_document':
active = FreeCADGui.ActiveDocument is not None
elif self.is_active == 'with_analysis':
active = FemGui.getActiveAnalysis() is not None \
and self.active_analysis_in_active_doc()
elif self.is_active == 'with_results':
active = FemGui.getActiveAnalysis() is not None \
and self.active_analysis_in_active_doc() \
and (self.results_present() or self.result_mesh_present())
elif self.is_active == 'with_selresult':
active = FemGui.getActiveAnalysis() is not None \
and self.active_analysis_in_active_doc() \
and self.result_selected()
elif self.is_active == 'with_part_feature':
active = FreeCADGui.ActiveDocument is not None \
and self.part_feature_selected()
elif self.is_active == 'with_femmesh':
active = FreeCADGui.ActiveDocument is not None \
and self.femmesh_selected()
elif self.is_active == 'with_gmsh_femmesh':
active = FreeCADGui.ActiveDocument is not None \
and self.gmsh_femmesh_selected()
elif self.is_active == 'with_femmesh_andor_res':
active = FreeCADGui.ActiveDocument is not None \
and self.with_femmesh_andor_res_selected()
elif self.is_active == 'with_material':
active = FemGui.getActiveAnalysis() is not None \
and self.active_analysis_in_active_doc() \
and self.material_selected()
elif self.is_active == 'with_material_solid_which_has_no_nonlinear_material':
active = FemGui.getActiveAnalysis() is not None \
and self.active_analysis_in_active_doc() \
and self.material_solid_selected() \
and self.has_no_nonlinear_material()
elif self.is_active == 'with_solver':
active = FemGui.getActiveAnalysis() is not None \
and self.active_analysis_in_active_doc() \
and self.solver_selected()
elif self.is_active == 'with_solver_elmer':
active = FemGui.getActiveAnalysis() is not None \
and self.active_analysis_in_active_doc() \
and self.solver_elmer_selected()
elif self.is_active == 'with_analysis_without_solver':
active = FemGui.getActiveAnalysis() is not None \
and self.active_analysis_in_active_doc() \
and not self.analysis_has_solver()
return active
def GetResources(self):
return self.resources
def results_present(self):
results = False
analysis_members = FemGui.getActiveAnalysis().Group
for o in analysis_members:
if o.isDerivedFrom('Fem::FemResultObject'):
results = True
return results
def IsActive(self):
if not self.is_active:
active = False
elif self.is_active == "allways":
active = True
elif self.is_active == "with_document":
active = FreeCADGui.ActiveDocument is not None
elif self.is_active == "with_analysis":
active = (
FemGui.getActiveAnalysis() is not None
and self.active_analysis_in_active_doc()
)
elif self.is_active == "with_results":
active = (
FemGui.getActiveAnalysis() is not None
and self.active_analysis_in_active_doc()
and (self.results_present() or self.result_mesh_present())
)
elif self.is_active == "with_selresult":
active = (
FemGui.getActiveAnalysis() is not None
and self.active_analysis_in_active_doc()
and self.result_selected()
)
elif self.is_active == "with_part_feature":
active = (
FreeCADGui.ActiveDocument is not None
and self.part_feature_selected()
)
elif self.is_active == "with_femmesh":
active = (
FreeCADGui.ActiveDocument is not None
and self.femmesh_selected()
)
elif self.is_active == "with_gmsh_femmesh":
active = (
FreeCADGui.ActiveDocument is not None
and self.gmsh_femmesh_selected()
)
elif self.is_active == "with_femmesh_andor_res":
active = (
FreeCADGui.ActiveDocument is not None
and self.with_femmesh_andor_res_selected()
)
elif self.is_active == "with_material":
active = (
FemGui.getActiveAnalysis() is not None
and self.active_analysis_in_active_doc()
and self.material_selected()
)
elif self.is_active == "with_material_solid_which_has_no_nonlinear_material":
active = (
FemGui.getActiveAnalysis() is not None
and self.active_analysis_in_active_doc()
and self.material_solid_selected()
and self.has_no_nonlinear_material()
)
elif self.is_active == "with_solver":
active = (
FemGui.getActiveAnalysis() is not None
and self.active_analysis_in_active_doc()
and self.solver_selected()
)
elif self.is_active == "with_solver_elmer":
active = (
FemGui.getActiveAnalysis() is not None
and self.active_analysis_in_active_doc()
and self.solver_elmer_selected()
)
elif self.is_active == "with_analysis_without_solver":
active = (
FemGui.getActiveAnalysis() is not None
and self.active_analysis_in_active_doc()
and not self.analysis_has_solver()
)
return active
def result_mesh_present(self):
result_mesh = False
analysis_members = FemGui.getActiveAnalysis().Group
for o in analysis_members:
if femutils.is_of_type(o, 'Fem::FemMeshResult'):
result_mesh = True
return result_mesh
def results_present(self):
results = False
analysis_members = FemGui.getActiveAnalysis().Group
for o in analysis_members:
if o.isDerivedFrom("Fem::FemResultObject"):
results = True
return results
def result_selected(self):
sel = FreeCADGui.Selection.getSelection()
if len(sel) == 1 and sel[0].isDerivedFrom("Fem::FemResultObject"):
for o in FemGui.getActiveAnalysis().Group:
if o == sel[0]:
self.selobj = o
return True
def result_mesh_present(self):
result_mesh = False
analysis_members = FemGui.getActiveAnalysis().Group
for o in analysis_members:
if femutils.is_of_type(o, "Fem::FemMeshResult"):
result_mesh = True
return result_mesh
def result_selected(self):
sel = FreeCADGui.Selection.getSelection()
if len(sel) == 1 and sel[0].isDerivedFrom("Fem::FemResultObject"):
for o in FemGui.getActiveAnalysis().Group:
if o == sel[0]:
self.selobj = o
return True
return False
def part_feature_selected(self):
sel = FreeCADGui.Selection.getSelection()
if len(sel) == 1 and sel[0].isDerivedFrom("Part::Feature"):
self.selobj = sel[0]
return True
else:
return False
def part_feature_selected(self):
sel = FreeCADGui.Selection.getSelection()
if len(sel) == 1 and sel[0].isDerivedFrom("Part::Feature"):
self.selobj = sel[0]
return True
else:
return False
def femmesh_selected(self):
sel = FreeCADGui.Selection.getSelection()
if len(sel) == 1 and sel[0].isDerivedFrom("Fem::FemMeshObject"):
self.selobj = sel[0]
return True
else:
return False
def gmsh_femmesh_selected(self):
sel = FreeCADGui.Selection.getSelection()
if len(sel) == 1 \
and hasattr(sel[0], "Proxy") \
and sel[0].Proxy.Type == "Fem::FemMeshGmsh":
self.selobj = sel[0]
return True
else:
return False
def material_selected(self):
sel = FreeCADGui.Selection.getSelection()
if len(sel) == 1 and sel[0].isDerivedFrom("App::MaterialObjectPython"):
return True
else:
return False
def material_solid_selected(self):
sel = FreeCADGui.Selection.getSelection()
if len(sel) == 1 \
and sel[0].isDerivedFrom("App::MaterialObjectPython") \
and hasattr(sel[0], "Category") \
and sel[0].Category == "Solid":
self.selobj = sel[0]
return True
else:
return False
def has_no_nonlinear_material(self):
"check if an nonlinear material exists which is already based on the selected material"
for o in FreeCAD.ActiveDocument.Objects:
if hasattr(o, "Proxy") \
and o.Proxy is not None \
and o.Proxy.Type == "Fem::MaterialMechanicalNonlinear" \
and o.LinearBaseMaterial == self.selobj:
FreeCAD.Console.PrintError(
'{} is based on the selected material: {}. '
'Only one nonlinear object for each material allowed.\n'
.format(o.Name, self.selobj)
)
return False
def femmesh_selected(self):
sel = FreeCADGui.Selection.getSelection()
if len(sel) == 1 and sel[0].isDerivedFrom("Fem::FemMeshObject"):
self.selobj = sel[0]
return True
else:
return False
def with_femmesh_andor_res_selected(self):
sel = FreeCADGui.Selection.getSelection()
if len(sel) == 1 and sel[0].isDerivedFrom("Fem::FemMeshObject"):
self.selobj = sel[0]
return True
elif len(sel) == 2:
if(sel[0].isDerivedFrom("Fem::FemMeshObject")):
if(sel[1].isDerivedFrom("Fem::FemResultObject")):
self.selobj = sel[0] # mesh
self.selobj2 = sel[1] # res
return True
else:
return False
elif(sel[1].isDerivedFrom("Fem::FemMeshObject")):
if(sel[0].isDerivedFrom("Fem::FemResultObject")):
self.selobj = sel[1] # mesh
self.selobj2 = sel[0] # res
return True
else:
return False
def gmsh_femmesh_selected(self):
sel = FreeCADGui.Selection.getSelection()
if (
len(sel) == 1
and hasattr(sel[0], "Proxy")
and sel[0].Proxy.Type == "Fem::FemMeshGmsh"
):
self.selobj = sel[0]
return True
else:
return False
def material_selected(self):
sel = FreeCADGui.Selection.getSelection()
if len(sel) == 1 and sel[0].isDerivedFrom("App::MaterialObjectPython"):
return True
else:
return False
def material_solid_selected(self):
sel = FreeCADGui.Selection.getSelection()
if (
len(sel) == 1
and sel[0].isDerivedFrom("App::MaterialObjectPython")
and hasattr(sel[0], "Category")
and sel[0].Category == "Solid"
):
self.selobj = sel[0]
return True
else:
return False
def has_no_nonlinear_material(self):
"check if an nonlinear material exists which is already based on the selected material"
for o in FreeCAD.ActiveDocument.Objects:
if (
hasattr(o, "Proxy")
and o.Proxy is not None
and o.Proxy.Type == "Fem::MaterialMechanicalNonlinear"
and o.LinearBaseMaterial == self.selobj
):
FreeCAD.Console.PrintError(
"{} is based on the selected material: {}. "
"Only one nonlinear object for each material allowed.\n"
.format(o.Name, self.selobj)
)
return False
return True
def with_femmesh_andor_res_selected(self):
sel = FreeCADGui.Selection.getSelection()
if len(sel) == 1 and sel[0].isDerivedFrom("Fem::FemMeshObject"):
self.selobj = sel[0]
return True
elif len(sel) == 2:
if sel[0].isDerivedFrom("Fem::FemMeshObject"):
if sel[1].isDerivedFrom("Fem::FemResultObject"):
self.selobj = sel[0] # mesh
self.selobj2 = sel[1] # res
return True
else:
return False
elif sel[1].isDerivedFrom("Fem::FemMeshObject"):
if sel[0].isDerivedFrom("Fem::FemResultObject"):
self.selobj = sel[1] # mesh
self.selobj2 = sel[0] # res
return True
else:
return False
else:
return False
else:
return False
def active_analysis_in_active_doc(self):
analysis = FemGui.getActiveAnalysis()
if analysis.Document is FreeCAD.ActiveDocument:
self.active_analysis = analysis
return True
else:
return False
def active_analysis_in_active_doc(self):
analysis = FemGui.getActiveAnalysis()
if analysis.Document is FreeCAD.ActiveDocument:
self.active_analysis = analysis
return True
else:
return False
def solver_selected(self):
sel = FreeCADGui.Selection.getSelection()
if len(sel) == 1 and sel[0].isDerivedFrom("Fem::FemSolverObjectPython"):
self.selobj = sel[0]
return True
else:
return False
def solver_selected(self):
sel = FreeCADGui.Selection.getSelection()
if len(sel) == 1 and sel[0].isDerivedFrom("Fem::FemSolverObjectPython"):
self.selobj = sel[0]
return True
else:
return False
def solver_elmer_selected(self):
sel = FreeCADGui.Selection.getSelection()
if len(sel) == 1 \
and hasattr(sel[0], "Proxy") \
and sel[0].Proxy.Type == "Fem::FemSolverObjectElmer":
self.selobj = sel[0]
return True
else:
return False
def solver_elmer_selected(self):
sel = FreeCADGui.Selection.getSelection()
if (
len(sel) == 1
and hasattr(sel[0], "Proxy")
and sel[0].Proxy.Type == "Fem::FemSolverObjectElmer"
):
self.selobj = sel[0]
return True
else:
return False
def analysis_has_solver(self):
solver = False
analysis_members = FemGui.getActiveAnalysis().Group
for o in analysis_members:
if o.isDerivedFrom("Fem::FemSolverObjectPython"):
solver = True
if solver is True:
return True
else:
return False
def analysis_has_solver(self):
solver = False
analysis_members = FemGui.getActiveAnalysis().Group
for o in analysis_members:
if o.isDerivedFrom("Fem::FemSolverObjectPython"):
solver = True
if solver is True:
return True
else:
return False
def hide_meshes_show_parts_constraints(self):
if FreeCAD.GuiUp:
for acnstrmesh in FemGui.getActiveAnalysis().Group:
if "Constraint" in acnstrmesh.TypeId:
acnstrmesh.ViewObject.Visibility = True
if "Mesh" in acnstrmesh.TypeId:
# OvG: Hide meshes and show constraints and meshed part
# e.g. on purging results
acnstrmesh.ViewObject.Visibility = False
def hide_meshes_show_parts_constraints(self):
if FreeCAD.GuiUp:
for acnstrmesh in FemGui.getActiveAnalysis().Group:
if "Constraint" in acnstrmesh.TypeId:
acnstrmesh.ViewObject.Visibility = True
if "Mesh" in acnstrmesh.TypeId:
# OvG: Hide meshes and show constraints and meshed part
# e.g. on purging results
acnstrmesh.ViewObject.Visibility = False
# ****************************************************************************************
# methods to add the objects to the document in FreeCADGui mode
# ****************************************************************************************
# methods to add the objects to the document in FreeCADGui mode
def add_obj_on_gui_set_edit(self, objtype):
FreeCAD.ActiveDocument.openTransaction(
"Create Fem{}"
.format(objtype)
)
FreeCADGui.addModule(
"ObjectsFem"
)
FreeCADGui.doCommand(
"FemGui.getActiveAnalysis().addObject(ObjectsFem."
"make{}(FreeCAD.ActiveDocument))"
.format(objtype)
)
# no other obj should be selected if we go in task panel
FreeCADGui.Selection.clearSelection()
FreeCADGui.doCommand(
"FreeCADGui.ActiveDocument.setEdit(FreeCAD.ActiveDocument.ActiveObject.Name)"
)
FreeCAD.ActiveDocument.recompute()
def add_obj_on_gui_set_edit(self, objtype):
FreeCAD.ActiveDocument.openTransaction(
"Create Fem{}"
.format(objtype)
)
FreeCADGui.addModule(
"ObjectsFem"
)
FreeCADGui.doCommand(
"FemGui.getActiveAnalysis().addObject(ObjectsFem."
"make{}(FreeCAD.ActiveDocument))"
.format(objtype)
)
# no other obj should be selected if we go in task panel
FreeCADGui.Selection.clearSelection()
FreeCADGui.doCommand(
"FreeCADGui.ActiveDocument.setEdit(FreeCAD.ActiveDocument.ActiveObject.Name)"
)
FreeCAD.ActiveDocument.recompute()
def add_obj_on_gui_noset_edit(self, objtype):
FreeCAD.ActiveDocument.openTransaction(
"Create Fem{}"
.format(objtype)
)
FreeCADGui.addModule(
"ObjectsFem"
)
FreeCADGui.doCommand(
"FemGui.getActiveAnalysis().addObject(ObjectsFem."
"make{}(FreeCAD.ActiveDocument))"
.format(objtype)
)
# FreeCAD.ActiveDocument.commitTransaction() # solver command class had this line
# no clear selection is done
FreeCAD.ActiveDocument.recompute()
def add_obj_on_gui_noset_edit(self, objtype):
FreeCAD.ActiveDocument.openTransaction(
"Create Fem{}"
.format(objtype)
)
FreeCADGui.addModule(
"ObjectsFem"
)
FreeCADGui.doCommand(
"FemGui.getActiveAnalysis().addObject(ObjectsFem."
"make{}(FreeCAD.ActiveDocument))"
.format(objtype)
)
# FreeCAD.ActiveDocument.commitTransaction() # solver command class had this line
# no clear selection is done
FreeCAD.ActiveDocument.recompute()
def add_obj_on_gui_selobj_set_edit(self, objtype):
FreeCAD.ActiveDocument.openTransaction(
"Create Fem{}"
.format(objtype)
)
FreeCADGui.addModule(
"ObjectsFem"
)
FreeCADGui.doCommand(
"ObjectsFem.make{}("
"FreeCAD.ActiveDocument, FreeCAD.ActiveDocument.{})"
.format(objtype, self.selobj.Name)
)
FreeCADGui.Selection.clearSelection()
FreeCADGui.doCommand(
"FreeCADGui.ActiveDocument.setEdit(FreeCAD.ActiveDocument.ActiveObject.Name)"
)
FreeCAD.ActiveDocument.recompute()
def add_obj_on_gui_selobj_set_edit(self, objtype):
FreeCAD.ActiveDocument.openTransaction(
"Create Fem{}"
.format(objtype)
)
FreeCADGui.addModule(
"ObjectsFem"
)
FreeCADGui.doCommand(
"ObjectsFem.make{}("
"FreeCAD.ActiveDocument, FreeCAD.ActiveDocument.{})"
.format(objtype, self.selobj.Name)
)
FreeCADGui.Selection.clearSelection()
FreeCADGui.doCommand(
"FreeCADGui.ActiveDocument.setEdit(FreeCAD.ActiveDocument.ActiveObject.Name)"
)
FreeCAD.ActiveDocument.recompute()
def add_obj_on_gui_selobj_noset_edit(self, objtype):
FreeCAD.ActiveDocument.openTransaction(
"Create Fem{}"
.format(objtype)
)
FreeCADGui.addModule(
"ObjectsFem"
)
FreeCADGui.doCommand(
"ObjectsFem.make{}("
"FreeCAD.ActiveDocument, FreeCAD.ActiveDocument.{})"
.format(objtype, self.selobj.Name)
)
FreeCADGui.Selection.clearSelection()
FreeCAD.ActiveDocument.recompute()
def add_obj_on_gui_selobj_noset_edit(self, objtype):
FreeCAD.ActiveDocument.openTransaction(
"Create Fem{}"
.format(objtype)
)
FreeCADGui.addModule(
"ObjectsFem"
)
FreeCADGui.doCommand(
"ObjectsFem.make{}("
"FreeCAD.ActiveDocument, FreeCAD.ActiveDocument.{})"
.format(objtype, self.selobj.Name)
)
FreeCADGui.Selection.clearSelection()
FreeCAD.ActiveDocument.recompute()
## @}
+21 -9
View File
@@ -803,9 +803,13 @@ class FemToolsCcx(QtCore.QRunnable, QtCore.QObject):
ccx_stdout = None
ccx_stderr = None
try:
p = subprocess.Popen([self.ccx_binary], stdout=subprocess.PIPE,
stderr=subprocess.PIPE, shell=False,
startupinfo=startup_info)
p = subprocess.Popen(
[self.ccx_binary],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=False,
startupinfo=startup_info
)
ccx_stdout, ccx_stderr = p.communicate()
if ccx_binary_sig in str(ccx_stdout):
self.ccx_binary_present = True
@@ -861,9 +865,13 @@ class FemToolsCcx(QtCore.QRunnable, QtCore.QObject):
cwd = QtCore.QDir.currentPath()
f = QtCore.QFileInfo(self.inp_file_name)
QtCore.QDir.setCurrent(f.path())
p = subprocess.Popen([self.ccx_binary, "-i ", f.baseName()],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
shell=False, env=_env)
p = subprocess.Popen(
[self.ccx_binary, "-i ", f.baseName()],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=False,
env=_env
)
self.ccx_stdout, self.ccx_stderr = p.communicate()
if sys.version_info.major >= 3:
self.ccx_stdout = self.ccx_stdout.decode()
@@ -884,9 +892,13 @@ class FemToolsCcx(QtCore.QRunnable, QtCore.QObject):
ccx_stdout = None
ccx_stderr = None
# Now extract the version number
p = subprocess.Popen([self.ccx_binary, '-v'], stdout=subprocess.PIPE,
stderr=subprocess.PIPE, shell=False,
startupinfo=startup_info)
p = subprocess.Popen(
[self.ccx_binary, '-v'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=False,
startupinfo=startup_info
)
ccx_stdout, ccx_stderr = p.communicate()
if sys.version_info.major >= 3:
ccx_stdout = ccx_stdout.decode()
@@ -141,8 +141,17 @@ class ObjectOp(PathOp.ObjectOp):
if shape.ShapeType == 'Edge' and type(shape.Curve) == Part.Circle:
return shape.Curve.Radius * 2
# for all other shapes the diameter is just the dimension in X
if shape.ShapeType == 'Face':
for i in range(len(shape.Edges)):
if (type(shape.Edges[i].Curve) == Part.Circle and
shape.Edges[i].Curve.Radius * 2 < shape.BoundBox.XLength*1.1 and
shape.Edges[i].Curve.Radius * 2 > shape.BoundBox.XLength*0.9):
return shape.Edges[i].Curve.Radius * 2
# for all other shapes the diameter is just the dimension in X. This may be inaccurate as the BoundBox is calculated on the tesselated geometry
PathLog.warning(translate("Path", "Hole diameter may be inaccurate due to tessellation on face. Consider selecting hole edge."))
return shape.BoundBox.XLength
except Part.OCCError as e:
PathLog.error(e)
+8 -13
View File
@@ -45,10 +45,10 @@ QGIArrow::QGIArrow() :
m_fill(Qt::SolidPattern),
m_size(5.0),
m_style(0),
m_flipped(false),
m_dirMode(false),
m_dir(Base::Vector3d(1.0,0.0,0.0))
{
isFlipped = false;
m_brush.setStyle(m_fill);
setCacheMode(QGraphicsItem::NoCache);
@@ -57,43 +57,38 @@ QGIArrow::QGIArrow() :
setFlag(QGraphicsItem::ItemIsMovable, false);
}
void QGIArrow::flip(bool state) {
isFlipped = state;
}
void QGIArrow::draw() {
QPainterPath path;
if (m_style == 0) {
if (m_dirMode) {
path = makeFilledTriangle(getDirection(), m_size,m_size/6.0);
} else {
path = makeFilledTriangle(m_size,m_size/6.0,isFlipped); //"arrow l/w sb 3/1" ??
path = makeFilledTriangle(m_size,m_size/6.0,isFlipped()); //"arrow l/w sb 3/1" ??
}
} else if (m_style == 1) {
if (m_dirMode) {
path = makeOpenArrow(getDirection(), m_size,m_size/3.0); //broad arrow?
} else {
path = makeOpenArrow(m_size,m_size/3.0,isFlipped);
path = makeOpenArrow(m_size,m_size/3.0,isFlipped());
}
} else if (m_style == 2) {
if (m_dirMode) {
path = makeHashMark(getDirection(), m_size/2.0,m_size/2.0); //big enough?
} else {
path = makeHashMark(m_size/2.0,m_size/2.0,isFlipped); //big enough?
path = makeHashMark(m_size/2.0,m_size/2.0,isFlipped()); //big enough?
}
} else if (m_style == 3) {
path = makeDot(m_size/2.0,m_size/2.0,isFlipped);
path = makeDot(m_size/2.0,m_size/2.0,isFlipped());
} else if (m_style == 4) {
path = makeOpenDot(m_size/2.0,m_size/2.0,isFlipped);
path = makeOpenDot(m_size/2.0,m_size/2.0,isFlipped());
} else if (m_style == 5) {
if (m_dirMode) {
path = makeForkArrow(getDirection(), m_size/2.0,m_size/2.0); //big enough?
} else {
path = makeForkArrow(m_size/2.0,m_size/2.0,isFlipped); //big enough?
path = makeForkArrow(m_size/2.0,m_size/2.0,isFlipped()); //big enough?
}
} else {
path = makeFilledTriangle(m_size,m_size/6.0,isFlipped); //sb a question mark or ???
path = makeFilledTriangle(m_size,m_size/6.0,isFlipped()); //sb a question mark or ???
}
setPath(path);
}
+6 -3
View File
@@ -46,15 +46,18 @@ public:
public:
void draw();
void flip(bool state);
bool isFlipped() { return m_flipped; }
void setFlipped(bool flipped) { m_flipped = flipped; }
void flip() { m_flipped = !m_flipped; }
double getSize() { return m_size; }
void setSize(double s);
int getStyle() { return m_style; }
void setStyle(int s) { m_style = s; }
bool getDirMode() { return m_dirMode; }
void setDirMode(bool b) { m_dirMode = b; }
Base::Vector3d getDirection(void) { return m_dir; }
Base::Vector3d getDirection(void) { return m_flipped ? -m_dir : m_dir; }
void setDirection(Base::Vector3d v) { m_dir = v; }
void setDirection(double angle) { m_dir = Base::Vector3d(cos(angle), sin(angle), 0.0); }
static int getPrefArrowStyle();
static double getPrefArrowSize();
static double getOverlapAdjust(int style, double size);
@@ -78,7 +81,7 @@ private:
Qt::BrushStyle m_fill;
double m_size;
int m_style;
bool isFlipped;
bool m_flipped;
bool m_dirMode;
Base::Vector3d m_dir;
};
+480 -124
View File
@@ -36,7 +36,7 @@
# include <QPaintDevice>
# include <QSvgGenerator>
# include <math.h>
# include <cmath>
#endif
#include <App/Application.h>
@@ -69,6 +69,11 @@
#include "ViewProviderDimension.h"
#include "DrawGuiUtil.h"
#ifndef M_2PI
// #define M_2PI 6.283185307179586476925287
#define M_2PI (M_PI * 2.0)
#endif
//TODO: hide the Qt coord system (+y down).
using namespace TechDraw;
@@ -182,8 +187,7 @@ void QGIDatumLabel::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt
QStyleOptionGraphicsItem myOption(*option);
myOption.state &= ~QStyle::State_Selected;
// painter->drawRect(boundingRect()); //good for debugging
//painter->drawRect(boundingRect()); //good for debugging
}
void QGIDatumLabel::setPosFromCenter(const double &xCenter, const double &yCenter)
@@ -1171,127 +1175,13 @@ void QGIViewDimension::draw()
// dim->getViewPart()->addVertex(curveCenter,true);
// }
} else if(strcmp(dimType, "Radius") == 0) {
// preferred terminology: Dimension Text, Dimension Line(s), Extension Lines, Arrowheads
// radius gets 1 dimension line from the dimension text to a point on the curve
Base::Vector3d pointOnCurve,curveCenter;
double radius;
arcPoints pts = dim->getArcPoints();
bool isArc = pts.isArc;
radius = Rez::guiX(pts.radius);
curveCenter = Rez::guiX(pts.center);
pointOnCurve = Rez::guiX(pts.onCurve.first);
QRectF mappedRect = mapRectFromItem(datumLabel, datumLabel->boundingRect());
lblCenter = Base::Vector3d(mappedRect.center().x(), mappedRect.center().y(), 0.0);
// Note Bounding Box size is not the same width or height as text (only used for finding center)
float bbX = datumLabel->boundingRect().width();
float bbY = datumLabel->boundingRect().height();
datumLabel->setTransformOriginPoint(bbX / 2, bbY /2);
datumLabel->setRotation(0.0); //label is always right side up & horizontal
//if inside the arc (len(DimLine < radius)) arrow goes from center to edge away from label
//if outside the arc arrow kinks, then goes to edge nearest label
bool outerPlacement = false;
if ((lblCenter - curveCenter).Length() > radius) { //label is outside circle
outerPlacement = true;
if (prefRadiusAligned() == 0) { //ISO
drawRadiusAligned(dim, vp);
} else if (prefRadiusAligned() == 1) { //ASME
drawRadiusUniform(dim, vp);
} else {
Base::Console().Error("QGIVD::draw - bad radiusAligned pref: %d\n", prefRadiusAligned());
}
Base::Vector3d dirDimLine = (lblCenter - curveCenter).Normalize();
if (fabs(dirDimLine.Length()) < (Precision::Confusion())) {
dirDimLine = Base::Vector3d(-1.0,0.0,0.0);
}
// Base::Vector3d adjustDir = dirDimLine; //adjust line lengths for arrowheads
double dimLineAdjust = Rez::guiX(QGIArrow::getOverlapAdjust(QGIArrow::getPrefArrowStyle(),
QGIArrow::getPrefArrowSize()));
Base::Vector3d dLineStart;
Base::Vector3d dLineEnd; //?? radius draws line from text to curve?? (diam is curve to text!)
Base::Vector3d kinkPoint;
margin = Rez::guiX(5.f); //space around label
double kinkLength = Rez::guiX(5.0); //sb % of horizontal dist(lblCenter,curveCenter)???
if (outerPlacement) {
double offset = getDefaultTextHorizontalOffset(lblCenter.x > curveCenter.x);
dLineStart.y = lblCenter.y;
dLineStart.x = lblCenter.x + offset; //start at right or left of label
kinkLength = (lblCenter.x < curveCenter.x) ? kinkLength : -kinkLength;
kinkPoint.y = dLineStart.y;
kinkPoint.x = dLineStart.x + kinkLength;
pointOnCurve = curveCenter + (kinkPoint - curveCenter).Normalize() * radius;
dLineEnd = pointOnCurve + (kinkPoint - curveCenter).Normalize() * dimLineAdjust;
if ((kinkPoint - curveCenter).Length() < radius) {
dirDimLine = (curveCenter - kinkPoint).Normalize();
} else {
dirDimLine = (kinkPoint - curveCenter).Normalize();
}
} else {
dLineStart = curveCenter - dirDimLine * margin; //just beyond centerpoint
pointOnCurve = curveCenter - dirDimLine * radius;
dLineEnd = pointOnCurve + dirDimLine * dimLineAdjust;
kinkPoint = dLineStart; //no kink
}
//handle partial arc weird cases
if (isArc) {
Base::Vector3d midPt = Rez::guiX(pts.midArc);
Base::Vector3d startPt = Rez::guiX(pts.arcEnds.first);
Base::Vector3d endPt = Rez::guiX(pts.arcEnds.second);
if (outerPlacement &&
!dim->leaderIntersectsArc(Rez::appX(curveCenter),Rez::appX(kinkPoint))) { //keep pathological case within arc
pointOnCurve = midPt;
} else if (!outerPlacement) {
if ((midPt - lblCenter).Length() > (midPt - curveCenter).Length()) { //label is farther than center
dirDimLine = dirDimLine * -1;
}
dLineStart = curveCenter + dirDimLine * margin;
pointOnCurve = curveCenter + dirDimLine * radius;
dLineEnd = pointOnCurve - dirDimLine * dimLineAdjust;
kinkPoint = dLineStart;
if (!dim->leaderIntersectsArc(Rez::appX(dLineStart),Rez::appX(pointOnCurve))) { //keep pathological case within arc
if ((pointOnCurve - endPt).Length() < (pointOnCurve - startPt).Length()) {
if (!pts.arcCW ) {
pointOnCurve = endPt;
} else {
pointOnCurve = startPt;
}
} else {
if (!pts.arcCW ) {
pointOnCurve = startPt;
} else {
pointOnCurve = endPt;
}
}
dLineStart = curveCenter + (pointOnCurve - curveCenter).Normalize() * margin;
dLineEnd = pointOnCurve - dirDimLine * dimLineAdjust;
kinkPoint = dLineStart;
}
}
}
QPainterPath dLinePath; //radius dimension line path
dLinePath.moveTo(dLineStart.x, dLineStart.y);
dLinePath.lineTo(kinkPoint.x, kinkPoint.y);
dLinePath.lineTo(dLineEnd.x, dLineEnd.y);
dimLines->setPath(dLinePath);
//NOTE: in this case aHead1->dirMode is false and Qt rotation is used to point arrowhead
aHead1->setStyle(QGIArrow::getPrefArrowStyle());
aHead1->setSize(QGIArrow::getPrefArrowSize());
aHead1->draw();
Base::Vector3d ar1Pos = pointOnCurve;
Base::Vector3d dirArrowLine = (pointOnCurve - kinkPoint).Normalize();
float arAngle = atan2(dirArrowLine.y, dirArrowLine.x) * 180 / M_PI;
aHead1->setPos(ar1Pos.x, ar1Pos.y);
aHead1->setRotation(arAngle);
aHead1->show();
aHead2->hide();
// if (dim->CentreLines.getValue()) {
// curveCenterMark->setPos(curveCenter.x,curveCenter.y);
// centerMark->show();
// dim->getViewPart()->addVertex(curveCenter,true);
// }
} else if( (strcmp(dimType, "Angle") == 0) ||
(strcmp(dimType, "Angle3Pt") == 0)) {
anglePoints pts = dim->getAnglePoints();
@@ -1408,7 +1298,7 @@ void QGIViewDimension::draw()
dimLines->setPath(path);
//NOTE: arrowheads are dirMode(false)
aHead1->flip(true);
aHead1->setFlipped(true);
aHead1->setStyle(QGIArrow::getPrefArrowStyle());
aHead1->setSize(QGIArrow::getPrefArrowSize());
aHead1->draw();
@@ -1489,6 +1379,420 @@ void QGIViewDimension::draw()
}
}
int QGIViewDimension::classifyPointToArcPosition(double pointDistance, double pointAngle,
double radius, double startAngle, double endAngle, bool clockwise) const
{
if (angleWithinSector(pointAngle, startAngle, endAngle, clockwise)) {
return pointDistance > radius ? OUTER_SECTOR : INNER_SECTOR;
}
if (angleWithinSector(addAngles(pointAngle, M_PI), startAngle, endAngle, clockwise)) {
return OPPOSITE_SECTOR;
}
return COMPLEMENT_SECTOR;
}
double QGIViewDimension::computeLineAndLabelAngles(Base::Vector3d lineTarget, Base::Vector3d labelCenter,
double lineLabelDistance, double &lineAngle, double &labelAngle) const
{
// By default horizontal line and no label rotation
lineAngle = 0.0;
labelAngle = 0.0;
Base::Vector3d rawDirection(labelCenter - lineTarget);
double rawDistance = rawDirection.Length();
if (rawDistance < Precision::Confusion()) { // Almost single point, can't tell
return 0.0;
}
double rawAngle = atan2(rawDirection.y, rawDirection.x);
lineAngle = rawAngle;
// If we are too close to the line origin, no further adjustments
if (lineLabelDistance >= rawDistance) {
return 0.0;
}
// Rotate the line by angle between the label rectangle center and label bottom side center
double devAngle = getStandardLinePlacement(rawAngle)*asin(lineLabelDistance/rawDistance);
lineAngle = addAngles(lineAngle, devAngle);
labelAngle = devAngle > 0.0 ? lineAngle : addAngles(lineAngle, M_PI);
return devAngle;
}
Base::Vector3d QGIViewDimension::computeLineOriginPoint(Base::Vector3d lineTarget, double projectedLabelDistance,
double lineAngle, double labelWidth, double direction) const
{
return lineTarget + (projectedLabelDistance + direction*(0.5*labelWidth + getDefaultReferenceLineOverhang()))
*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0);
}
//draw a Radius dimension using "aligned" convention (ISO)
void QGIViewDimension::drawRadiusAligned(TechDraw::DrawViewDimension *dimension,
ViewProviderDimension *viewProvider) const
{
// Preferred terminology according to ISO 129-1 for Radius:
// Dimensional Value, Leader Line, Reference Line, Terminator
QPainterPath radiusPath;
aHead1->setFlipped(false);
datumLabel->setRotation(0.0);
QRectF mappedRect = mapRectFromItem(datumLabel, datumLabel->boundingRect());
Base::Vector3d labelCenter = Base::Vector3d(mappedRect.center().x(), mappedRect.center().y(), 0.0);
arcPoints curvePoints = dimension->getArcPoints();
Base::Vector3d curveCenter = Rez::guiX(curvePoints.center);
double mappedRadius = Rez::guiX(curvePoints.radius);
double centerDistance = (labelCenter - curveCenter).Length();
double arcStartAngle;
double arcEndAngle;
bool arcClockwise;
if (curvePoints.isArc) {
arcStartAngle = atan2(curvePoints.arcEnds.first.y - curvePoints.center.y,
curvePoints.arcEnds.first.x - curvePoints.center.x);
arcEndAngle = atan2(curvePoints.arcEnds.second.y - curvePoints.center.y,
curvePoints.arcEnds.second.x - curvePoints.center.x);
arcClockwise = !curvePoints.arcCW;
}
else { // A circle arc covers the whole plane
arcStartAngle = -M_PI;
arcEndAngle = +M_PI;
arcClockwise = false;
}
double labelAngle = 0.0;
Base::Vector3d arcPoint;
double lineAngle;
//TODO: does this violate "Aligned" convention?
if (viewProvider->TiltText.getValue()) { // We may rotate the label so no reference line is needed
double devAngle = computeLineAndLabelAngles(curveCenter, labelCenter,
getDefaultTextVerticalOffset(), lineAngle, labelAngle);
// Correct the label center distance projected on the leader line
centerDistance *= cos(devAngle);
Base::Vector3d originPoint;
Base::Vector3d targetPoint;
switch (classifyPointToArcPosition(centerDistance, lineAngle, mappedRadius,
arcStartAngle, arcEndAngle, arcClockwise)) {
case INNER_SECTOR: {
// The label is placed within the arc sector angle, there's always point
// on the arc where the leader line can cross it perpendicularly
arcPoint = curveCenter + mappedRadius*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0);
if (viewProvider->ExtendToCenter.getValue()) { // Start in the very center
originPoint = curveCenter;
}
else { // Start on the label side closer to the center
originPoint = computeLineOriginPoint(curveCenter, centerDistance, lineAngle,
mappedRect.width(), -1.0);
}
targetPoint = arcPoint;
break;
}
case OUTER_SECTOR: {
// Same situation as when on the inner side of sector
arcPoint = curveCenter + mappedRadius*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0);
aHead1->flip();
originPoint = computeLineOriginPoint(curveCenter, centerDistance, lineAngle,
mappedRect.width(), +1.0);
// If leader line shall not be extended to the center, start on the arc projection
targetPoint = viewProvider->ExtendToCenter.getValue() ? curveCenter : arcPoint;
break;
}
case OPPOSITE_SECTOR: {
// If the label is placed within the vertically opposite angle of the arc sector,
// the leader line passing through the arc center can mark a point on the arc
arcPoint = curveCenter - mappedRadius*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0);
aHead1->flip();
originPoint = computeLineOriginPoint(curveCenter, centerDistance, lineAngle,
mappedRect.width(), +1.0);
targetPoint = arcPoint;
break;
}
default: {
// Label outside both arc wedges
arcPoint = Rez::guiX(curvePoints.midArc);
aHead1->flip();
devAngle = computeLineAndLabelAngles(arcPoint, labelCenter,
getDefaultTextVerticalOffset(), lineAngle, labelAngle);
centerDistance = (labelCenter - arcPoint).Length()*cos(devAngle);
originPoint = computeLineOriginPoint(arcPoint, centerDistance, lineAngle,
mappedRect.width(), +1.0);
targetPoint = arcPoint;
break;
}
}
// Draw only the leader line from start point to end point
radiusPath.moveTo(originPoint.x, originPoint.y);
radiusPath.lineTo(targetPoint.x, targetPoint.y);
}
else { // The dimensional value text must stay horizontal
Base::Vector3d leftJoint(mappedRect.left() - getDefaultReferenceLineOverhang(),
labelCenter.y + getDefaultTextVerticalOffset(), 0.0);
Base::Vector3d rightJoint(mappedRect.right() + getDefaultReferenceLineOverhang(),
labelCenter.y + getDefaultTextVerticalOffset(), 0.0);
double leftAngle = atan2(leftJoint.y - curveCenter.y, leftJoint.x - curveCenter.x);
double rightAngle = atan2(rightJoint.y - curveCenter.y, rightJoint.x - curveCenter.x);
int leftPosition = classifyPointToArcPosition((leftJoint - curveCenter).Length(),
leftAngle, mappedRadius, arcStartAngle, arcEndAngle, arcClockwise);
int rightPosition = classifyPointToArcPosition((rightJoint - curveCenter).Length(),
rightAngle, mappedRadius, arcStartAngle, arcEndAngle, arcClockwise);
Base::Vector3d originPoint;
Base::Vector3d jointPoint;
Base::Vector3d targetPoint;
if (leftPosition >= OPPOSITE_SECTOR || rightPosition >= OPPOSITE_SECTOR) {
// At least from one of the reference line sides can run the leader line
// perpendicularly to the arc, i.e. in direction to the center
if (leftPosition >= OPPOSITE_SECTOR && rightPosition >= OPPOSITE_SECTOR) {
// Both are acceptable, so choose the more convenient one
double leftBend = leftPosition == INNER_SECTOR ? M_PI - fabs(leftAngle) : fabs(leftAngle);
double rightBend = rightPosition == INNER_SECTOR ? fabs(rightAngle) : M_PI - fabs(rightAngle);
// If right leader line bends less or does not cross the dimensional value,
// use it by marking left point as outlayer
if (leftBend <= M_PI_2 || rightBend <= M_PI_2) { // At least one line is not crossing the text
if (rightBend < leftBend) {
leftPosition = COMPLEMENT_SECTOR;
}
}
else {
bool leftDown = leftPosition == INNER_SECTOR ? leftAngle > 0.0 : leftAngle < 0.0;
bool rightDown = rightPosition == INNER_SECTOR ? rightAngle > 0.0 : rightAngle < 0.0;
if (leftDown == rightDown) { // Both lines go downwards or upwards
if (rightBend < leftBend) {
leftPosition = COMPLEMENT_SECTOR;
}
}
else if (rightDown) {
leftPosition = COMPLEMENT_SECTOR;
}
}
}
int resultPosition;
if (leftPosition >= OPPOSITE_SECTOR) {
originPoint = rightJoint;
jointPoint = leftJoint;
lineAngle = leftAngle;
resultPosition = leftPosition;
}
else {
originPoint = leftJoint;
jointPoint = rightJoint;
lineAngle = rightAngle;
resultPosition = rightPosition;
}
switch (resultPosition) {
case INNER_SECTOR:
arcPoint = curveCenter + mappedRadius*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0);
targetPoint = arcPoint;
break;
case OUTER_SECTOR:
arcPoint = curveCenter + mappedRadius*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0);
// If desired, extend the target point to the center
targetPoint = viewProvider->ExtendToCenter.getValue() ? curveCenter : arcPoint;
aHead1->flip();
break;
case OPPOSITE_SECTOR:
arcPoint = curveCenter - mappedRadius*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0);
targetPoint = arcPoint;
aHead1->flip();
break;
}
}
else { // Both joint points lay outside the vertical angles
arcPoint = Rez::guiX(curvePoints.midArc);
if (labelCenter.x >= arcPoint.x) { // Place the dimensional value right
originPoint = rightJoint;
jointPoint = leftJoint;
}
else { // Place the dimensional value left
originPoint = leftJoint;
jointPoint = rightJoint;
}
targetPoint = arcPoint;
lineAngle = atan2(targetPoint.y - jointPoint.y, targetPoint.x - jointPoint.x);
}
radiusPath.moveTo(originPoint.x, originPoint.y);
radiusPath.lineTo(jointPoint.x, jointPoint.y);
radiusPath.lineTo(targetPoint.x, targetPoint.y);
}
datumLabel->setTransformOriginPoint(datumLabel->boundingRect().width()*0.5,
datumLabel->boundingRect().height()*0.5);
datumLabel->setRotation(labelAngle*180.0/M_PI);
dimLines->setPath(radiusPath);
aHead1->setPos(arcPoint.x, arcPoint.y);
aHead1->setRotation(0.0);
aHead1->setDirMode(true);
aHead1->setDirection(lineAngle);
if (viewProvider->FlipArrowheads.getValue()) {
aHead1->flip();
}
aHead1->setStyle(QGIArrow::getPrefArrowStyle());
aHead1->setSize(QGIArrow::getPrefArrowSize());
aHead1->draw();
aHead1->show();
aHead2->hide();
}
//Draw a Radius dimension using "uniform" alignment convention (Ansi/Asme)
void QGIViewDimension::drawRadiusUniform(TechDraw::DrawViewDimension* dim,
TechDrawGui::ViewProviderDimension* viewProvider) const
{
// preferred terminology: Dimension Text, Dimension Line(s), Extension Lines, Arrowheads
// radius gets 1 dimension line from the dimension text to a point on the curve
aHead1->setFlipped(false);
Base::Vector3d pointOnCurve,curveCenter;
double radius;
arcPoints pts = dim->getArcPoints();
bool isArc = pts.isArc;
radius = Rez::guiX(pts.radius);
curveCenter = Rez::guiX(pts.center);
pointOnCurve = Rez::guiX(pts.onCurve.first);
QRectF mappedRect = mapRectFromItem(datumLabel, datumLabel->boundingRect());
Base::Vector3d lblCenter = Base::Vector3d(mappedRect.center().x(), mappedRect.center().y(), 0.0);
// Note Bounding Box size is not the same width or height as text (only used for finding center)
float bbX = datumLabel->boundingRect().width();
float bbY = datumLabel->boundingRect().height();
datumLabel->setTransformOriginPoint(bbX / 2, bbY /2);
datumLabel->setRotation(0.0); //label is always right side up & horizontal
//if inside the arc (len(DimLine < radius)) arrow goes from center to edge away from label
//if outside the arc arrow kinks, then goes to edge nearest label
bool outerPlacement = false;
if ((lblCenter - curveCenter).Length() > radius) { //label is outside circle
outerPlacement = true;
}
Base::Vector3d dirDimLine = (lblCenter - curveCenter).Normalize();
if (fabs(dirDimLine.Length()) < (Precision::Confusion())) {
dirDimLine = Base::Vector3d(-1.0,0.0,0.0);
}
// Base::Vector3d adjustDir = dirDimLine; //adjust line lengths for arrowheads
double dimLineAdjust = Rez::guiX(QGIArrow::getOverlapAdjust(QGIArrow::getPrefArrowStyle(),
QGIArrow::getPrefArrowSize()));
Base::Vector3d dLineStart;
Base::Vector3d dLineEnd; //?? radius draws line from text to curve?? (diam is curve to text!)
Base::Vector3d kinkPoint;
double margin = Rez::guiX(5.f); //space around label
double kinkLength = Rez::guiX(5.0); //sb % of horizontal dist(lblCenter,curveCenter)???
if (outerPlacement) {
double offset = getDefaultTextHorizontalOffset(lblCenter.x > curveCenter.x);
dLineStart.y = lblCenter.y;
dLineStart.x = lblCenter.x + offset; //start at right or left of label
kinkLength = (lblCenter.x < curveCenter.x) ? kinkLength : -kinkLength;
kinkPoint.y = dLineStart.y;
kinkPoint.x = dLineStart.x + kinkLength;
pointOnCurve = curveCenter + (kinkPoint - curveCenter).Normalize() * radius;
dLineEnd = pointOnCurve + (kinkPoint - curveCenter).Normalize() * dimLineAdjust;
if ((kinkPoint - curveCenter).Length() < radius) {
dirDimLine = (curveCenter - kinkPoint).Normalize();
} else {
dirDimLine = (kinkPoint - curveCenter).Normalize();
}
} else {
dLineStart = curveCenter - dirDimLine * margin; //just beyond centerpoint
pointOnCurve = curveCenter - dirDimLine * radius;
dLineEnd = pointOnCurve + dirDimLine * dimLineAdjust;
kinkPoint = dLineStart; //no kink
}
//handle partial arc weird cases
if (isArc) {
Base::Vector3d midPt = Rez::guiX(pts.midArc);
Base::Vector3d startPt = Rez::guiX(pts.arcEnds.first);
Base::Vector3d endPt = Rez::guiX(pts.arcEnds.second);
if (outerPlacement &&
!dim->leaderIntersectsArc(Rez::appX(curveCenter),Rez::appX(kinkPoint))) { //keep pathological case within arc
pointOnCurve = midPt;
} else if (!outerPlacement) {
if ((midPt - lblCenter).Length() > (midPt - curveCenter).Length()) { //label is farther than center
dirDimLine = dirDimLine * -1;
}
dLineStart = curveCenter + dirDimLine * margin;
pointOnCurve = curveCenter + dirDimLine * radius;
dLineEnd = pointOnCurve - dirDimLine * dimLineAdjust;
kinkPoint = dLineStart;
if (!dim->leaderIntersectsArc(Rez::appX(dLineStart),Rez::appX(pointOnCurve))) { //keep pathological case within arc
if ((pointOnCurve - endPt).Length() < (pointOnCurve - startPt).Length()) {
if (!pts.arcCW ) {
pointOnCurve = endPt;
} else {
pointOnCurve = startPt;
}
} else {
if (!pts.arcCW ) {
pointOnCurve = startPt;
} else {
pointOnCurve = endPt;
}
}
dLineStart = curveCenter + (pointOnCurve - curveCenter).Normalize() * margin;
dLineEnd = pointOnCurve - dirDimLine * dimLineAdjust;
kinkPoint = dLineStart;
}
}
}
QPainterPath dLinePath; //radius dimension line path
dLinePath.moveTo(dLineStart.x, dLineStart.y);
dLinePath.lineTo(kinkPoint.x, kinkPoint.y);
dLinePath.lineTo(dLineEnd.x, dLineEnd.y);
dimLines->setPath(dLinePath);
Base::Vector3d ar1Pos = pointOnCurve;
Base::Vector3d dirArrowLine = (pointOnCurve - kinkPoint).Normalize();
float arAngle = atan2(dirArrowLine.y, dirArrowLine.x) * 180 / M_PI;
//NOTE: in this case aHead1->dirMode is false and Qt rotation is used to point arrowhead
aHead1->setPos(ar1Pos.x, ar1Pos.y);
aHead1->setDirMode(false);
aHead1->setRotation(arAngle);
if (viewProvider->FlipArrowheads.getValue()) {
aHead1->flip();
}
aHead1->setStyle(QGIArrow::getPrefArrowStyle());
aHead1->setSize(QGIArrow::getPrefArrowSize());
aHead1->draw();
aHead1->show();
aHead2->hide();
// code for showCenterMark as attribute of Dimension instead of View
// if (dim->CentreLines.getValue()) {
// curveCenterMark->setPos(curveCenter.x,curveCenter.y);
// centerMark->show();
// dim->getViewPart()->addVertex(curveCenter,true);
// }
}
QColor QGIViewDimension::getNormalColor()
{
Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
@@ -1613,6 +1917,50 @@ double QGIViewDimension::getDefaultTextVerticalOffset() const
return textMult*Rez::guiX(vp->Fontsize.getValue()) + TextOffsetFudge;
}
double QGIViewDimension::getDefaultReferenceLineOverhang() const
{
return 2.0*TextOffsetFudge;
}
double QGIViewDimension::getStandardLinePlacement(double labelAngle)
{
// According to ISO 129-1 Standard Figure 23, the bordering angle is 2/3 PI, resp. -1/3 PI
// As Qt Y axis points downwards, all signs are flipped
return labelAngle > +M_PI/3.0 || labelAngle < -2.0*M_PI/3.0
? -1.0 : +1.0;
}
bool QGIViewDimension::angleWithinSector(double testAngle, double startAngle, double endAngle, bool clockwise)
{
if (clockwise) {
std::swap(startAngle, endAngle);
}
if (endAngle < startAngle) {
endAngle += M_2PI;
}
if (testAngle < startAngle) {
testAngle += M_2PI;
}
return testAngle <= endAngle;
}
double QGIViewDimension::addAngles(double angle1, double angle2)
{
angle1 += angle2;
if (angle2 >= 0.0) {
if (angle1 > +M_PI) angle1 -= M_2PI;
return angle1;
}
else {
if (angle1 < -M_PI) angle1 += M_2PI;
return angle1;
}
}
//frame, border, caption are never shown in QGIVD, so shouldn't be in bRect
QRectF QGIViewDimension::boundingRect() const
{
@@ -1662,5 +2010,13 @@ void QGIViewDimension::setPens(void)
aHead2->setWidth(m_lineWidth);
}
int QGIViewDimension::prefRadiusAligned(void)
{
int result = 0;
Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
.GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Standards");
result = hGrp->GetInt("RadiusAligned", 0); //default to ISO
return result;
}
#include <Mod/TechDraw/Gui/moc_QGIViewDimension.cpp>
+26
View File
@@ -48,6 +48,7 @@ namespace TechDrawGui
class QGIArrow;
class QGIDimLines;
class QGIViewDimension;
class ViewProviderDimension;
class QGIDatumLabel : public QGraphicsObject
{
@@ -154,7 +155,25 @@ public Q_SLOTS:
void updateDim(bool obtuse = false);
protected:
static const int INNER_SECTOR = 3;
static const int OUTER_SECTOR = 2;
static const int OPPOSITE_SECTOR = 1;
static const int COMPLEMENT_SECTOR = 0;
int classifyPointToArcPosition(double pointDistance, double pointAngle,
double radius, double startAngle, double endAngle, bool clockwise) const;
double computeLineAndLabelAngles(Base::Vector3d lineTarget, Base::Vector3d labelCenter,
double lineLabelDistance, double &lineAngle, double &labelAngle) const;
Base::Vector3d computeLineOriginPoint(Base::Vector3d lineTarget, double projectedLabelDistance,
double lineAngle, double labelWidth, double direction) const;
void draw() override;
void drawRadiusAligned(TechDraw::DrawViewDimension *dimension,
ViewProviderDimension *viewProvider) const;
void drawRadiusUniform(TechDraw::DrawViewDimension *dimension,
ViewProviderDimension *viewProvider) const;
virtual QVariant itemChange( GraphicsItemChange change,
const QVariant &value ) override;
virtual void setSvgPens(void);
@@ -162,6 +181,8 @@ protected:
Base::Vector3d findIsoDir(Base::Vector3d ortho);
Base::Vector3d findIsoExt(Base::Vector3d isoDir);
QString getPrecision(void);
int prefRadiusAligned(void);
protected:
bool hasHover;
@@ -178,6 +199,11 @@ private:
double getDefaultTextHorizontalOffset(bool toLeft) const;
double getDefaultTextVerticalOffset() const;
double getDefaultReferenceLineOverhang() const;
static double getStandardLinePlacement(double labelAngle);
static bool angleWithinSector(double testAngle, double startAngle, double endAngle, bool clockwise);
static double addAngles(double angle1, double angle2);
};
} // namespace MDIViewPageGui
@@ -79,8 +79,9 @@ ViewProviderDimension::ViewProviderDimension()
fcColor.setPackedValue(hGrp->GetUnsigned("Color", 0x00000000));
ADD_PROPERTY_TYPE(Color,(fcColor),group,App::Prop_None,"The color of the Dimension");
ADD_PROPERTY_TYPE(FlipArrowheads ,(false),group,App::Prop_None,"Reverse the normal direction of arrowheads on dimline");
ADD_PROPERTY_TYPE(FlipArrowheads, (false), group, App::Prop_None,"Reverse the normal direction of arrowheads on dimline");
ADD_PROPERTY_TYPE(TiltText, (true), group, App::Prop_None,"Rotate the text label so it is parallel with dimline");
ADD_PROPERTY_TYPE(ExtendToCenter, (true), group, App::Prop_None,"Prolong the leader line right upto the center point");
}
ViewProviderDimension::~ViewProviderDimension()
@@ -131,7 +132,9 @@ void ViewProviderDimension::onChanged(const App::Property* p)
if ((p == &Font) ||
(p == &Fontsize) ||
(p == &LineWidth) ||
(p == &FlipArrowheads)) {
(p == &FlipArrowheads) ||
(p == &TiltText) ||
(p == &ExtendToCenter)) {
QGIView* qgiv = getQView();
if (qgiv) {
qgiv->updateView(true);
+2 -1
View File
@@ -49,7 +49,8 @@ public:
App::PropertyFloat LineWidth;
App::PropertyColor Color;
App::PropertyBool FlipArrowheads;
App::PropertyBool TiltText;
App::PropertyBool ExtendToCenter;
virtual void attach(App::DocumentObject *);
virtual void setDisplayMode(const char* ModeName);