diff --git a/src/Base/CMakeLists.txt b/src/Base/CMakeLists.txt index 3cab43354..4b5a06170 100644 --- a/src/Base/CMakeLists.txt +++ b/src/Base/CMakeLists.txt @@ -152,6 +152,7 @@ SET(FreeCADBase_XML_SRCS SOURCE_GROUP("XML" FILES ${FreeCADBase_XML_SRCS}) set(FreeCADBase_MOC_HDRS + Debugger.h FutureWatcherProgress.h ) fc_wrap_cpp(FreeCADBase_MOC_SRCS ${FreeCADBase_MOC_HDRS}) @@ -182,6 +183,7 @@ SET(FreeCADBase_CPP_SRCS BoundBoxPyImp.cpp Builder3D.cpp Console.cpp + Debugger.cpp Exception.cpp Factory.cpp FileInfo.cpp @@ -234,6 +236,7 @@ SET(FreeCADBase_HPP_SRCS BoundBox.h Builder3D.h Console.h + Debugger.h Exception.h Factory.h FileInfo.h diff --git a/src/Base/Debugger.cpp b/src/Base/Debugger.cpp new file mode 100644 index 000000000..2b08f0aa4 --- /dev/null +++ b/src/Base/Debugger.cpp @@ -0,0 +1,80 @@ +/*************************************************************************** + * Copyright (c) 2012 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 51 Franklin Street, * + * Fifth Floor, Boston, MA 02110-1301, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +# include +#endif + +#include "Debugger.h" +#include "Console.h" + +using namespace Base; + +Debugger::Debugger(QObject* parent) + : QObject(parent), isAttached(false) +{ +} + +Debugger::~Debugger() +{ +} + +void Debugger::attach() +{ + QCoreApplication::instance()->installEventFilter(this); + isAttached = true; +} + +void Debugger::detach() +{ + QCoreApplication::instance()->removeEventFilter(this); + isAttached = false; +} + +bool Debugger::eventFilter(QObject*, QEvent* event) +{ + if (event->type() == QEvent::KeyPress) { + if (loop.isRunning()) { + loop.quit(); + return true; + } + } + + return false; +} + +int Debugger::exec() +{ + if (isAttached) + Base::Console().Message("TO CONTINUE PRESS ANY KEY...\n"); + return loop.exec(); +} + +void Debugger::quit() +{ + loop.quit(); +} + +#include "moc_Debugger.cpp" diff --git a/src/Base/Debugger.h b/src/Base/Debugger.h new file mode 100644 index 000000000..114b7e38b --- /dev/null +++ b/src/Base/Debugger.h @@ -0,0 +1,76 @@ +/*************************************************************************** + * Copyright (c) 2012 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 51 Franklin Street, * + * Fifth Floor, Boston, MA 02110-1301, USA * + * * + ***************************************************************************/ + + +#ifndef BASE_DEBUGGER_H +#define BASE_DEBUGGER_H + +#include +#include + +namespace Base { +/** + This is a utility class to break the application at a point to inspect e.g. the result of + an algorithm. + You usually use it like this + \code + ... + Base::Debugger dbg; + dbg.attach(); + dbg.exec(); + ... + \endcode + Or you can connect it with a button and let the user click it in order to continue. + \code + QPushButton* btn = new QPushButton(); + btn->setText("Continue"); + btn->show(); + Base::Debugger dbg; + connect(btn, SIGNAL(clicked()), &dbg, SLOT(quit())); + dbg.exec(); + \endcode + \author Werner Mayer + */ +class BaseExport Debugger : public QObject +{ + Q_OBJECT + +public: + Debugger(QObject* parent=0); + ~Debugger(); + + void attach(); + void detach(); + bool eventFilter(QObject*, QEvent*); + int exec(); + +public Q_SLOTS: + void quit(); + +private: + bool isAttached; + QEventLoop loop; +}; + +} + +#endif // BASE_DEBUGGER_H diff --git a/src/Base/PreCompiled.h b/src/Base/PreCompiled.h index f3b7dba3b..8d9663454 100644 --- a/src/Base/PreCompiled.h +++ b/src/Base/PreCompiled.h @@ -105,6 +105,8 @@ // QtCore #include #include +#include +#include #include #include #include diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index b7b8a8ea3..53dec5681 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -1457,9 +1457,10 @@ namespace Gui { */ class GUIApplication : public GUIApplicationNativeEventAware { + int systemExit; public: - GUIApplication(int & argc, char ** argv) - : GUIApplicationNativeEventAware(argc, argv) + GUIApplication(int & argc, char ** argv, int exitcode) + : GUIApplicationNativeEventAware(argc, argv), systemExit(exitcode) { } @@ -1480,6 +1481,10 @@ public: else return QApplication::notify(receiver, event); } + catch (const Base::SystemExitException&) { + qApp->exit(systemExit); + return true; + } catch (const Base::Exception& e) { Base::Console().Error("Unhandled Base::Exception caught in GUIApplication::notify.\n" "The error message is: %s\n", e.what()); @@ -1543,7 +1548,8 @@ void Application::runApplication(void) Base::Console().Log("Init: Creating Gui::Application and QApplication\n"); // if application not yet created by the splasher int argc = App::Application::GetARGC(); - GUIApplication mainApp(argc, App::Application::GetARGV()); + int systemExit = 1000; + GUIApplication mainApp(argc, App::Application::GetARGV(), systemExit); // set application icon and window title const std::map& cfg = App::Application::Config(); std::map::const_iterator it; @@ -1716,9 +1722,15 @@ void Application::runApplication(void) Base::Console().Log("Init: Entering event loop\n"); try { - mainApp.exec(); + int ret = mainApp.exec(); + if (ret == systemExit) + throw Base::SystemExitException(); } - catch(...) { + catch (const Base::SystemExitException&) { + Base::Console().Message("System exit\n"); + throw; + } + catch (...) { // catching nasty stuff coming out of the event loop App::Application::destructObserver(); Base::Console().Error("Event loop left through unhandled exception\n"); diff --git a/src/Gui/Command.cpp b/src/Gui/Command.cpp index 40fdb9557..f66adf95e 100644 --- a/src/Gui/Command.cpp +++ b/src/Gui/Command.cpp @@ -281,6 +281,9 @@ void Command::invoke(int i) if (isActive()) activated( i ); } + catch (const Base::SystemExitException&) { + throw; + } catch (Base::PyException &e) { e.ReportException(); Base::Console().Error("Stack Trace: %s\n",e.getStackTrace().c_str()); diff --git a/src/Gui/DlgSettingsViewColor.cpp b/src/Gui/DlgSettingsViewColor.cpp index 1449489bd..2bba4faac 100644 --- a/src/Gui/DlgSettingsViewColor.cpp +++ b/src/Gui/DlgSettingsViewColor.cpp @@ -66,10 +66,14 @@ void DlgSettingsViewColor::saveSettings() checkBoxSelection->onSave(); HighlightColor->onSave(); SelectionColor->onSave(); + CursorTextColor->onSave(); EditedEdgeColor->onSave(); EditedVertexColor->onSave(); ConstructionColor->onSave(); FullyConstrainedColor->onSave(); + DefaultShapeColor->onSave(); + DefaultShapeLineColor->onSave(); + DefaultShapeLineWidth->onSave(); } void DlgSettingsViewColor::loadSettings() @@ -85,10 +89,14 @@ void DlgSettingsViewColor::loadSettings() checkBoxSelection->onRestore(); HighlightColor->onRestore(); SelectionColor->onRestore(); + CursorTextColor->onRestore(); EditedEdgeColor->onRestore(); EditedVertexColor->onRestore(); ConstructionColor->onRestore(); FullyConstrainedColor->onRestore(); + DefaultShapeColor->onRestore(); + DefaultShapeLineColor->onRestore(); + DefaultShapeLineWidth->onRestore(); } /** diff --git a/src/Gui/DlgSettingsViewColor.ui b/src/Gui/DlgSettingsViewColor.ui index e17848a4e..bcd5cd44f 100644 --- a/src/Gui/DlgSettingsViewColor.ui +++ b/src/Gui/DlgSettingsViewColor.ui @@ -7,7 +7,7 @@ 0 0 601 - 407 + 445 @@ -361,7 +361,20 @@ Default colors - + + + + Qt::Horizontal + + + + 40 + 20 + + + + + 0 @@ -369,7 +382,7 @@ 6 - + @@ -382,28 +395,28 @@ - + Edited vertex color - + Construction geometry - + Fully constrained geometry - + The color of construction geometry in edit mode @@ -423,7 +436,7 @@ - + The color of fully constrained geometry in edit mode @@ -443,7 +456,7 @@ - + The color of vertices being edited @@ -463,7 +476,7 @@ - + The color of edges being edited @@ -483,20 +496,124 @@ + + + + Cursor text color + + + + + + + + 0 + 0 + 255 + + + + CursorTextColor + + + View + + + - - - - Qt::Horizontal - - - - 40 - 20 - - - + + + + + + + 240 + 0 + + + + Default shape color + + + + + + + The default color for new shapes + + + + 204 + 204 + 204 + + + + DefaultShapeColor + + + View + + + + + + + + + + + + 182 + 0 + + + + Default line width and color + + + + + + + The default line color for new shapes + + + + 25 + 25 + 25 + + + + DefaultShapeLineColor + + + View + + + + + + + The default line thickness for new shapes + + + px + + + 2 + + + DefaultShapeLineWidth + + + View + + + + @@ -509,6 +626,11 @@ QPushButton
Gui/Widgets.h
+ + Gui::PrefSpinBox + QSpinBox +
Gui/PrefWidgets.h
+
Gui::PrefColorButton Gui::ColorButton @@ -530,6 +652,11 @@ checkBoxSelection HighlightColor SelectionColor + CursorTextColor + EditedEdgeColor + EditedVertexColor + ConstructionColor + FullyConstrainedColor radioButtonSimple radioButtonGradient checkMidColor diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index 972d9d148..512f39186 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -187,6 +187,9 @@ bool Document::setEdit(Gui::ViewProvider* p, int ModNum) View3DInventor *activeView = dynamic_cast(getActiveView()); if (activeView && activeView->getViewer()->setEditingViewProvider(p,ModNum)) { d->_pcInEdit = p; + Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); + if (dlg) + dlg->setDocumentName(this->getDocument()->getName()); if (d->_pcInEdit->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) signalInEdit(*(static_cast(d->_pcInEdit))); } diff --git a/src/Gui/Macro.cpp b/src/Gui/Macro.cpp index 1ac796478..20a7f49c4 100644 --- a/src/Gui/Macro.cpp +++ b/src/Gui/Macro.cpp @@ -233,7 +233,7 @@ void MacroManager::run(MacroType eType,const char *sName) Base::Interpreter().runFile(sName, this->localEnv); } catch (const Base::SystemExitException&) { - qApp->quit(); + throw; } catch (const Base::PyException& e) { Base::Console().Error("%s%s: %s\n", diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index a13a16c2c..cccdf146b 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -1157,8 +1157,7 @@ void MainWindow::delayedStartup() App::Application::processCmdLineFiles(); } catch (const Base::SystemExitException&) { - QApplication::quit(); - return; + throw; } const std::map& cfg = App::Application::Config(); diff --git a/src/Gui/PythonConsole.cpp b/src/Gui/PythonConsole.cpp index 780789b71..eaa7f53cb 100644 --- a/src/Gui/PythonConsole.cpp +++ b/src/Gui/PythonConsole.cpp @@ -709,7 +709,7 @@ void PythonConsole::runSource(const QString& line) } if (ret == QMessageBox::Yes) { PyErr_Clear(); - qApp->quit(); + throw; } else { PyErr_Clear(); diff --git a/src/Gui/TaskView/TaskDialog.h b/src/Gui/TaskView/TaskDialog.h index f6a0e402f..ec92a9dd2 100644 --- a/src/Gui/TaskView/TaskDialog.h +++ b/src/Gui/TaskView/TaskDialog.h @@ -69,6 +69,8 @@ public: const std::string& getDocumentName() const { return documentName; } + void setDocumentName(const std::string& doc) + { documentName = doc; } virtual bool isAllowedAlterDocument(void) const { return false; } virtual bool isAllowedAlterView(void) const @@ -94,6 +96,8 @@ protected: /// List of TaskBoxes of that dialog std::vector Content; ButtonPosition pos; + +private: std::string documentName; }; diff --git a/src/Gui/ViewProviderGeometryObject.cpp b/src/Gui/ViewProviderGeometryObject.cpp index 4e17a85e1..4b5b33c3a 100644 --- a/src/Gui/ViewProviderGeometryObject.cpp +++ b/src/Gui/ViewProviderGeometryObject.cpp @@ -63,14 +63,17 @@ using namespace Gui; - PROPERTY_SOURCE(Gui::ViewProviderGeometryObject, Gui::ViewProviderDocumentObject) const App::PropertyIntegerConstraint::Constraints intPercent = {0,100,1}; ViewProviderGeometryObject::ViewProviderGeometryObject() : pcBoundSwitch(0) { - ADD_PROPERTY(ShapeColor,(0.8f,0.8f,0.8f)); + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); + unsigned long shcol = hGrp->GetUnsigned("DefaultShapeColor",3435973887UL); // light gray (204,204,204) + float r,g,b; + r = ((shcol >> 24) & 0xff) / 255.0; g = ((shcol >> 16) & 0xff) / 255.0; b = ((shcol >> 8) & 0xff) / 255.0; + ADD_PROPERTY(ShapeColor,(r, g, b)); ADD_PROPERTY(Transparency,(0)); Transparency.setConstraints(&intPercent); App::Material mat(App::Material::DEFAULT); @@ -86,7 +89,8 @@ ViewProviderGeometryObject::ViewProviderGeometryObject() : pcBoundSwitch(0) pcShapeMaterial = new SoMaterial; pcShapeMaterial->ref(); - ShapeMaterial.touch(); + //ShapeMaterial.touch(); materials are rarely used, so better to initialize with default shape color + ShapeColor.touch(); pcBoundingBox = new Gui::SoFCBoundingBox; pcBoundingBox->ref(); diff --git a/src/Gui/ViewProviderPythonFeature.cpp b/src/Gui/ViewProviderPythonFeature.cpp index ed84b97dd..144d15815 100644 --- a/src/Gui/ViewProviderPythonFeature.cpp +++ b/src/Gui/ViewProviderPythonFeature.cpp @@ -498,6 +498,8 @@ const char* ViewProviderPythonFeatureImp::getDefaultDisplayMode() const Py::Callable method(vp.getAttr(std::string("getDefaultDisplayMode"))); Py::Tuple args(0); Py::String str(method.apply(args)); + if (str.isUnicode()) + str = str.encode("ascii"); // json converts strings into unicode mode = str.as_std_string(); return mode.c_str(); } diff --git a/src/Main/MainGui.cpp b/src/Main/MainGui.cpp index 5552bd6b4..288bc3df2 100644 --- a/src/Main/MainGui.cpp +++ b/src/Main/MainGui.cpp @@ -300,6 +300,9 @@ int main( int argc, char ** argv ) else App::Application::runApplication(); } + catch (const Base::SystemExitException&) { + exit(0); + } catch (const Base::Exception& e) { Base::Console().Error("%s\n", e.what()); } diff --git a/src/Mod/Arch/ArchCommands.py b/src/Mod/Arch/ArchCommands.py index 8ee62c546..44dd537c2 100644 --- a/src/Mod/Arch/ArchCommands.py +++ b/src/Mod/Arch/ArchCommands.py @@ -43,6 +43,22 @@ def getStringList(objects): result += "]" return result +def getDefaultColor(objectType): + '''getDefaultColor(string): returns a color value for the given object + type (Wall, Structure, Window)''' + p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") + if objectType == "Wall": + c = p.GetUnsigned("WallColor") + elif objectType == "Structure": + c = p.GetUnsigned("StructureColor") + else: + c = p.GetUnsigned("WindowsColor") + r = float((c>>24)&0xFF)/255.0 + g = float((c>>16)&0xFF)/255.0 + b = float((c>>8)&0xFF)/255.0 + result = (r,g,b,1.0) + return result + def addComponents(objectsList,host): '''addComponents(objectsList,hostObject): adds the given object or the objects from the given list as components to the given host Object. Use this for @@ -278,7 +294,7 @@ def getCutVolume(cutplane,shapes): v = placement.Rotation.multVec(FreeCAD.Vector(0,1,0)) if not bb.isCutPlane(placement.Base,ax): print "No objects are cut by the plane" - return None,None + return None,None,None else: corners = [FreeCAD.Vector(bb.XMin,bb.YMin,bb.ZMin), FreeCAD.Vector(bb.XMin,bb.YMax,bb.ZMin), @@ -305,7 +321,44 @@ def getCutVolume(cutplane,shapes): cutface.Placement = placement cutnormal = DraftVecUtils.scaleTo(ax,wm) cutvolume = cutface.extrude(cutnormal) - return cutface,cutvolume + cutnormal = DraftVecUtils.neg(cutnormal) + invcutvolume = cutface.extrude(cutnormal) + return cutface,cutvolume,invcutvolume + +def getShapeFromMesh(mesh): + import Part, MeshPart + if mesh.isSolid() and (mesh.countComponents() == 1): + # use the best method + faces = [] + for f in mesh.Facets: + p=f.Points+[f.Points[0]] + pts = [] + for pp in p: + pts.append(FreeCAD.Vector(pp[0],pp[1],pp[2])) + faces.append(Part.Face(Part.makePolygon(pts))) + shell = Part.makeShell(faces) + solid = Part.Solid(shell) + solid = solid.removeSplitter() + return solid + + faces = [] + segments = mesh.getPlanarSegments(0.001) # use rather strict tolerance here + for i in segments: + if len(i) > 0: + wires = MeshPart.wireFromSegment(mesh, i) + if wires: + faces.append(makeFace(wires)) + try: + se = Part.makeShell(faces) + except: + return None + else: + try: + solid = Part.Solid(se) + except: + return se + else: + return solid def meshToShape(obj,mark=True): @@ -313,36 +366,18 @@ def meshToShape(obj,mark=True): mark is True (default), non-solid objects will be marked in red''' name = obj.Name - import Part, MeshPart, DraftGeomUtils if "Mesh" in obj.PropertiesList: faces = [] mesh = obj.Mesh plac = obj.Placement - segments = mesh.getPlanarSegments(0.001) # use rather strict tolerance here - print len(segments)," segments ",segments - for i in segments: - print "treating",segments.index(i),i - if len(i) > 0: - wires = MeshPart.wireFromSegment(mesh, i) - print "wire done" - print wires - if wires: - faces.append(makeFace(wires)) - print "done facing" - print "faces",faces - - try: - se = Part.makeShell(faces) - solid = Part.Solid(se) - except: - raise - else: - if solid.isClosed(): + solid = getShapeFromMesh(mesh) + if solid: + if solid.isClosed() and solid.isValid(): FreeCAD.ActiveDocument.removeObject(name) newobj = FreeCAD.ActiveDocument.addObject("Part::Feature",name) newobj.Shape = solid newobj.Placement = plac - if not solid.isClosed(): + if (not solid.isClosed()) or (not solid.isValid()): if mark: newobj.ViewObject.ShapeColor = (1.0,0.0,0.0,1.0) return newobj @@ -428,8 +463,8 @@ def download(url): else: return filepath -def check(objectslist,includehidden=True): - """check(objectslist,includehidden=True): checks if the given objects contain only solids""" +def check(objectslist,includehidden=False): + """check(objectslist,includehidden=False): checks if the given objects contain only solids""" objs = Draft.getGroupContents(objectslist) if not includehidden: objs = Draft.removeHidden(objs) @@ -439,11 +474,11 @@ def check(objectslist,includehidden=True): bad.append([o,"is not a Part-based object"]) else: s = o.Shape - if not s.isClosed(): + if (not s.isClosed()) and (not (Draft.getType(o) == "Axis")): bad.append([o,"is not closed"]) elif not s.isValid(): bad.append([o,"is not valid"]) - elif not s.Solids: + elif (not s.Solids) and (not (Draft.getType(o) == "Axis")): bad.append([o,"doesn't contain any solid"]) else: f = 0 diff --git a/src/Mod/Arch/ArchSectionPlane.py b/src/Mod/Arch/ArchSectionPlane.py index 97fe2023d..8dbb779ab 100644 --- a/src/Mod/Arch/ArchSectionPlane.py +++ b/src/Mod/Arch/ArchSectionPlane.py @@ -184,12 +184,14 @@ class _ArchDrawingView: def __init__(self, obj): obj.addProperty("App::PropertyLink","Source","Base","The linked object") obj.addProperty("App::PropertyEnumeration","RenderingMode","Drawing View","The rendering mode to use") + obj.addProperty("App::PropertyBool","ShowCut","Drawing View","If cut geometry is shown or not") obj.addProperty("App::PropertyFloat","LineWidth","Drawing View","The line width of the rendered objects") obj.RenderingMode = ["Solid","Wireframe"] obj.RenderingMode = "Wireframe" obj.LineWidth = 0.35 + obj.ShowCut = False obj.Proxy = self - self.Type = "DrawingView" + self.Type = "ArchSectionView" def execute(self, obj): if obj.Source: @@ -199,6 +201,40 @@ class _ArchDrawingView: if prop in ["Source","RenderingMode"]: obj.ViewResult = self.updateSVG(obj) + def __getstate__(self): + return None + + def __setstate__(self,state): + return None + + def getDisplayModes(self,vobj): + modes=["Default"] + return modes + + def setDisplayMode(self,mode): + return mode + + def getFlatShape(self): + "returns a flat shape representation of the view" + if hasattr(self,"baseshape"): + import Drawing + [V0,V1,H0,H1] = Drawing.project(self.baseshape,self.direction) + return V0.Edges+V1.Edges + else: + print "No shape has been computed yet" + return None + + def getDXF(self): + "returns a flat shape representation of the view" + if hasattr(self,"baseshape"): + import Drawing + [V0,V1,H0,H1] = Drawing.project(self.baseshape,self.direction) + DxfOutput = Drawing.projectToDXF(self.baseshape,self.direction) + return DxfOutput + else: + print "No shape has been computed yet" + return None + def updateSVG(self, obj,join=False): "encapsulates a svg fragment into a transformation node" import Part, DraftGeomUtils @@ -209,6 +245,9 @@ class _ArchDrawingView: objs = Draft.removeHidden(objs) svg = '' + st = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("CutLineThickness") + if not st: st = 2 + # generating SVG linewidth = obj.LineWidth/obj.Scale if obj.RenderingMode == "Solid": @@ -217,42 +256,74 @@ class _ArchDrawingView: render = ArchVRM.Renderer() render.setWorkingPlane(obj.Source.Placement) render.addObjects(Draft.getGroupContents(objs,walls=True)) - render.cut(obj.Source.Shape) + render.cut(obj.Source.Shape,obj.ShowCut) svg += render.getViewSVG(linewidth=linewidth) - svg += render.getSectionSVG(linewidth=linewidth*2) + svg += render.getSectionSVG(linewidth=linewidth*st) + if obj.ShowCut: + svg += render.getHiddenSVG(linewidth=linewidth) # print render.info() else: # render using the Drawing module import Drawing, Part shapes = [] + hshapes = [] + sshapes = [] p = FreeCAD.Placement(obj.Source.Placement) - direction = p.Rotation.multVec(FreeCAD.Vector(0,0,1)) + self.direction = p.Rotation.multVec(FreeCAD.Vector(0,0,1)) for o in objs: if o.isDerivedFrom("Part::Feature"): - shapes.extend(o.Shape.Solids) - cutface,cutvolume = ArchCommands.getCutVolume(obj.Source.Shape.copy(),shapes) + if o.Shape.isValid(): + shapes.extend(o.Shape.Solids) + else: + FreeCAD.Console.PrintWarning("Skipping invalid object: "+o.Name) + cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(obj.Source.Shape.copy(),shapes) if cutvolume: nsh = [] for sh in shapes: for sol in sh.Solids: c = sol.cut(cutvolume) - nsh.append(c) + s = sol.section(cutface) + nsh.extend(c.Solids) + sshapes.append(s) + if obj.ShowCut: + c = sol.cut(invcutvolume) + hshapes.append(c) shapes = nsh - base = Part.makeCompound(shapes) - #if shapes: - # base = shapes.pop().copy() - #for sh in shapes: - # try: - # base = base.fuse(sh) - # except: - # print "unable to fuse, passing..." - svgf = Drawing.projectToSVG(base,direction) + if shapes: + self.shapes = shapes + self.baseshape = Part.makeCompound(shapes) + svgf = Drawing.projectToSVG(self.baseshape,self.direction) if svgf: svgf = svgf.replace('stroke-width="0.35"','stroke-width="' + str(linewidth) + 'px"') svgf = svgf.replace('stroke-width="1"','stroke-width="' + str(linewidth) + 'px"') svgf = svgf.replace('stroke-width:0.01','stroke-width:' + str(linewidth) + 'px') - svg += svgf + svg += svgf + if hshapes: + hshapes = Part.makeCompound(hshapes) + svgh = Drawing.projectToSVG(hshapes,self.direction) + if svgh: + svgh = svgh.replace('stroke-width="0.35"','stroke-width="' + str(linewidth) + 'px"') + svgh = svgh.replace('stroke-width="1"','stroke-width="' + str(linewidth) + 'px"') + svgh = svgh.replace('stroke-width:0.01','stroke-width:' + str(linewidth) + 'px') + svgh = svgh.replace('fill="none"','fill="none"\nstroke-dasharray="0.09,0.05"') + svg += svgh + if sshapes: + edges = [] + for s in sshapes: + edges.extend(s.Edges) + wires = DraftGeomUtils.findWires(edges) + faces = [] + for w in wires: + if (w.ShapeType == "Wire") and w.isClosed(): + faces.append(Part.Face(w)) + sshapes = Part.makeCompound(faces) + svgs = Drawing.projectToSVG(sshapes,self.direction) + if svgs: + svgs = svgs.replace('stroke-width="0.35"','stroke-width="' + str(linewidth*st) + 'px"') + svgs = svgs.replace('stroke-width="1"','stroke-width="' + str(linewidth*st) + 'px"') + svgs = svgs.replace('stroke-width:0.01','stroke-width:' + str(linewidth*st) + 'px') + svg += svgs result = '' result += '>24)&0xFF)/255.0 - g = float((c>>16)&0xFF)/255.0 - b = float((c>>8)&0xFF)/255.0 - obj.ViewObject.ShapeColor = (r,g,b,1.0) + obj.ViewObject.ShapeColor = ArchCommands.getDefaultColor("Structure") return obj def makeStructuralSystem(objects,axes): @@ -171,7 +166,13 @@ class _Structure(ArchComponent.Component): elif (len(base.Wires) == 1): if base.Wires[0].isClosed(): base = Part.Face(base.Wires[0]) - base = base.extrude(normal) + base = base.extrude(normal) + elif obj.Base.isDerivedFrom("Mesh::Feature"): + if obj.Base.Mesh.isSolid(): + if obj.Base.Mesh.countComponents() == 1: + sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh) + if sh.isClosed() and sh.isValid() and sh.Solids: + base = sh else: if obj.Normal == Vector(0,0,0): normal = Vector(0,0,1) @@ -221,7 +222,12 @@ class _Structure(ArchComponent.Component): # finalizing else: if base: - if not base.isNull(): + if base.isValid() and (not base.isNull()) and base.Solids: + if base.Volume < 0: + base.reverse() + if base.Volume < 0: + FreeCAD.Console.PrintError(str(translate("Arch","Couldn't compute the wall shape"))) + return base = base.removeSplitter() obj.Shape = base if not DraftGeomUtils.isNull(pl): diff --git a/src/Mod/Arch/ArchVRM.py b/src/Mod/Arch/ArchVRM.py index b54b0446f..0ecad3cc4 100644 --- a/src/Mod/Arch/ArchVRM.py +++ b/src/Mod/Arch/ArchVRM.py @@ -25,12 +25,13 @@ import FreeCAD,math,Part,ArchCommands,DraftVecUtils,DraftGeomUtils -DEBUG = True # if we want debug messages MAXLOOP = 10 # the max number of loop before abort # WARNING: in this module, faces are lists whose first item is the actual OCC face, the # other items being additional information such as color, etc. +DEBUG = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetBool("ShowVRMDebug") + class Renderer: "A renderer object" def __init__(self,wp=None): @@ -73,6 +74,7 @@ class Renderer: self.iscut = False self.joined = False self.sections = [] + self.hiddenEdges = [] def setWorkingPlane(self,wp): "sets a Draft WorkingPlane or Placement for this renderer" @@ -151,6 +153,8 @@ class Renderer: self.faces = [self.projectFace(f) for f in self.faces] if self.sections: self.sections = [self.projectFace(f) for f in self.sections] + if self.hiddenEdges: + self.hiddenEdges = [self.projectEdge(e) for e in self.hiddenEdges] self.oriented = True #print "VRM: end reorient" @@ -200,6 +204,14 @@ class Renderer: #print "VRM: projectFace end: ",len(sh.Vertexes)," verts" return [sh]+face[1:] + def projectEdge(self,edge): + "projects a single edge on the WP" + if len(edge.Vertexes) > 1: + v1 = self.wp.getLocalCoords(edge.Vertexes[0].Point) + v2 = self.wp.getLocalCoords(edge.Vertexes[-1].Point) + return Part.Line(v1,v2).toShape() + return edge + def flattenFace(self,face): "Returns a face where all vertices have Z = 0" wires = [] @@ -219,7 +231,7 @@ class Renderer: else: return [sh]+face[1:] - def cut(self,cutplane): + def cut(self,cutplane,hidden=False): "Cuts through the shapes with a given cut plane and builds section faces" if DEBUG: print "\n\n======> Starting cut\n\n" if self.iscut: @@ -231,7 +243,7 @@ class Renderer: shps = [] for sh in self.shapes: shps.append(sh[0]) - cutface,cutvolume = ArchCommands.getCutVolume(cutplane,shps) + cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(cutplane,shps) if cutface and cutvolume: shapes = [] faces = [] @@ -246,6 +258,9 @@ class Renderer: if DraftGeomUtils.isCoplanar([f,cutface]): print "COPLANAR" sections.append([f,fill]) + if hidden: + c = sol.cut(invcutvolume) + self.hiddenEdges.extend(c.Edges) self.shapes = shapes self.faces = faces self.sections = sections @@ -555,7 +570,8 @@ class Renderer: v = e.Vertexes[-1].Point svg += 'A '+ tostr(r) + ' '+ tostr(r) +' 0 0 1 '+ tostr(v.x) +' ' svg += tostr(v.y) + ' ' - svg += 'Z ' + if len(edges) > 1: + svg += 'Z ' return svg def getViewSVG(self,linewidth=0.01): @@ -608,4 +624,25 @@ class Renderer: svg += 'fill-rule: evenodd' svg += '"/>\n' return svg + + def getHiddenSVG(self,linewidth=0.02): + "Returns a SVG fragment from cut geometry" + if DEBUG: print "Printing ", len(self.sections), " hidden faces" + if not self.oriented: + self.reorient() + svg = '' + for e in self.hiddenEdges: + svg +='>24)&0xFF)/255.0 - g = float((c>>16)&0xFF)/255.0 - b = float((c>>8)&0xFF)/255.0 - obj.ViewObject.ShapeColor = (r,g,b,1.0) + if obj.Base: + obj.Base.ViewObject.hide() + obj.ViewObject.ShapeColor = ArchCommands.getDefaultColor("Wall") return obj def joinWalls(walls): @@ -357,7 +356,7 @@ class _Wall(ArchComponent.Component): # computing shape base = None if obj.Base.isDerivedFrom("Part::Feature"): - if not obj.Base.Shape.isNull(): + if obj.Base.Shape.isValid() and (not obj.Base.Shape.isNull()): base = obj.Base.Shape.copy() if base.Solids: pass @@ -380,9 +379,21 @@ class _Wall(ArchComponent.Component): if sh: base = sh else: + base = None FreeCAD.Console.PrintError(str(translate("Arch","Error: Invalid base object"))) + + elif obj.Base.isDerivedFrom("Mesh::Feature"): + if obj.Base.Mesh.isSolid(): + if obj.Base.Mesh.countComponents() == 1: + sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh) + if sh.isClosed() and sh.isValid() and sh.Solids and (not sh.isNull()): + base = sh + else: + FreeCAD.Console.PrintWarning("This mesh is an invalid solid") + obj.Base.ViewObject.show() if base: + for app in obj.Additions: if Draft.getType(app) == "Window": # window @@ -418,7 +429,12 @@ class _Wall(ArchComponent.Component): base = base.cut(hole.Shape) hole.ViewObject.hide() # to be removed - if not base.isNull(): + if base.isValid() and (not base.isNull()) and base.Solids: + if base.Volume < 0: + base.reverse() + if base.Volume < 0: + FreeCAD.Console.PrintError(str(translate("Arch","Couldn't compute the wall shape"))) + return try: base = base.removeSplitter() except: diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py index 9c540e7be..5a78ce627 100644 --- a/src/Mod/Arch/ArchWindow.py +++ b/src/Mod/Arch/ArchWindow.py @@ -21,7 +21,7 @@ #* * #*************************************************************************** -import FreeCAD,FreeCADGui,Draft,ArchComponent,DraftVecUtils +import FreeCAD,FreeCADGui,Draft,ArchComponent,DraftVecUtils,ArchCommands from FreeCAD import Vector from PyQt4 import QtCore,QtGui from DraftTools import translate @@ -49,12 +49,7 @@ def makeWindow(baseobj=None,width=None,name=str(translate("Arch","Window"))): if obj.Base: obj.Base.ViewObject.DisplayMode = "Wireframe" obj.Base.ViewObject.hide() - p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") - c = p.GetUnsigned("WindowColor") - r = float((c>>24)&0xFF)/255.0 - g = float((c>>16)&0xFF)/255.0 - b = float((c>>8)&0xFF)/255.0 - obj.ViewObject.ShapeColor = (r,g,b,1.0) + obj.ViewObject.ShapeColor = ArchCommands.getDefaultColor("Window") return obj def makeDefaultWindowPart(obj): diff --git a/src/Mod/Arch/Arch_rc.py b/src/Mod/Arch/Arch_rc.py index 590681ea5..f6b175977 100644 --- a/src/Mod/Arch/Arch_rc.py +++ b/src/Mod/Arch/Arch_rc.py @@ -2,8 +2,8 @@ # Resource object code # -# Created: Sun Jul 22 16:38:54 2012 -# by: The Resource Compiler for PyQt (Qt v4.8.1) +# Created: Sun Aug 5 16:52:51 2012 +# by: The Resource Compiler for PyQt (Qt v4.8.2) # # WARNING! All changes made in this file will be lost! @@ -6042,85 +6042,100 @@ qt_resource_data = "\ \x00\x00\x00\x12\x00\x57\x00\x65\x00\x72\x00\x6b\x00\x7a\x00\x65\ \x00\x75\x00\x67\x00\x65\x08\x00\x00\x00\x00\x06\x00\x00\x00\x05\ \x54\x6f\x6f\x6c\x73\x07\x00\x00\x00\x04\x61\x72\x63\x68\x01\ -\x00\x00\x04\xd0\ +\x00\x00\x05\xb5\ \x00\ -\x00\x1e\xaa\x78\x9c\xed\x59\x6d\x6f\xdb\x36\x10\xfe\x9e\x5f\x41\ -\xe8\xd3\x06\x6c\x95\xed\xd8\x6e\x13\xc8\x2a\xd6\x74\x79\x01\x5a\ -\x2c\x81\xd3\xe6\xe3\x20\x4b\x67\x8b\xab\x24\x7a\x24\x95\xd8\xfd\ -\xf5\x3d\x92\x92\x65\xbd\x58\x89\x63\x27\x01\x82\x00\x31\x22\xf2\ -\x4e\xc7\xe3\xc3\xe3\xa3\x3b\xd2\xf9\xb8\x88\x23\x72\x0b\x5c\x50\ -\x96\x8c\xac\xee\xbb\x8e\x45\x20\xf1\x59\x40\x93\xd9\xc8\xfa\x76\ -\x7d\xfa\xe7\x07\xeb\xa3\x7b\xe0\xa4\xb4\x50\xea\xa3\x92\x7b\x40\ -\x1c\x3f\xf2\x84\x70\xcf\x52\x7a\x7c\xfc\x99\x7a\x11\x9b\xe1\xff\ -\x68\x36\x06\x29\xf1\x65\xf1\x17\xf7\x43\xc7\x36\x3a\xa8\x7c\x47\ -\x83\x19\x48\xa2\xdb\x23\xeb\xea\x46\x37\x2d\x92\x78\x31\x8c\xac\ -\x36\x1b\x6a\x28\xe2\xcc\x39\x9b\x03\x97\xcb\xec\x85\x19\xb0\x18\ -\x24\x5f\x6a\x21\x71\x38\xf8\x52\x3f\x11\x67\xe1\x76\x1c\x7b\x91\ -\x35\x96\xaa\xb1\xcc\x1a\xe8\x81\x0c\xdd\xc1\xfb\x81\x63\x9b\x47\ -\xd3\x1d\x02\x9d\x85\xd2\x1d\xf6\x8e\x1c\x3b\x7b\xd6\x36\xed\xdc\ -\xa8\x63\xe7\x83\x37\x79\x72\x47\x93\x80\xdd\x5d\x53\x19\x41\xe6\ -\x8c\x90\x1c\x7d\x77\xcf\x20\x01\xee\x45\x44\x64\x73\x71\xec\x4c\ -\x50\x37\x19\x79\x4b\x96\x16\xd8\x7c\xff\xc4\x16\x5f\x74\x57\x66\ -\xb1\x32\xa4\x98\x7b\x3e\x1a\xb2\xb2\x09\x24\x69\x3c\x01\xee\x0e\ -\x1d\x3b\x7b\x32\xee\xaf\x8f\x50\x33\x11\x7b\x7c\x46\x93\x8a\x85\ -\xa3\x56\x0b\x54\x42\x5c\x20\xb9\xbe\x96\x67\x9c\xa5\x73\xf4\x39\ -\x5f\xcd\x59\xde\x36\xea\xb5\xc1\x65\x01\x56\x03\x5e\x6a\xcd\xc9\ -\xb8\x01\xb4\xba\x4f\xad\xd0\x65\x83\x61\xd4\x4a\xea\x7b\x91\xe9\ -\xfd\xb7\x57\x8c\x5b\x4c\xa8\xc1\xd0\x79\xcd\x50\xc8\x38\xfd\xc9\ -\x12\xd9\x60\xaa\x6a\xac\x0e\xd1\x17\x6f\x02\x51\x6e\x29\x52\x8d\ -\xd2\xeb\x0d\x18\xc1\x42\x96\x14\x56\x38\x7d\x86\xa9\x97\x46\x68\ -\x9a\x45\x8c\x93\x29\xfe\xee\xbc\x28\xaa\x22\xd5\x0c\x97\xe9\x34\ -\xbe\xad\x39\x6f\x97\xbd\xaf\x4d\x46\x05\x1c\xf0\x1a\x0e\x63\xdd\ -\xdd\x3a\x0d\xd4\x05\x54\x95\xc8\x1b\x95\xd9\x00\x86\x9a\x7b\x25\ -\x8f\x8f\xcf\x57\xf6\x1c\x5b\x77\xde\x37\x81\xfa\x7e\xa0\x3f\xe1\ -\x9c\x26\xb8\x52\x42\x06\xb8\xdd\x46\x56\xa7\x0a\x1d\x6a\x94\x7a\ -\x72\x36\xe8\x77\x4a\x64\xb0\x92\x66\x44\xd0\xeb\x94\x38\xa1\x70\ -\xab\x6a\x70\x03\xd2\x06\xb8\x2d\x90\x2e\x87\x8d\xa6\xc5\x4b\x0e\ -\xd3\x13\xb5\xd6\x9f\x52\x29\x11\xc6\x7c\x93\x29\xd9\x1c\x65\x3a\ -\x0e\x26\x46\xd6\x1a\x51\x8c\x45\xd7\x74\xde\x1c\x54\xd7\x21\x15\ -\x04\xff\x64\x08\x24\xa8\x05\x58\x02\x77\xe4\x06\x83\x8c\xb0\xc9\ -\x7f\x48\x8a\x0f\x8f\xb5\x9a\x13\xda\x66\xc5\x05\xdd\x57\xc1\x9f\ -\x43\xe0\xf6\x06\x03\x45\xc2\x41\x45\x34\xe3\x00\x89\xdb\x3d\xc2\ -\xa5\x31\x8f\x65\xf1\x24\x4a\xc1\xed\xbe\x47\xa9\x7e\x2a\x2f\x5b\ -\x6d\xa8\x87\x79\xad\x60\xfe\x3b\x51\x9f\x9b\x8d\x11\xe6\x67\x88\ -\x28\x98\xf4\x6a\xe1\x60\x8f\x05\x49\x0d\x77\xe9\xc9\xf0\xfe\xd1\ -\xbe\xb2\xc0\xce\xbe\xb3\xfb\xda\xfd\x8e\x6d\x98\x70\x45\x93\x25\ -\xf1\xae\xa4\xb9\x13\x65\xee\x8d\x30\x51\x90\xfa\x32\xe5\xf0\x72\ -\xac\x79\x0f\xfd\xbf\xf1\xe6\x73\xf2\xe6\x7d\xdf\xe2\xdd\x98\x73\ -\x9c\x47\xdb\xf3\xd2\x67\x77\xd0\x69\xa1\xcf\xe1\x51\x1b\x7d\x7e\ -\x18\xbe\x10\x7d\xae\xb0\x7a\xe3\xd0\xcd\x89\xe7\x70\xb7\xc4\x73\ -\xb0\xbf\xc4\x53\xd7\x3e\x2f\x48\xa2\xfd\x37\x12\xdd\x8c\xf5\x73\ -\x93\xe8\x61\xeb\x62\x6c\x43\x5d\x83\xa3\x16\xe6\x3a\xec\xb5\x31\ -\x57\xff\xa5\x98\xeb\x46\xef\x85\xd7\x4b\x5b\x65\x61\xc9\xd6\x9a\ -\xde\x23\x4e\x09\x8a\x8f\xef\xc3\xce\x09\x2e\x4e\x4f\x08\x8d\xe7\ -\x8c\xcb\x7d\x1f\x0e\xec\xef\x68\x60\xf0\x70\x86\x2e\xb6\x59\x08\ -\xfe\x8f\x75\x7c\x56\x7b\x4c\x09\x26\xc5\x71\x4a\x33\x56\x6d\x39\ -\xca\xc5\x14\xd3\x13\x93\xa6\x68\x63\x10\xfc\xa1\xf3\x15\x84\xf2\ -\x9f\x39\x24\xe3\x10\xb0\xb6\x33\x98\x82\x62\x75\x6c\x4d\x80\xa4\ -\x42\xe9\x61\x3d\xc3\x90\xe7\x67\x44\xb2\x4c\x85\xc4\x8c\xeb\x77\ -\x89\x5c\xce\xb7\x48\xa1\xb7\xf8\xd4\x7c\x13\x55\xe7\xa6\xc4\xbb\ -\xf5\x28\x7e\xc0\x22\x78\xfc\x80\x5b\x6c\x67\x9c\xfc\xc5\xd4\x5f\ -\x39\xf0\x2a\xb7\xf4\xee\x71\x7e\xf8\x14\x71\xbe\x4b\x36\x7e\xc2\ -\xc1\x93\x20\x88\x26\x17\xa1\x93\x14\xf0\xfc\xd0\x1c\x2a\x9a\xf4\ -\x5b\x47\xed\x53\x04\xad\x26\x38\xcc\x8e\x70\x93\x24\x98\x77\x08\ -\x32\x59\xee\xba\x43\xb6\x08\x58\x5f\xcf\x1c\x63\x56\xbb\x21\xde\ -\x02\xb6\x31\x60\xfb\x4f\x12\xb0\xed\x99\xcf\xe6\x88\xb9\x30\x7c\ -\x3a\x4d\x79\x42\x75\x81\xf8\x9b\xef\x25\x24\xf6\x7e\x80\xa6\xe7\ -\x98\x05\x10\x91\x10\xbc\xdb\xe5\xef\xcf\x12\x43\x86\xdf\x31\x86\ -\x4e\x73\x8f\x5e\x65\x18\x6d\x9f\xca\x94\xaa\x90\x3c\x69\x28\x1f\ -\x7f\x3f\xa4\xf8\x28\xea\x8e\xef\x99\x8d\x52\xd5\x51\x4f\x60\xb6\ -\xa8\x35\xca\x65\x46\x56\x61\xf4\x6a\x15\x46\x5e\x5c\xf4\x6b\xc5\ -\x45\xa9\xae\xa8\xba\x52\xaa\x26\x0a\x90\xd6\x90\x5c\x83\x31\xdb\ -\x97\xf9\x69\x48\x76\x5d\x35\xb2\x86\x16\x31\xf7\x4e\x23\xab\xdb\ -\xb5\x6c\xa5\x39\xa7\x8b\xd8\x9b\x4f\xd3\xc4\x57\x40\xb9\xff\x5f\ -\xea\xf6\x29\x67\xf1\x57\x1a\xc3\x98\xa5\xdc\xc7\x18\xac\x68\xa9\ -\xab\xc7\x54\x48\x16\x9b\x11\x85\xf6\x64\xbd\xc7\x78\xb9\x76\x3d\ -\xb9\x56\xc2\x14\x57\x92\x6a\x3d\x16\x12\x92\x40\xb8\x57\x97\xa9\ -\x08\x73\x79\xde\x79\x60\xe0\xf2\x02\x9c\x36\x5a\xb1\xcd\x95\xa5\ -\x78\x17\x2a\xe4\x74\xaf\x46\xa0\x3a\x70\xbb\x27\x95\x82\xaa\xd1\ -\x9b\xba\xcb\x9b\x5c\x52\xd6\xf6\xe7\x56\xc6\x73\xcd\x08\x15\xd2\ -\xdd\x9d\x29\x77\xe8\xeb\x61\x0e\x42\x2f\xb6\xd0\x61\xe1\xb3\x24\ -\x01\xbd\xd8\xaa\xed\xd8\x29\x75\x0f\x7e\x01\x09\x6b\xe1\xfc\ +\x00\x27\xfd\x78\x9c\xed\x5a\x6d\x4f\xe3\x38\x10\xfe\xce\xaf\xb0\ +\xf2\xe9\x4e\xba\x23\xa5\x50\x58\x50\x9a\xd5\x2d\x1c\x0b\xd2\xae\ +\x8e\xbd\xb2\xbb\x1f\x4f\x69\x32\x6d\x7c\x9b\xd8\x39\xc7\xa1\xed\ +\xfe\xfa\x1b\xdb\x49\xd3\xbc\x34\x50\x5a\x40\x42\x20\x10\xb1\xc7\ +\x9d\x19\x3f\x9e\x79\x3c\x76\xe3\xbc\x9f\xc7\x11\xb9\x03\x91\x52\ +\xce\x86\xd6\xc1\x7e\xcf\x22\xc0\x7c\x1e\x50\x36\x1d\x5a\x5f\x6f\ +\x2f\x7f\x7f\x67\xbd\x77\xf7\x9c\x8c\x96\x83\x8e\x70\x90\xbb\x47\ +\x1c\x3f\xf2\xd2\xd4\xfd\x98\xd1\xb3\xb3\x0b\xea\x45\x7c\x8a\xff\ +\xa3\xe9\x08\xa4\xc4\x0f\xa7\x7f\x08\x3f\x74\x6c\x33\x06\x07\xcf\ +\x68\x30\x05\x49\x74\x7b\x68\x7d\xf9\xae\x9b\x16\x61\x5e\x0c\x43\ +\xab\x4b\x87\x32\x45\x9c\x44\xf0\x04\x84\x5c\xe4\x1f\x98\x02\x8f\ +\x41\x8a\x85\x16\x12\x47\x80\x2f\xf5\x13\x71\xe6\x6e\xcf\xb1\xe7\ +\x79\x63\xa1\x1a\x8b\xbc\x81\x1e\xc8\xd0\x1d\x9c\x0c\x1c\xdb\x3c\ +\x9a\xee\x10\xe8\x34\x94\xee\x71\xff\xd4\xb1\xf3\x67\xad\xd3\x2e\ +\x94\x3a\x76\x61\xbc\xcd\x93\x19\x65\x01\x9f\xdd\x52\x19\x41\xee\ +\x4c\x2a\x05\xfa\xee\x7e\x04\x06\xc2\x8b\x48\x9a\xcf\xc5\xb1\x73\ +\x41\x53\x65\xe4\x2d\x78\x56\x62\xf3\xed\x03\x9f\x7f\xd2\x5d\xb9\ +\xc6\x9a\xc9\x34\xf1\x7c\x54\x64\xe5\x13\x60\x59\x3c\x06\xe1\x1e\ +\x3b\x76\xfe\x64\xdc\x5f\xb5\xd0\x50\x11\x7b\x62\x4a\x59\x4d\xc3\ +\x69\xa7\x06\x2a\x21\x2e\x91\x5c\x5d\xcb\x8f\x82\x67\x09\xfa\x5c\ +\xac\xe6\xb4\x68\x9b\xe1\x0d\xe3\xb2\x04\xab\x05\x2f\xb5\xe6\x64\ +\xd4\x02\x5a\xd3\xa7\x4e\xe8\x72\x63\x18\xb5\x92\xfa\x5e\x64\x7a\ +\xff\xe9\x97\x76\xcb\x09\xb5\x28\xba\x6a\x28\x0a\xb9\xa0\x3f\x39\ +\x93\x2d\xaa\xea\xca\x9a\x10\x7d\xf2\xc6\x10\x15\x9a\x22\xd5\xa8\ +\x7c\xbc\x05\x23\x98\xcb\xca\x80\x25\x4e\x17\x30\xf1\xb2\x08\x55\ +\xf3\x88\x0b\x32\xc1\xbf\x99\x17\x45\x75\xa4\xda\xe1\x32\x9d\xc6\ +\xb7\x15\xe7\xed\xaa\xf7\x8d\xc9\xa8\x80\x03\xd1\xc0\x61\xa4\xbb\ +\x3b\xa7\x81\x63\x01\x87\x4a\xe4\x8d\xda\x6c\x00\x43\xcd\xfd\x22\ +\xcf\xce\xae\x96\xfa\x1c\x5b\x77\xde\x37\x81\x66\x3e\xd0\x9f\x70\ +\x45\x19\xae\x54\x2a\x03\x4c\xb7\xa1\xd5\xab\x43\x87\x23\x2a\x3d\ +\x05\x1b\x1c\xf5\x2a\x64\xb0\x94\xe6\x44\xd0\xef\x55\x38\xa1\x74\ +\xab\xae\x70\x0d\xd2\x06\xb8\x0d\x90\xae\x86\x8d\xa6\xc5\x1b\x01\ +\x93\x73\xb5\xd6\x1f\x32\x29\x11\xc6\x22\xc9\x94\x2c\x41\x99\x8e\ +\x83\xb1\x91\x75\x46\x14\xe7\xd1\x2d\x4d\xda\x83\xea\x36\xa4\x29\ +\xc1\x5f\x19\x02\x09\x1a\x01\xc6\x60\x46\xbe\x63\x90\x11\x3e\xfe\ +\x17\x49\xf1\xe1\xb1\xd6\x70\x42\xeb\xac\xb9\xa0\xfb\x6a\xf8\x0b\ +\x08\xdc\xfe\x60\xa0\x48\x38\xa8\x89\xa6\x02\x80\xb9\x07\xa7\xb8\ +\x34\xe6\xb1\x2a\x1e\x47\x19\xb8\x07\x27\x28\xd5\x4f\xd5\x65\x6b\ +\x98\x7a\x98\xd7\x0a\xe6\x3f\x99\xda\x6e\xd6\x46\x98\x9f\x23\xa2\ +\x60\xd2\xab\x85\xc6\x1e\x0b\x92\x32\x77\xe3\xc9\xf0\x7e\x6b\x9f\ +\x79\x60\xe7\xfb\xec\xae\xb2\xdf\xb1\x0d\x13\x2e\x69\xb2\x22\xde\ +\x96\x34\xb7\xa2\xcc\x9d\x11\x26\x0a\x32\x5f\x66\x02\x5e\x8e\x35\ +\xef\xa1\xff\x37\xde\x7c\x4e\xde\xbc\x6f\x2f\xde\x8e\x39\x47\x45\ +\xb4\x3d\x2f\x7d\x1e\x0c\x7a\x1d\xf4\x79\x7c\xda\x45\x9f\xef\x8e\ +\x5f\x88\x3e\x97\x58\xbd\x71\xe8\xfa\xc2\xf3\x78\xbb\xc2\x73\xb0\ +\xbb\xc2\x53\x9f\x7d\x5e\x90\x44\x8f\xde\x48\x74\x3d\xd6\xcf\x4d\ +\xa2\x87\x9d\x8b\xb1\x09\x75\x0d\x4e\x3b\x98\xeb\xb0\xdf\xc5\x5c\ +\x47\x2f\xc5\x5c\xdf\x75\x2e\xbc\x5e\xda\xaa\x0a\x2b\xba\x56\xc6\ +\x3d\xe2\x96\xa0\xdc\x7c\x1f\x76\x4f\x70\x7d\x79\x4e\x68\x9c\x70\ +\x21\x77\x7d\x39\xb0\xbb\xab\x81\xc1\xc3\x19\xba\x4c\xb3\x10\xfc\ +\x1f\xab\xf8\x2c\x73\x4c\x09\xc6\xe5\x75\x4a\x3b\x56\x5d\x35\xca\ +\xf5\x04\xcb\x13\x53\xa6\x68\x65\x10\xfc\xa6\xeb\x15\x84\xf2\xaf\ +\x04\xd8\x28\x04\x3c\xdb\x19\x4c\x41\xb1\x3a\xb6\xc6\x40\xb2\x54\ +\x8d\xc3\xf3\x0c\x47\x9e\x9f\x12\xc9\xf3\x21\x24\xe6\x42\x7f\x96\ +\xc8\x45\xb2\x41\x09\xbd\xc1\x56\xf3\x35\xad\x3b\x37\x21\xde\x9d\ +\x47\x71\x03\x8b\xe0\xf1\x06\x37\x48\x67\x9c\xfc\xf5\xc4\x5f\x3a\ +\xf0\x2a\x53\x7a\xfb\x38\x3f\x7c\x8a\x38\xdf\xa6\x1a\x3f\x17\xe0\ +\x49\x48\x89\x26\x97\x54\x17\x29\xe0\xf9\xa1\xb9\x54\x34\xe5\xb7\ +\x8e\xda\xa7\x08\x5a\x4d\x70\x58\x1d\x61\x92\x30\xac\x3b\x52\x32\ +\x5e\x6c\x9b\x21\x1b\x04\xac\xaf\x67\x8e\x31\xab\xdd\x48\xdf\x02\ +\xb6\x35\x60\x8f\x9e\x24\x60\xbb\x2b\x9f\xf5\x11\x73\x6d\xf8\x74\ +\x92\x09\x46\xf5\x01\xf1\x17\xdf\x63\x24\xf6\x7e\x80\xa6\xe7\x98\ +\x07\x10\x91\x10\xbc\xbb\xc5\xaf\xcf\x12\x43\x86\xdf\x31\x86\x2e\ +\x0b\x8f\x5e\x65\x18\x3d\x5d\x29\x73\xb8\x59\x29\xd3\xbf\x20\x02\ +\x58\x00\xaa\xb1\xf3\x6f\x3a\x0e\x77\x57\xce\x9c\x3c\x49\xd6\x74\ +\x1f\xde\x3a\x69\x7e\x14\xf2\x19\x09\x60\x9c\x4d\x09\x65\x48\xf2\ +\xb1\x3e\xe4\x91\x20\x53\x52\xd2\x01\xeb\x06\xf1\xbb\x3e\x6d\xb5\ +\x75\x63\x01\xcb\x25\xe3\x46\x0c\x69\xea\x4d\x9f\x89\xeb\x95\x03\ +\xdf\xfe\xfe\x7c\xa1\x2c\xbf\xca\x0c\xdd\x3e\x64\xdf\x6d\x77\x47\ +\xf2\x58\x46\x3f\x47\x2f\x3d\xdc\x89\x53\x12\x51\xa6\x58\x9c\xfa\ +\x3f\x18\x86\x06\x11\x2a\x42\x5f\xee\xa2\xa4\x7b\x3e\x6f\x17\x25\ +\x3b\xb9\x28\xb9\xe0\x19\x1e\x4f\x46\x09\x65\x6d\xbc\x17\x68\x69\ +\x8a\xd2\xad\xce\x72\xa3\x04\x7c\x3a\xa1\x58\xe3\x2a\x16\x8a\x3d\ +\x86\x45\x26\x45\xf6\xd1\x15\xc3\x1d\x85\x19\x04\xf5\xd8\x8b\xb3\ +\x54\xaa\x03\x9d\x97\x24\x11\x45\x31\x9e\xe4\x7c\x8c\x53\x35\x6a\ +\x0b\xbe\xba\xf3\xa2\x0c\x6a\x3e\x9a\x39\xba\xfd\xfd\x5e\xf5\xc7\ +\xb1\x73\xc9\x53\xb2\x22\xe6\xde\x27\x9c\xd2\x6d\x31\xef\x57\xc9\ +\x8c\x9b\xd7\x2e\x15\x62\x28\x6a\x84\xea\x57\xf7\x0f\xe1\x83\x92\ +\x0a\xbe\xe5\x3a\x2a\x44\xd0\xac\x57\x36\x48\xff\x6a\xe6\xe7\x49\ +\xdf\x6f\x24\x7d\x91\xef\x47\x8d\x7c\xaf\xa4\x7a\xdd\x95\x4a\x82\ +\x97\x20\xad\x20\xb9\x02\x63\xbe\xd5\x14\xdf\xe4\xe4\xaf\xda\x0c\ +\xad\x63\x8b\x98\x77\x66\x86\xd6\xc1\x81\x65\xab\x91\x09\x9d\xc7\ +\x5e\x32\xc9\x98\xaf\x80\x72\xff\xbb\xd1\xed\x4b\xc1\xe3\xcf\x98\ +\x90\x23\x9e\x09\x1f\xeb\xe7\xda\x28\xf5\xda\x14\xa6\x23\x8f\x8d\ +\xc5\x54\x7b\xb2\xda\x63\xbc\x5c\x79\xb5\x6a\xe5\xfa\xb5\x7c\x9d\ +\x4a\xad\xc7\x5c\x62\x09\x92\xba\x5f\x6e\xb2\x34\x2c\xe4\x45\xe7\ +\x9e\x81\xcb\xc3\x12\x45\x69\xb1\xcd\xeb\x56\xe9\x7e\xa8\x90\xd3\ +\xbd\x1a\x81\xba\xe1\x6e\x4f\x6a\x97\xc1\xad\xde\x34\x5d\x5e\xe7\ +\x92\xd2\xb6\x3b\xb7\xf2\x6a\xb3\x1d\xa1\x52\xfa\x2c\xce\x54\xf6\ +\x81\x76\x8f\x6a\x43\xb6\x77\xab\xda\xa1\xdf\xb8\x13\x90\xea\x18\ +\x4c\x75\xb4\xfa\x9c\x31\xd0\x31\xa8\xda\x8e\x9d\x51\x77\xef\x7f\ +\xd6\x19\x97\xf4\ \x00\x00\x07\x4c\ \x00\ \x00\x29\xd1\x78\x9c\xed\x59\x5b\x8f\xe2\x46\x16\x7e\xef\x5f\xe1\ @@ -11371,35 +11386,35 @@ qt_resource_struct = "\ \x00\x00\x01\x8a\x00\x00\x00\x00\x00\x01\x00\x01\x1d\x6e\ \x00\x00\x00\xba\x00\x00\x00\x00\x00\x01\x00\x00\x6c\x7e\ \x00\x00\x00\x38\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x05\x6e\x00\x01\x00\x00\x00\x01\x00\x02\x52\xde\ -\x00\x00\x04\x7a\x00\x00\x00\x00\x00\x01\x00\x02\x15\x0f\ -\x00\x00\x03\x16\x00\x00\x00\x00\x00\x01\x00\x01\xb7\x13\ -\x00\x00\x06\x9e\x00\x01\x00\x00\x00\x01\x00\x02\xa9\x48\ -\x00\x00\x05\x40\x00\x01\x00\x00\x00\x01\x00\x02\x4c\x0c\ -\x00\x00\x03\x50\x00\x01\x00\x00\x00\x01\x00\x01\xc5\x82\ -\x00\x00\x03\xa2\x00\x01\x00\x00\x00\x01\x00\x01\xd9\x09\ -\x00\x00\x02\xba\x00\x01\x00\x00\x00\x01\x00\x01\x9c\x71\ -\x00\x00\x06\x38\x00\x00\x00\x00\x00\x01\x00\x02\x86\x04\ -\x00\x00\x04\xba\x00\x00\x00\x00\x00\x01\x00\x02\x2e\xe9\ -\x00\x00\x04\x5a\x00\x01\x00\x00\x00\x01\x00\x02\x0d\x47\ -\x00\x00\x02\x98\x00\x01\x00\x00\x00\x01\x00\x01\x93\x78\ -\x00\x00\x06\x0e\x00\x01\x00\x00\x00\x01\x00\x02\x7e\x6f\ -\x00\x00\x03\x7e\x00\x01\x00\x00\x00\x01\x00\x01\xce\xda\ -\x00\x00\x02\x4e\x00\x01\x00\x00\x00\x01\x00\x01\x82\xd0\ -\x00\x00\x02\x78\x00\x01\x00\x00\x00\x01\x00\x01\x8c\x78\ -\x00\x00\x04\xea\x00\x01\x00\x00\x00\x01\x00\x02\x3e\x57\ -\x00\x00\x04\x0e\x00\x00\x00\x00\x00\x01\x00\x01\xf5\x04\ -\x00\x00\x05\x18\x00\x01\x00\x00\x00\x01\x00\x02\x43\xa7\ -\x00\x00\x04\x38\x00\x01\x00\x00\x00\x01\x00\x02\x05\x85\ -\x00\x00\x05\x98\x00\x00\x00\x00\x00\x01\x00\x02\x59\xb8\ -\x00\x00\x03\xc6\x00\x01\x00\x00\x00\x01\x00\x01\xde\x20\ -\x00\x00\x05\xe2\x00\x01\x00\x00\x00\x01\x00\x02\x75\xf5\ -\x00\x00\x05\xc2\x00\x01\x00\x00\x00\x01\x00\x02\x6b\xbb\ -\x00\x00\x04\x9a\x00\x01\x00\x00\x00\x01\x00\x02\x28\xd1\ -\x00\x00\x06\x64\x00\x00\x00\x00\x00\x01\x00\x02\x97\xd3\ -\x00\x00\x02\xec\x00\x00\x00\x00\x00\x01\x00\x01\xa4\xb3\ -\x00\x00\x03\xf0\x00\x00\x00\x00\x00\x01\x00\x01\xe6\x08\ -\x00\x00\x02\x1a\x00\x01\x00\x00\x00\x01\x00\x01\x7b\x80\ +\x00\x00\x05\x6e\x00\x01\x00\x00\x00\x01\x00\x02\x53\xc3\ +\x00\x00\x04\x7a\x00\x00\x00\x00\x00\x01\x00\x02\x15\xf4\ +\x00\x00\x03\x16\x00\x00\x00\x00\x00\x01\x00\x01\xb7\xf8\ +\x00\x00\x06\x9e\x00\x01\x00\x00\x00\x01\x00\x02\xaa\x2d\ +\x00\x00\x05\x40\x00\x01\x00\x00\x00\x01\x00\x02\x4c\xf1\ +\x00\x00\x03\x50\x00\x01\x00\x00\x00\x01\x00\x01\xc6\x67\ +\x00\x00\x03\xa2\x00\x01\x00\x00\x00\x01\x00\x01\xd9\xee\ +\x00\x00\x02\xba\x00\x01\x00\x00\x00\x01\x00\x01\x9d\x56\ +\x00\x00\x06\x38\x00\x00\x00\x00\x00\x01\x00\x02\x86\xe9\ +\x00\x00\x04\xba\x00\x00\x00\x00\x00\x01\x00\x02\x2f\xce\ +\x00\x00\x04\x5a\x00\x01\x00\x00\x00\x01\x00\x02\x0e\x2c\ +\x00\x00\x02\x98\x00\x01\x00\x00\x00\x01\x00\x01\x94\x5d\ +\x00\x00\x06\x0e\x00\x01\x00\x00\x00\x01\x00\x02\x7f\x54\ +\x00\x00\x03\x7e\x00\x01\x00\x00\x00\x01\x00\x01\xcf\xbf\ +\x00\x00\x02\x4e\x00\x01\x00\x00\x00\x01\x00\x01\x83\xb5\ +\x00\x00\x02\x78\x00\x01\x00\x00\x00\x01\x00\x01\x8d\x5d\ +\x00\x00\x04\xea\x00\x01\x00\x00\x00\x01\x00\x02\x3f\x3c\ +\x00\x00\x04\x0e\x00\x00\x00\x00\x00\x01\x00\x01\xf5\xe9\ +\x00\x00\x05\x18\x00\x01\x00\x00\x00\x01\x00\x02\x44\x8c\ +\x00\x00\x04\x38\x00\x01\x00\x00\x00\x01\x00\x02\x06\x6a\ +\x00\x00\x05\x98\x00\x00\x00\x00\x00\x01\x00\x02\x5a\x9d\ +\x00\x00\x03\xc6\x00\x01\x00\x00\x00\x01\x00\x01\xdf\x05\ +\x00\x00\x05\xe2\x00\x01\x00\x00\x00\x01\x00\x02\x76\xda\ +\x00\x00\x05\xc2\x00\x01\x00\x00\x00\x01\x00\x02\x6c\xa0\ +\x00\x00\x04\x9a\x00\x01\x00\x00\x00\x01\x00\x02\x29\xb6\ +\x00\x00\x06\x64\x00\x00\x00\x00\x00\x01\x00\x02\x98\xb8\ +\x00\x00\x02\xec\x00\x00\x00\x00\x00\x01\x00\x01\xa5\x98\ +\x00\x00\x03\xf0\x00\x00\x00\x00\x00\x01\x00\x01\xe6\xed\ +\x00\x00\x02\x1a\x00\x01\x00\x00\x00\x01\x00\x01\x7c\x65\ \x00\x00\x01\xf2\x00\x01\x00\x00\x00\x01\x00\x01\x76\xac\ " diff --git a/src/Mod/Arch/Resources/ui/archprefs-base.ui b/src/Mod/Arch/Resources/ui/archprefs-base.ui index ec9b787c0..2a793cfa1 100644 --- a/src/Mod/Arch/Resources/ui/archprefs-base.ui +++ b/src/Mod/Arch/Resources/ui/archprefs-base.ui @@ -224,6 +224,75 @@ + + + + 2D rendering + + + + + + + + Show debug information during 2D rendering + + + Show renderer debug messages + + + ShowVRMDebug + + + Mod/Arch + + + + + + + + + + + Cut areas line thickness ratio + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Specifies how many times the viewed line thickness must be applied to cut lines + + + 2.000000000000000 + + + CutLineThickness + + + Mod/Arch + + + + + + + + @@ -257,6 +326,11 @@ QCheckBox
Gui/PrefWidgets.h
+ + Gui::PrefDoubleSpinBox + QDoubleSpinBox +
Gui/PrefWidgets.h
+
diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index d9e4d0a99..337d49756 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -1562,10 +1562,8 @@ def makeSketch(objectslist,autoconstraints=False,addTo=None,name="Sketch"): if tp == "BSpline": print "makeSketch: BSplines not supported" elif tp == "Circle": - if obj.FirstAngle == obj.LastAngle: - nobj.addGeometry(obj.Shape.Edges[0].Curve) - else: - nobj.addGeometry(Part.ArcOfCircle(obj.Shape.Edges[0].Curve,math.radians(obj.FirstAngle),math.radians(obj.LastAngle))) + g = (DraftGeomUtils.geom(obj.Shape.Edges[0],nobj.Placement)) + nobj.addGeometry(g) # TODO add Radius constraits ok = True elif tp == "Rectangle": @@ -1586,25 +1584,26 @@ def makeSketch(objectslist,autoconstraints=False,addTo=None,name="Sketch"): nobj.addConstraint(Constraint("Vertical",last)) ok = True elif tp in ["Wire","Polygon"]: - closed = False - if tp == "Polygon": - closed = True - elif hasattr(obj,"Closed"): - closed = obj.Closed - for edge in obj.Shape.Edges: - nobj.addGeometry(edge.Curve) - if autoconstraints: - last = nobj.GeometryCount - segs = range(last-len(obj.Shape.Edges),last-1) - for seg in segs: - nobj.addConstraint(Constraint("Coincident",seg,EndPoint,seg+1,StartPoint)) - if DraftGeomUtils.isAligned(nobj.Geometry[seg],"x"): - nobj.addConstraint(Constraint("Vertical",seg)) - elif DraftGeomUtils.isAligned(nobj.Geometry[seg],"y"): - nobj.addConstraint(Constraint("Horizontal",seg)) - if closed: - nobj.addConstraint(Constraint("Coincident",last-1,EndPoint,segs[0],StartPoint)) - ok = True + if obj.FilletRadius == 0: + closed = False + if tp == "Polygon": + closed = True + elif hasattr(obj,"Closed"): + closed = obj.Closed + for edge in obj.Shape.Edges: + nobj.addGeometry(edge.Curve) + if autoconstraints: + last = nobj.GeometryCount + segs = range(last-len(obj.Shape.Edges),last-1) + for seg in segs: + nobj.addConstraint(Constraint("Coincident",seg,EndPoint,seg+1,StartPoint)) + if DraftGeomUtils.isAligned(nobj.Geometry[seg],"x"): + nobj.addConstraint(Constraint("Vertical",seg)) + elif DraftGeomUtils.isAligned(nobj.Geometry[seg],"y"): + nobj.addConstraint(Constraint("Horizontal",seg)) + if closed: + nobj.addConstraint(Constraint("Coincident",last-1,EndPoint,segs[0],StartPoint)) + ok = True if (not ok) and obj.isDerivedFrom("Part::Feature"): if not DraftGeomUtils.isPlanar(obj.Shape): print "Error: The given object is not planar and cannot be converted into a sketch." diff --git a/src/Mod/Draft/DraftGeomUtils.py b/src/Mod/Draft/DraftGeomUtils.py index f47ae0f09..441809d22 100755 --- a/src/Mod/Draft/DraftGeomUtils.py +++ b/src/Mod/Draft/DraftGeomUtils.py @@ -39,14 +39,14 @@ precision = params.GetInt("precision") def vec(edge): - "vec(edge) or vec(line) -- returns a vector from an edge or a Part.line" - # if edge is not straight, you'll get strange results! - if isinstance(edge,Part.Shape): - return edge.Vertexes[-1].Point.sub(edge.Vertexes[0].Point) - elif isinstance(edge,Part.Line): - return edge.EndPoint.sub(edge.StartPoint) - else: - return None + "vec(edge) or vec(line) -- returns a vector from an edge or a Part.line" + # if edge is not straight, you'll get strange results! + if isinstance(edge,Part.Shape): + return edge.Vertexes[-1].Point.sub(edge.Vertexes[0].Point) + elif isinstance(edge,Part.Line): + return edge.EndPoint.sub(edge.StartPoint) + else: + return None def edg(p1,p2): "edg(Vector,Vector) -- returns an edge from 2 vectors" @@ -370,17 +370,18 @@ def geom(edge,plac=FreeCAD.Placement()): c = edge.Curve.Center cu = Part.Circle(edge.Curve.Center,normal,edge.Curve.Radius) ref = plac.Rotation.multVec(Vector(1,0,0)) - a1 = math.pi + DraftVecUtils.angle(v1.sub(c),ref,normal) - a2 = DraftVecUtils.angle(v2.sub(c),ref,normal) + a1 = DraftVecUtils.angle(v1.sub(c),ref,DraftVecUtils.neg(normal)) + a2 = DraftVecUtils.angle(v2.sub(c),ref,DraftVecUtils.neg(normal)) # direction check - if a1 > a2: + if edge.Curve.Axis.getAngle(normal) > 1: a1,a2 = a2,a1 - #print "creating sketch arc from ",cu, ", p1=",v1, " (",math.degrees(a1), "d) p2=",v2," (", math.degrees(a2),"d)" + p= Part.ArcOfCircle(cu,a1,a2) return p else: + print edge.Curve return edge.Curve def mirror (point, edge): @@ -539,57 +540,62 @@ def sortEdges(lEdges, aVertex=None): def findWires(edgeslist): - '''finds connected wires in the given list of edges''' + '''finds connected wires in the given list of edges''' - def touches(e1,e2): - if len(e1.Vertexes) < 2: - return False - if len(e2.Vertexes) < 2: - return False - if DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[0].Point): - return True - if DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[-1].Point): - return True - if DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[0].Point): - return True - if DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[-1].Point): - return True - return False - - edges = edgeslist[:] - wires = [] - lost = [] - while edges: - e = edges[0] - if not wires: - # create first group - edges.remove(e) - wires.append([e]) + def touches(e1,e2): + if len(e1.Vertexes) < 2: + return False + if len(e2.Vertexes) < 2: + return False + if DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[0].Point): + return True + if DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[-1].Point): + return True + if DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[0].Point): + return True + if DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[-1].Point): + return True + return False + + edges = edgeslist[:] + wires = [] + lost = [] + while edges: + e = edges[0] + if not wires: + # create first group + edges.remove(e) + wires.append([e]) + else: + found = False + for w in wires: + if not found: + for we in w: + if touches(e,we): + edges.remove(e) + w.append(e) + found = True + break + if not found: + if e in lost: + # we already tried this edge, and still nothing + edges.remove(e) + wires.append([e]) + lost = [] else: - found = False - for w in wires: - if not found: - for we in w: - if touches(e,we): - edges.remove(e) - w.append(e) - found = True - break - if not found: - if e in lost: - # we already tried this edge, and still nothing - edges.remove(e) - wires.append([e]) - lost = [] - else: - # put to the end of the list - edges.remove(e) - edges.append(e) - lost.append(e) - nwires = [] - for w in wires: - nwires.append(Part.Wire(w)) - return nwires + # put to the end of the list + edges.remove(e) + edges.append(e) + lost.append(e) + nwires = [] + for w in wires: + try: + wi = Part.Wire(w) + except: + print "couldn't join some edges" + else: + nwires.append(wi) + return nwires def superWire(edgeslist,closed=False): '''superWire(edges,[closed]): forces a wire between edges that don't necessarily @@ -767,8 +773,8 @@ def getNormal(shape): if (shape.ShapeType == "Face") and hasattr(shape,"normalAt"): n = shape.normalAt(0.5,0.5) elif shape.ShapeType == "Edge": - if isinstance(shape.Curve,Part.Circle): - n = shape.Curve.Axis + if isinstance(shape.Edges[0].Curve,Part.Circle): + n = shape.Edges[0].Curve.Axis else: for e in shape.Edges: if isinstance(e.Curve,Part.Circle): diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py index 1e84dbce8..85c6f8385 100644 --- a/src/Mod/Draft/DraftGui.py +++ b/src/Mod/Draft/DraftGui.py @@ -990,7 +990,7 @@ class DraftToolBar: def setCurrentText(self,tstr): if (not self.taskmode) or (self.taskmode and self.isTaskOn): self.textValue.setText(tstr) - + def sendText(self): ''' this function sends the entered text to the active draft command diff --git a/src/Mod/Draft/DraftSnap.py b/src/Mod/Draft/DraftSnap.py index ddc66e528..5a36e70ff 100644 --- a/src/Mod/Draft/DraftSnap.py +++ b/src/Mod/Draft/DraftSnap.py @@ -317,16 +317,16 @@ class Snapper: "returns a 3D point, projected on the current working plane" view = Draft.get3DView() pt = view.getPoint(x,y) - if hasattr(FreeCAD,"DraftWorkingPlane"): - if view.getCameraType() == "Perspective": - camera = view.getCameraNode() - p = camera.getField("position").getValue() - dv = pt.sub(Vector(p[0],p[1],p[2])) - else: - dv = view.getViewDirection() - return FreeCAD.DraftWorkingPlane.projectPoint(pt,dv) - else: - return pt + if self.mask != "z": + if hasattr(FreeCAD,"DraftWorkingPlane"): + if view.getCameraType() == "Perspective": + camera = view.getCameraNode() + p = camera.getField("position").getValue() + dv = pt.sub(Vector(p[0],p[1],p[2])) + else: + dv = view.getViewDirection() + return FreeCAD.DraftWorkingPlane.projectPoint(pt,dv) + return pt def snapToExtensions(self,point,last,constrain,eline): "returns a point snapped to extension or parallel line to last object, if any" diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index 10d1bb382..916632716 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -3711,7 +3711,7 @@ class Draft2Sketch(): elif obj.isDerivedFrom("Part::Part2DObjectPython"): Draft.makeSketch(obj,autoconstraints=True) elif obj.isDerivedFrom("Part::Feature"): - if len(obj.Shape.Wires) == 1: + if (len(obj.Shape.Wires) == 1) or (len(obj.Shape.Edges) == 1): Draft.makeSketch(obj,autoconstraints=False) FreeCAD.ActiveDocument.commitTransaction() diff --git a/src/Mod/Draft/importDXF.py b/src/Mod/Draft/importDXF.py index ba8fa2909..8efd01723 100644 --- a/src/Mod/Draft/importDXF.py +++ b/src/Mod/Draft/importDXF.py @@ -1356,65 +1356,76 @@ def export(objectslist,filename,nospline=False): "called when freecad exports a file. If nospline=True, bsplines are exported as straight segs" global exportList exportList = objectslist - dxf = dxfLibrary.Drawing() - if (len(exportList) == 1) and (exportList[0].isDerivedFrom("Drawing::FeaturePage")): + + if (len(exportList) == 1) and (Draft.getType(exportList[0]) == "ArchSectionView"): + # arch view: export it "as is" + dxf = exportList[0].Proxy.getDXF() + if dxf: + f = open(filename,"w") + f.write(dxf) + f.close() + + elif (len(exportList) == 1) and (exportList[0].isDerivedFrom("Drawing::FeaturePage")): + # page: special hack-export! (see below) exportPage(exportList[0],filename) - return - for ob in exportList: - print "processing ",ob.Name - if ob.isDerivedFrom("Part::Feature"): - if not ob.Shape.isNull(): - if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft").GetBool("dxfmesh"): - writeMesh(ob,dxf) - else: - if ob.Shape.ShapeType == 'Compound': - if (len(ob.Shape.Wires) == 1): - # only one wire in this compound, no lone edge -> polyline - if (len(ob.Shape.Wires[0].Edges) == len(ob.Shape.Edges)): - writeShape(ob,dxf,nospline) + + else: + # other cases, treat edges + dxf = dxfLibrary.Drawing() + for ob in exportList: + print "processing ",ob.Name + if ob.isDerivedFrom("Part::Feature"): + if not ob.Shape.isNull(): + if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft").GetBool("dxfmesh"): + writeMesh(ob,dxf) + else: + if ob.Shape.ShapeType == 'Compound': + if (len(ob.Shape.Wires) == 1): + # only one wire in this compound, no lone edge -> polyline + if (len(ob.Shape.Wires[0].Edges) == len(ob.Shape.Edges)): + writeShape(ob,dxf,nospline) + else: + # 1 wire + lone edges -> block + block = getBlock(ob) + dxf.blocks.append(block) + dxf.append(dxfLibrary.Insert(name=ob.Name.upper())) else: - # 1 wire + lone edges -> block + # all other cases: block block = getBlock(ob) dxf.blocks.append(block) dxf.append(dxfLibrary.Insert(name=ob.Name.upper())) else: - # all other cases: block - block = getBlock(ob) - dxf.blocks.append(block) - dxf.append(dxfLibrary.Insert(name=ob.Name.upper())) - else: - writeShape(ob,dxf,nospline) - - elif (ob.Type == "App::Annotation"): - - # texts - - # temporary - as dxfLibrary doesn't support mtexts well, we use several single-line texts - # well, anyway, at the moment, Draft only writes single-line texts, so... - for text in ob.LabelText: - point = DraftVecUtils.tup(FreeCAD.Vector(ob.Position.x, - ob.Position.y-ob.LabelText.index(text), - ob.Position.z)) - if gui: height = float(ob.ViewObject.FontSize) - else: height = 1 - dxf.append(dxfLibrary.Text(text,point,height=height, - color=getACI(ob,text=True), - style='STANDARD', - layer=getGroup(ob,exportList))) - - elif 'Dimline' in ob.PropertiesList: - p1 = DraftVecUtils.tup(ob.Start) - p2 = DraftVecUtils.tup(ob.End) - base = Part.Line(ob.Start,ob.End).toShape() - proj = DraftGeomUtils.findDistance(ob.Dimline,base) - if not proj: - pbase = DraftVecUtils.tup(ob.End) - else: - pbase = DraftVecUtils.tup(ob.End.add(DraftVecUtils.neg(proj))) - dxf.append(dxfLibrary.Dimension(pbase,p1,p2,color=getACI(ob), - layer=getGroup(ob,exportList))) - - dxf.saveas(filename) + writeShape(ob,dxf,nospline) + + elif Draft.getType(ob) == "Annotation": + # texts + + # temporary - as dxfLibrary doesn't support mtexts well, we use several single-line texts + # well, anyway, at the moment, Draft only writes single-line texts, so... + for text in ob.LabelText: + point = DraftVecUtils.tup(FreeCAD.Vector(ob.Position.x, + ob.Position.y-ob.LabelText.index(text), + ob.Position.z)) + if gui: height = float(ob.ViewObject.FontSize) + else: height = 1 + dxf.append(dxfLibrary.Text(text,point,height=height, + color=getACI(ob,text=True), + style='STANDARD', + layer=getGroup(ob,exportList))) + + elif Draft.getType(ob) == "Dimension": + p1 = DraftVecUtils.tup(ob.Start) + p2 = DraftVecUtils.tup(ob.End) + base = Part.Line(ob.Start,ob.End).toShape() + proj = DraftGeomUtils.findDistance(ob.Dimline,base) + if not proj: + pbase = DraftVecUtils.tup(ob.End) + else: + pbase = DraftVecUtils.tup(ob.End.add(DraftVecUtils.neg(proj))) + dxf.append(dxfLibrary.Dimension(pbase,p1,p2,color=getACI(ob), + layer=getGroup(ob,exportList))) + + dxf.saveas(filename) FreeCAD.Console.PrintMessage("successfully exported "+filename+"\r\n") def exportPage(page,filename): diff --git a/src/Mod/Mesh/App/Core/Algorithm.cpp b/src/Mod/Mesh/App/Core/Algorithm.cpp index f72bba760..828a6675a 100644 --- a/src/Mod/Mesh/App/Core/Algorithm.cpp +++ b/src/Mod/Mesh/App/Core/Algorithm.cpp @@ -255,6 +255,17 @@ float MeshAlgorithm::GetAverageEdgeLength() const return fLen; } +Base::Vector3f MeshAlgorithm::GetGravityPoint() const +{ + Base::Vector3f center; + MeshPointIterator cP(_rclMesh); + for (cP.Init(); cP.More(); cP.Next()) { + center += *cP; + } + + return center / (float)_rclMesh.CountPoints(); +} + void MeshAlgorithm::GetMeshBorders (std::list > &rclBorders) const { std::vector aulAllFacets(_rclMesh.CountFacets()); diff --git a/src/Mod/Mesh/App/Core/Algorithm.h b/src/Mod/Mesh/App/Core/Algorithm.h index 78a4caf5b..7d55d6e94 100644 --- a/src/Mod/Mesh/App/Core/Algorithm.h +++ b/src/Mod/Mesh/App/Core/Algorithm.h @@ -115,6 +115,10 @@ public: * Calculates the average length of edges. */ float GetAverageEdgeLength() const; + /** + * Calculates the gravity point of the mesh. + */ + Base::Vector3f GetGravityPoint() const; /** * Returns all boundaries of the mesh. */ diff --git a/src/Mod/Part/Gui/TaskFaceColors.cpp b/src/Mod/Part/Gui/TaskFaceColors.cpp index 61a112e90..ba593b5da 100644 --- a/src/Mod/Part/Gui/TaskFaceColors.cpp +++ b/src/Mod/Part/Gui/TaskFaceColors.cpp @@ -30,11 +30,15 @@ # include #endif +#include +#include + #include "ui_TaskFaceColors.h" #include "TaskFaceColors.h" #include "ViewProviderExt.h" #include +#include #include #include @@ -69,15 +73,20 @@ namespace PartGui { class FaceColors::Private { public: + typedef boost::signals::connection Connection; Ui_TaskFaceColors* ui; ViewProviderPartExt* vp; App::DocumentObject* obj; + Gui::Document* doc; std::vector current,perface; QSet index; + Connection connectDelDoc; + Connection connectDelObj; Private(ViewProviderPartExt* vp) : ui(new Ui_TaskFaceColors()), vp(vp) { obj = vp->getObject(); + doc = Gui::Application::Instance->getDocument(obj->getDocument()); // build up map edge->face TopTools_IndexedMapOfShape mapOfShape; @@ -110,14 +119,33 @@ FaceColors::FaceColors(ViewProviderPartExt* vp, QWidget* parent) FaceSelection* gate = new FaceSelection(d->vp->getObject()); Gui::Selection().addSelectionGate(gate); + + d->connectDelDoc = Gui::Application::Instance->signalDeleteDocument.connect(boost::bind + (&FaceColors::slotDeleteDocument, this, _1)); + d->connectDelObj = Gui::Application::Instance->signalDeletedObject.connect(boost::bind + (&FaceColors::slotDeleteObject, this, _1)); } FaceColors::~FaceColors() { Gui::Selection().rmvSelectionGate(); + d->connectDelDoc.disconnect(); + d->connectDelObj.disconnect(); delete d; } +void FaceColors::slotDeleteDocument(const Gui::Document& Doc) +{ + if (d->doc == &Doc) + Gui::Control().closeDialog(); +} + +void FaceColors::slotDeleteObject(const Gui::ViewProvider& obj) +{ + if (d->vp == &obj) + Gui::Control().closeDialog(); +} + void FaceColors::on_defaultButton_clicked() { std::fill(d->perface.begin(), d->perface.end(), d->vp->ShapeColor.getValue()); diff --git a/src/Mod/Part/Gui/TaskFaceColors.h b/src/Mod/Part/Gui/TaskFaceColors.h index eec3035ba..3ba96c9ce 100644 --- a/src/Mod/Part/Gui/TaskFaceColors.h +++ b/src/Mod/Part/Gui/TaskFaceColors.h @@ -27,6 +27,11 @@ #include #include +namespace Gui { + class Document; + class ViewProvider; +} + namespace PartGui { class ViewProviderPartExt; @@ -49,6 +54,8 @@ private Q_SLOTS: protected: void onSelectionChanged(const Gui::SelectionChanges& msg); void changeEvent(QEvent *e); + void slotDeleteDocument(const Gui::Document&); + void slotDeleteObject(const Gui::ViewProvider&); private: class Private; diff --git a/src/Mod/Part/Gui/ViewProviderExt.cpp b/src/Mod/Part/Gui/ViewProviderExt.cpp index 1c2584813..b066476eb 100644 --- a/src/Mod/Part/Gui/ViewProviderExt.cpp +++ b/src/Mod/Part/Gui/ViewProviderExt.cpp @@ -125,9 +125,14 @@ ViewProviderPartExt::ViewProviderPartExt() { VisualTouched = true; + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); + unsigned long lcol = hGrp->GetUnsigned("DefaultShapeLineColor",421075455UL); // dark grey (25,25,25) + float r,g,b; + r = ((lcol >> 24) & 0xff) / 255.0; g = ((lcol >> 16) & 0xff) / 255.0; b = ((lcol >> 8) & 0xff) / 255.0; + int lwidth = hGrp->GetInt("DefaultShapeLineWidth",2); App::Material mat; mat.ambientColor.set(0.2f,0.2f,0.2f); - mat.diffuseColor.set(0.1f,0.1f,0.1f); + mat.diffuseColor.set(r,g,b); mat.specularColor.set(0.0f,0.0f,0.0f); mat.emissiveColor.set(0.0f,0.0f,0.0f); mat.shininess = 1.0f; @@ -137,10 +142,10 @@ ViewProviderPartExt::ViewProviderPartExt() ADD_PROPERTY(LineColor,(mat.diffuseColor)); ADD_PROPERTY(PointColor,(mat.diffuseColor)); ADD_PROPERTY(DiffuseColor,(ShapeColor.getValue())); - ADD_PROPERTY(LineWidth,(2.0f)); + ADD_PROPERTY(LineWidth,(lwidth)); LineWidth.setConstraints(&sizeRange); PointSize.setConstraints(&sizeRange); - ADD_PROPERTY(PointSize,(2.0f)); + ADD_PROPERTY(PointSize,(lwidth)); ADD_PROPERTY(Deviation,(0.5f)); Deviation.setConstraints(&tessRange); ADD_PROPERTY(ControlPoints,(false)); diff --git a/src/Mod/Ship/CMakeLists.txt b/src/Mod/Ship/CMakeLists.txt index 432c91576..9e7ed7347 100644 --- a/src/Mod/Ship/CMakeLists.txt +++ b/src/Mod/Ship/CMakeLists.txt @@ -45,6 +45,8 @@ SET(ShipIcons_SRCS Icons/SimRunIco.xpm Icons/SimStopIco.png Icons/SimStopIco.xpm + Icons/SimPostIco.png + Icons/SimPostIco.xpm Icons/Tank.png Icons/Tank.xcf Icons/Tank.xpm @@ -150,10 +152,20 @@ SET(SimRun_SRCS simRun/clSim/Utils.py simRun/Sim/__init__.py simRun/Sim/initialization.py + simRun/Sim/matrixGen.py + simRun/Sim/computeSources.py + simRun/Sim/fsEvolution.py ) SOURCE_GROUP("simrun" FILES ${SimRun_SRCS}) -SET(all_files ${ShipMain_SRCS} ${ShipIcons_SRCS} ${ShipExamples_SRCS} ${ShipLoadExample_SRCS} ${ShipCreateShip_SRCS} ${ShipOutlineDraw_SRCS} ${ShipAreasCurve_SRCS} ${ShipHydrostatics_SRCS} ${ShipUtils_SRCS} ${ShipWeights_SRCS} ${ShipCreateTank_SRCS} ${ShipGZ_SRCS} ${SimCreate_SRCS} ${SimRun_SRCS}) +SET(SimPost_SRCS + simPost/__init__.py + simPost/TaskPanel.py + simPost/TaskPanel.ui +) +SOURCE_GROUP("simpost" FILES ${SimPost_SRCS}) + +SET(all_files ${ShipMain_SRCS} ${ShipIcons_SRCS} ${ShipExamples_SRCS} ${ShipLoadExample_SRCS} ${ShipCreateShip_SRCS} ${ShipOutlineDraw_SRCS} ${ShipAreasCurve_SRCS} ${ShipHydrostatics_SRCS} ${ShipUtils_SRCS} ${ShipWeights_SRCS} ${ShipCreateTank_SRCS} ${ShipGZ_SRCS} ${SimCreate_SRCS} ${SimRun_SRCS} ${SimPost_SRCS}) ADD_CUSTOM_TARGET(Ship ALL SOURCES ${all_files} @@ -239,6 +251,12 @@ INSTALL( DESTINATION Mod/Ship/simRun ) +INSTALL( + FILES + ${SimPost_SRCS} + DESTINATION + Mod/Ship/simPost +) INSTALL( FILES ${ShipMain_SRCS} diff --git a/src/Mod/Ship/Icons/SimIco.xcf b/src/Mod/Ship/Icons/SimIco.xcf index 8d250eb82..1c00aefe1 100644 Binary files a/src/Mod/Ship/Icons/SimIco.xcf and b/src/Mod/Ship/Icons/SimIco.xcf differ diff --git a/src/Mod/Ship/Icons/SimPostIco.png b/src/Mod/Ship/Icons/SimPostIco.png new file mode 100644 index 000000000..557aa671c Binary files /dev/null and b/src/Mod/Ship/Icons/SimPostIco.png differ diff --git a/src/Mod/Ship/Icons/SimPostIco.xpm b/src/Mod/Ship/Icons/SimPostIco.xpm new file mode 100644 index 000000000..f113ec894 --- /dev/null +++ b/src/Mod/Ship/Icons/SimPostIco.xpm @@ -0,0 +1,2077 @@ +/* XPM */ +static char * SimPostIco_xpm[] = { +"128 128 1946 2", +" c None", +". c #7B7B7B", +"+ c #EAEAEA", +"@ c #E9EAE9", +"# c #E9E9E9", +"$ c #E9E9E8", +"% c #D9D9D9", +"& c #EAEAE9", +"* c #E8E9E8", +"= c #E9E8E8", +"- c #E8E8E8", +"; c #E8E8E7", +"> c #E7E7E7", +", c #E7E6E7", +"' c #E6E6E6", +") c #5F5F5F", +"! c #606060", +"~ c #868686", +"{ c #AEAEAE", +"] c #C3C2C2", +"^ c #D1D1D1", +"/ c #E4E3E3", +"( c #E5E6E5", +"_ c #E6E5E5", +": c #E5E4E5", +"< c #6B6B6B", +"[ c #7B7A7A", +"} c #888889", +"| c #ABABAB", +"1 c #D5D5D5", +"2 c #E5E6E6", +"3 c #E5E5E5", +"4 c #E4E5E4", +"5 c #E4E4E4", +"6 c #E3E3E3", +"7 c #E3E3E2", +"8 c #E2E2E2", +"9 c #5E5E5E", +"0 c #5D5D5D", +"a c #5C5C5C", +"b c #5B5B5C", +"c c #5A5B5B", +"d c #838484", +"e c #BABABA", +"f c #DEDEDE", +"g c #E2E3E2", +"h c #E1E2E2", +"i c #E1E1E2", +"j c #E0E1E0", +"k c #E1E1E1", +"l c #EAE9E9", +"m c #5E5F5F", +"n c #5E5D5E", +"o c #5C5D5C", +"p c #5B5C5B", +"q c #5B5A5A", +"r c #5A5A5A", +"s c #595959", +"t c #595858", +"u c #585857", +"v c #575757", +"w c #686868", +"x c #909090", +"y c #BEBEBE", +"z c #D3D2D3", +"A c #E0E0E0", +"B c #E0DFE0", +"C c #E0DFDF", +"D c #DEDEDF", +"E c #5F5E5E", +"F c #5E5D5D", +"G c #5C5B5B", +"H c #5B5B5B", +"I c #5A5A59", +"J c #595A59", +"K c #595859", +"L c #585757", +"M c #565656", +"N c #555555", +"O c #545455", +"P c #545454", +"Q c #676666", +"R c #717272", +"S c #8B8B8A", +"T c #B7B7B8", +"U c #DFDFDF", +"V c #DDDDDD", +"W c #DCDDDD", +"X c #DDDCDC", +"Y c #E8E9E9", +"Z c #5D5E5E", +"` c #5C5B5C", +" . c #595958", +".. c #585858", +"+. c #565657", +"@. c #555556", +"#. c #545554", +"$. c #555454", +"%. c #535354", +"&. c #525252", +"*. c #525251", +"=. c #515050", +"-. c #4F5050", +";. c #4F4F50", +">. c #4E4F4F", +",. c #959595", +"'. c #CAC9C9", +"). c #D9D9DA", +"!. c #DADBDA", +"~. c #DCDCDC", +"{. c #DDDDDC", +"]. c #DBDCDB", +"^. c #DBDBDB", +"/. c #DADADB", +"(. c #DADADA", +"_. c #E8E8E9", +":. c #5B5A5B", +"<. c #505151", +"[. c #505050", +"}. c #4F4F4F", +"|. c #4E4D4E", +"1. c #4D4D4D", +"2. c #4C4D4D", +"3. c #4C4C4C", +"4. c #4B4B4B", +"5. c #707070", +"6. c #959596", +"7. c #AAAAAA", +"8. c #BFBEBF", +"9. c #D7D7D6", +"0. c #DADAD9", +"a. c #D9DADA", +"b. c #D8D9D9", +"c. c #5B5C5C", +"d. c #5A5B5A", +"e. c #5A5959", +"f. c #565757", +"g. c #535353", +"h. c #535253", +"i. c #505150", +"j. c #4F504F", +"k. c #4E4E4E", +"l. c #4C4B4B", +"m. c #494A49", +"n. c #494949", +"o. c #484747", +"p. c #6C6C6C", +"q. c #C7C7C7", +"r. c #DAD9D9", +"s. c #D9D8D9", +"t. c #D9D8D8", +"u. c #D8D8D8", +"v. c #D8D8D7", +"w. c #D7D8D8", +"x. c #D7D7D7", +"y. c #D6D6D6", +"z. c #D5D5D6", +"A. c #5E5E5D", +"B. c #595A5A", +"C. c #575656", +"D. c #545555", +"E. c #4F4E4E", +"F. c #4E4E4D", +"G. c #4C4D4C", +"H. c #4C4B4C", +"I. c #4A4A4A", +"J. c #494A4A", +"K. c #494848", +"L. c #484847", +"M. c #474747", +"N. c #474646", +"O. c #454545", +"P. c #444444", +"Q. c #434343", +"R. c #434243", +"S. c #6D6D6D", +"T. c #A7A8A7", +"U. c #D0D0D0", +"V. c #D4D4D4", +"W. c #D6D5D5", +"X. c #E7E8E8", +"Y. c #59595A", +"Z. c #535454", +"`. c #515151", +" + c #4D4D4C", +".+ c #464647", +"++ c #464545", +"@+ c #444545", +"#+ c #424242", +"$+ c #414141", +"%+ c #404041", +"&+ c #3F4040", +"*+ c #787878", +"=+ c #969696", +"-+ c #A7A7A7", +";+ c #C3C3C2", +">+ c #D5D4D5", +",+ c #D4D4D5", +"'+ c #D3D4D4", +")+ c #D3D3D3", +"!+ c #D2D3D3", +"~+ c #E6E7E6", +"{+ c #5A5A5B", +"]+ c #575858", +"^+ c #575657", +"/+ c #555656", +"(+ c #565555", +"_+ c #525352", +":+ c #515051", +"<+ c #4D4D4E", +"[+ c #4D4C4C", +"}+ c #4A4A49", +"|+ c #474848", +"1+ c #464747", +"2+ c #444544", +"3+ c #434342", +"4+ c #434142", +"5+ c #404141", +"6+ c #403F3F", +"7+ c #3F3E3E", +"8+ c #3E3E3E", +"9+ c #3D3D3D", +"0+ c #3C3C3C", +"a+ c #404040", +"b+ c #707071", +"c+ c #A4A5A5", +"d+ c #D4D3D3", +"e+ c #D3D2D2", +"f+ c #D2D2D2", +"g+ c #D2D2D1", +"h+ c #D1D0D0", +"i+ c #D0D1D0", +"j+ c #CFD0CF", +"k+ c #525353", +"l+ c #525152", +"m+ c #504F4F", +"n+ c #4B4A4A", +"o+ c #484848", +"p+ c #464646", +"q+ c #454544", +"r+ c #454444", +"s+ c #424343", +"t+ c #414142", +"u+ c #403F40", +"v+ c #3F3F3F", +"w+ c #3C3D3C", +"x+ c #3B3B3B", +"y+ c #3A3A3A", +"z+ c #3A3A39", +"A+ c #383838", +"B+ c #373737", +"C+ c #474847", +"D+ c #7F7F7F", +"E+ c #B6B6B6", +"F+ c #C8C9C8", +"G+ c #CBCBCB", +"H+ c #CFD0D0", +"I+ c #D0D0CF", +"J+ c #D0CFD0", +"K+ c #CFCFCF", +"L+ c #CECECE", +"M+ c #CECDCE", +"N+ c #545453", +"O+ c #525151", +"P+ c #4F4E4F", +"Q+ c #4A4B4B", +"R+ c #4A494A", +"S+ c #474647", +"T+ c #454645", +"U+ c #404140", +"V+ c #3E3E3F", +"W+ c #3D3E3E", +"X+ c #3D3C3C", +"Y+ c #3C3B3C", +"Z+ c #3C3B3B", +"`+ c #3A3939", +" @ c #383839", +".@ c #363637", +"+@ c #353636", +"@@ c #353535", +"#@ c #343434", +"$@ c #333333", +"%@ c #7B7B7C", +"&@ c #919190", +"*@ c #ACACAB", +"=@ c #C9C9C9", +"-@ c #CECFCE", +";@ c #CECECD", +">@ c #CDCDCD", +",@ c #CDCDCC", +"'@ c #CCCCCC", +")@ c #CCCCCB", +"!@ c #858585", +"~@ c #E6E5E6", +"{@ c #585859", +"]@ c #565655", +"^@ c #545354", +"/@ c #4E4F4E", +"(@ c #4C4C4D", +"_@ c #4B4B4A", +":@ c #484748", +"<@ c #434344", +"[@ c #3D3C3D", +"}@ c #393839", +"|@ c #373636", +"1@ c #333334", +"2@ c #323332", +"3@ c #323232", +"4@ c #313131", +"5@ c #303131", +"6@ c #383939", +"7@ c #50504F", +"8@ c #7E7F7E", +"9@ c #B6B7B6", +"0@ c #CBCBCC", +"a@ c #CBCBCA", +"b@ c #CACACA", +"c@ c #CAC9CA", +"d@ c #575857", +"e@ c #515150", +"f@ c #4A4A4B", +"g@ c #494849", +"h@ c #474746", +"i@ c #464547", +"j@ c #434444", +"k@ c #424141", +"l@ c #3D3D3E", +"m@ c #3B3C3B", +"n@ c #3B3B3A", +"o@ c #383737", +"p@ c #363737", +"q@ c #363636", +"r@ c #353635", +"s@ c #343433", +"t@ c #333233", +"u@ c #313132", +"v@ c #323131", +"w@ c #303030", +"x@ c #2F2F2F", +"y@ c #2F2F2E", +"z@ c #2E2E2F", +"A@ c #2D2C2D", +"B@ c #2C2D2D", +"C@ c #2C2C2C", +"D@ c #2C2B2C", +"E@ c #939393", +"F@ c #B9BAB9", +"G@ c #C0C0C0", +"H@ c #C7C6C7", +"I@ c #CACAC9", +"J@ c #C9C9C8", +"K@ c #C8C8C9", +"L@ c #C8C8C8", +"M@ c #585758", +"N@ c #535152", +"O@ c #504F50", +"P@ c #4B4C4A", +"Q@ c #494948", +"R@ c #454646", +"S@ c #434443", +"T@ c #414241", +"U@ c #3F3F40", +"V@ c #3F3E3F", +"W@ c #3E3E3D", +"X@ c #3D3C3E", +"Y@ c #393939", +"Z@ c #373838", +"`@ c #363535", +" # c #343334", +".# c #313232", +"+# c #2E2E2E", +"@# c #2D2D2D", +"## c #2C2B2B", +"$# c #2B2B2B", +"%# c #2A2A2A", +"&# c #29292A", +"*# c #292929", +"=# c #282828", +"-# c #383938", +";# c #5D5E5D", +"># c #7A797A", +",# c #919191", +"'# c #B3B2B3", +")# c #C8C7C8", +"!# c #C8C7C7", +"~# c #C8C8C7", +"{# c #C7C7C6", +"]# c #C6C6C7", +"^# c #C6C6C5", +"/# c #9D9D9D", +"(# c #E4E4E5", +"_# c #4A4B4A", +":# c #484949", +"<# c #474748", +"[# c #444443", +"}# c #424241", +"|# c #3C3D3D", +"1# c #3B3A3B", +"2# c #383837", +"3# c #353434", +"4# c #333434", +"5# c #313031", +"6# c #302F2F", +"7# c #2D2D2E", +"8# c #2A2B2B", +"9# c #292A2A", +"0# c #292828", +"a# c #282928", +"b# c #272727", +"c# c #262626", +"d# c #242524", +"e# c #C6C6C6", +"f# c #C5C5C5", +"g# c #C5C5C6", +"h# c #424243", +"i# c #3B3A3A", +"j# c #383738", +"k# c #343534", +"l# c #343333", +"m# c #313130", +"n# c #302F30", +"o# c #2D2C2C", +"p# c #2C2C2D", +"q# c #272626", +"r# c #252625", +"s# c #262525", +"t# c #242424", +"u# c #232423", +"v# c #222223", +"w# c #222222", +"x# c #212121", +"y# c #1F1F20", +"z# c #30302F", +"A# c #6A696A", +"B# c #A0A09F", +"C# c #C5C6C5", +"D# c #E3E4E4", +"E# c #555655", +"F# c #535352", +"G# c #4E4D4D", +"H# c #424142", +"I# c #414040", +"J# c #3F403F", +"K# c #3C3C3D", +"L# c #39393A", +"M# c #383637", +"N# c #323233", +"O# c #323132", +"P# c #303031", +"Q# c #2F2E2E", +"R# c #2E2E2D", +"S# c #2B2C2C", +"T# c #2B2A2A", +"U# c #272627", +"V# c #252525", +"W# c #242423", +"X# c #232222", +"Y# c #212221", +"Z# c #202021", +"`# c #202020", +" $ c #1F1F1F", +".$ c #1E1E1F", +"+$ c #1E1D1D", +"@$ c #1D1C1D", +"#$ c #C4C5C5", +"$$ c #C4C4C4", +"%$ c #525253", +"&$ c #515252", +"*$ c #4E4E4F", +"=$ c #4D4C4D", +"-$ c #4B4A4B", +";$ c #414041", +">$ c #3C3C3B", +",$ c #393938", +"'$ c #363536", +")$ c #353435", +"!$ c #333433", +"~$ c #2B2A2B", +"{$ c #2A2B2A", +"]$ c #292829", +"^$ c #262627", +"/$ c #252624", +"($ c #252424", +"_$ c #222322", +":$ c #20201F", +"<$ c #1E1F1E", +"[$ c #1D1D1D", +"}$ c #1C1D1D", +"|$ c #1C1C1C", +"1$ c #C4C5C4", +"2$ c #4F4F4E", +"3$ c #444344", +"4$ c #3E3F3E", +"5$ c #3E3D3E", +"6$ c #393A39", +"7$ c #393838", +"8$ c #363736", +"9$ c #2F302F", +"0$ c #2D2E2D", +"a$ c #2E2D2E", +"b$ c #2D2D2C", +"c$ c #2B2B2C", +"d$ c #2B2B2A", +"e$ c #262526", +"f$ c #242324", +"g$ c #232324", +"h$ c #212222", +"i$ c #202121", +"j$ c #1F2020", +"k$ c #1F1F1E", +"l$ c #1D1C1C", +"m$ c #1B1B1C", +"n$ c #C4C4C3", +"o$ c #E3E2E3", +"p$ c #555455", +"q$ c #515251", +"r$ c #4B4C4C", +"s$ c #3D3E3D", +"t$ c #3B3D3C", +"u$ c #3A3A3B", +"v$ c #373837", +"w$ c #373637", +"x$ c #2F2E2F", +"y$ c #232323", +"z$ c #1E1E1D", +"A$ c #1B1C1C", +"B$ c #1C1B1B", +"C$ c #1B1B1B", +"D$ c #C3C4C4", +"E$ c #C3C3C3", +"F$ c #464546", +"G$ c #3E3F3F", +"H$ c #3E3D3D", +"I$ c #3D3D3C", +"J$ c #3A3B3B", +"K$ c #323333", +"L$ c #313030", +"M$ c #2F3030", +"N$ c #2E2F2F", +"O$ c #2D2D2B", +"P$ c #2A2B29", +"Q$ c #292A29", +"R$ c #282726", +"S$ c #202120", +"T$ c #1E1E1E", +"U$ c #19191A", +"V$ c #C3C3C4", +"W$ c #E2E1E1", +"X$ c #4A4949", +"Y$ c #484849", +"Z$ c #3A3B3A", +"`$ c #373738", +" % c #373736", +".% c #252425", +"+% c #222122", +"@% c #212122", +"#% c #1A1B1B", +"$% c #1B1A1A", +"%% c #1A1919", +"&% c #E2E1E2", +"*% c #E1E0E1", +"=% c #505051", +"-% c #49494A", +";% c #1A1A1A", +">% c #3A393A", +",% c #2E2F2E", +"'% c #282727", +")% c #242425", +"!% c #232322", +"~% c #1E1F1F", +"{% c #1B1C1B", +"]% c #1A191A", +"^% c #191A19", +"/% c #191918", +"(% c #C2C2C2", +"_% c #E0E1E1", +":% c #E1E1E0", +"<% c #4B4B4C", +"[% c #454445", +"}% c #161515", +"|% c #8B8B8B", +"1% c #2C2C2B", +"2% c #282827", +"3% c #272728", +"4% c #262727", +"5% c #1F1E1F", +"6% c #1A1A19", +"7% c #181818", +"8% c #C1C1C2", +"9% c #E1E0E0", +"0% c #464746", +"a% c #111111", +"b% c #7C7C7C", +"c% c #BBBBBB", +"d% c #969697", +"e% c #5F5F5C", +"f% c #33332F", +"g% c #28292A", +"h% c #262726", +"i% c #201F20", +"j% c #1F201F", +"k% c #191919", +"l% c #171717", +"m% c #4C4C4B", +"n% c #444445", +"o% c #444343", +"p% c #1A1717", +"q% c #211515", +"r% c #2D2B2B", +"s% c #999999", +"t% c #B3B3B5", +"u% c #8B8BB2", +"v% c #6F6F89", +"w% c #4A4A4F", +"x% c #2A2929", +"y% c #2B2C2B", +"z% c #2A292A", +"A% c #232424", +"B% c #212120", +"C% c #181718", +"D% c #171818", +"E% c #171716", +"F% c #C1C1C1", +"G% c #C0C1C1", +"H% c #DFE0E0", +"I% c #484948", +"J% c #422121", +"K% c #552D2D", +"L% c #363232", +"M% c #A0A0A0", +"N% c #646464", +"O% c #ABABAE", +"P% c #7575C7", +"Q% c #5C5CD5", +"R% c #7878BD", +"S% c #7B7B8E", +"T% c #585855", +"U% c #30302E", +"V% c #2A2A29", +"W% c #212020", +"X% c #201E1F", +"Y% c #1E1D1E", +"Z% c #1C1C1D", +"`% c #1A1B1A", +" & c #191A1A", +".& c #171616", +"+& c #161616", +"@& c #C0C0C1", +"#& c #414242", +"$& c #1F1C1C", +"%& c #542424", +"&& c #4C2625", +"*& c #585756", +"=& c #A8A8A8", +"-& c #767677", +";& c #9D9D9E", +">& c #8A8AAD", +",& c #5A5AC4", +"'& c #3838D7", +")& c #3434D9", +"!& c #4848BD", +"~& c #535372", +"{& c #878888", +"]& c #A4A4A4", +"^& c #A7A6A6", +"/& c #B0B0B0", +"(& c #B1B1B1", +"_& c #A1A1A1", +":& c #808080", +"<& c #151515", +"[& c #242525", +"}& c #1D1E1E", +"|& c #1A1A1B", +"1& c #191819", +"2& c #181817", +"3& c #161717", +"4& c #151516", +"5& c #C1C0C0", +"6& c #DFDEDE", +"7& c #5B2020", +"8& c #391A19", +"9& c #A4A4A5", +"0& c #878687", +"a& c #8E8E8E", +"b& c #9B9B98", +"c& c #999994", +"d& c #888898", +"e& c #6C6BA8", +"f& c #4F4FBD", +"g& c #50508B", +"h& c #CECDCD", +"i& c #6A6A6A", +"j& c #242323", +"k& c #222121", +"l& c #1F1E1E", +"m& c #1C1D1C", +"n& c #151514", +"o& c #BFC0BF", +"p& c #DFDFDE", +"q& c #434445", +"r& c #3F3E40", +"s& c #1B1212", +"t& c #611717", +"u& c #301414", +"v& c #797878", +"w& c #9C9C9D", +"x& c #888888", +"y& c #8A8A89", +"z& c #868688", +"A& c #7C7C8F", +"B& c #45455C", +"C& c #B8B8B8", +"D& c #C5C4C4", +"E& c #AAA9A9", +"F& c #252523", +"G& c #222323", +"H& c #171817", +"I& c #161516", +"J& c #141514", +"K& c #141313", +"L& c #C0BFBF", +"M& c #4D4E4E", +"N& c #464645", +"O& c #1B0F0F", +"P& c #570D0D", +"Q& c #270D0D", +"R& c #706F6F", +"S& c #838383", +"T& c #757474", +"U& c #878787", +"V& c #6F6F6F", +"W& c #5C5C5A", +"X& c #353533", +"Y& c #656565", +"Z& c #BCBCBC", +"`& c #BFBFBF", +" * c #C1C2C1", +".* c #696969", +"+* c #1D1D1E", +"@* c #191818", +"#* c #131313", +"$* c #DDDEDD", +"%* c #110F0F", +"&* c #220B0B", +"** c #201B1B", +"=* c #7D7D7C", +"-* c #727272", +";* c #898989", +">* c #BBBBBA", +",* c #BCBCBB", +"'* c #BDBDBD", +")* c #676868", +"!* c #7A7A7A", +"~* c #1D1D1C", +"{* c #181918", +"]* c #141414", +"^* c #131314", +"/* c #131312", +"(* c #BEBFBF", +"_* c #454546", +":* c #3B3B3C", +"<* c #181919", +"[* c #818181", +"}* c #656465", +"|* c #888787", +"1* c #9B9B9B", +"2* c #ADADAD", +"3* c #B4B4B4", +"4* c #B5B5B5", +"5* c #B5B5B4", +"6* c #B6B6B5", +"7* c #B6B6B7", +"8* c #B7B7B7", +"9* c #B7B8B8", +"0* c #767676", +"a* c #121213", +"b* c #212021", +"c* c #141413", +"d* c #111212", +"e* c #9A9A9A", +"f* c #515152", +"g* c #616162", +"h* c #949495", +"i* c #A6A6A6", +"j* c #AFAFAF", +"k* c #ACADAD", +"l* c #B2B2B2", +"m* c #B0B0AF", +"n* c #AFAFB0", +"o* c #B3B3B3", +"p* c #B5B4B4", +"q* c #1C1B1C", +"r* c #131414", +"s* c #121313", +"t* c #121212", +"u* c #BEBDBD", +"v* c #DCDCDD", +"w* c #6E6E6E", +"x* c #A5A5A5", +"y* c #A9A9A9", +"z* c #ABABAA", +"A* c #AAAAA9", +"B* c #ABA9A9", +"C* c #ABAAAB", +"D* c #ABABAC", +"E* c #ACACAC", +"F* c #666766", +"G* c #141314", +"H* c #1D1E1D", +"I* c #1B1A1B", +"J* c #131213", +"K* c #101111", +"L* c #586362", +"M* c #5D6F74", +"N* c #596767", +"O* c #555A58", +"P* c #A2A2A3", +"Q* c #A2A2A2", +"R* c #A3A3A3", +"S* c #A5A5A3", +"T* c #A6A7A7", +"U* c #A5A4A5", +"V* c #A8A7A7", +"W* c #A9A8A9", +"X* c #9C9C9C", +"Y* c #424342", +"Z* c #6C6D6C", +"`* c #101010", +" = c #151616", +".= c #131412", +"+= c #101110", +"@= c #0F0F0F", +"#= c #BDBCBD", +"$= c #DBDCDC", +"%= c #7FA3AE", +"&= c #79A5EC", +"*= c #5F80EB", +"== c #485FD4", +"-= c #4758B4", +";= c #516392", +">= c #586874", +",= c #55605F", +"'= c #393A3A", +")= c #2D2E2F", +"!= c #9E9E9E", +"~= c #979897", +"{= c #9A9B9B", +"]= c #929493", +"^= c #8C8D8D", +"/= c #979797", +"(= c #989999", +"_= c #969898", +":= c #979898", +"<= c #9B9C9C", +"[= c #A2A1A2", +"}= c #737272", +"|= c #A6A5A6", +"1= c #616161", +"2= c #1B1B1A", +"3= c #181717", +"4= c #161615", +"5= c #151414", +"6= c #121112", +"7= c #111110", +"8= c #7A9DAE", +"9= c #597AF5", +"0= c #5373F9", +"a= c #668CFC", +"b= c #5D80FC", +"c= c #5271FB", +"d= c #5576F5", +"e= c #739AE6", +"f= c #7495A5", +"g= c #607578", +"h= c #54646B", +"i= c #58686B", +"j= c #505A59", +"k= c #484B4B", +"l= c #323432", +"m= c #919292", +"n= c #959494", +"o= c #878686", +"p= c #7A7979", +"q= c #7C7777", +"r= c #807778", +"s= c #776F6F", +"t= c #706565", +"u= c #7B6C6B", +"v= c #847171", +"w= c #7C6B6B", +"x= c #746464", +"y= c #736262", +"z= c #7A6969", +"A= c #807070", +"B= c #807676", +"C= c #807C7C", +"D= c #949696", +"E= c #9E9F9F", +"F= c #757575", +"G= c #171617", +"H= c #151615", +"I= c #141415", +"J= c #121111", +"K= c #0F1010", +"L= c #0F0F10", +"M= c #0E0F0E", +"N= c #BDBDBC", +"O= c #5B6766", +"P= c #799CA3", +"Q= c #76979D", +"R= c #6F8D9F", +"S= c #97CEEF", +"T= c #76A2FB", +"U= c #4C69FC", +"V= c #1B27FD", +"W= c #3549F4", +"X= c #5979E3", +"Y= c #698DE4", +"Z= c #77A2F2", +"`= c #688EE1", +" - c #5C78C4", +".- c #576FA2", +"+- c #55697C", +"@- c #4D5C5F", +"#- c #333E39", +"$- c #3D3B37", +"%- c #6F6766", +"&- c #786868", +"*- c #7D6666", +"=- c #947676", +"-- c #9C7979", +";- c #9D7676", +">- c #AB7E7E", +",- c #BA8888", +"'- c #B88585", +")- c #B17E7E", +"!- c #B57E7E", +"~- c #BD8383", +"{- c #BD8181", +"]- c #B07777", +"^- c #A06A6A", +"/- c #956161", +"(- c #8A5B5B", +"_- c #7D5858", +":- c #755F5F", +"<- c #807878", +"[- c #7D7D7D", +"}- c #797979", +"|- c #131212", +"1- c #0F0F0E", +"2- c #0D0E0E", +"3- c #BCBBBC", +"4- c #DBDADB", +"5- c #424545", +"6- c #4F5756", +"7- c #9BD0D5", +"8- c #6D96FC", +"9- c #435DFC", +"0- c #3E55FC", +"a- c #5270FC", +"b- c #5878F8", +"c- c #4862F2", +"d- c #435DF8", +"e- c #4D6BF8", +"f- c #597BFC", +"g- c #5B7DFB", +"h- c #5E81FB", +"i- c #678DEF", +"j- c #7198D3", +"k- c #354658", +"l- c #5B4442", +"m- c #B6817F", +"n- c #C68B8B", +"o- c #C38787", +"p- c #C78888", +"q- c #CE8C8C", +"r- c #CA8686", +"s- c #C68181", +"t- c #C78080", +"u- c #C87F7F", +"v- c #C57B7B", +"w- c #C37777", +"x- c #C07373", +"y- c #C17271", +"z- c #C17070", +"A- c #BF6B6B", +"B- c #BB6767", +"C- c #B15F5F", +"D- c #9E5453", +"E- c #744343", +"F- c #302929", +"G- c #161617", +"H- c #141515", +"I- c #131413", +"J- c #100F10", +"K- c #0F0E0E", +"L- c #0E0E0E", +"M- c #0D0D0D", +"N- c #BBBCBB", +"O- c #DAD9DA", +"P- c #40403F", +"Q- c #739297", +"R- c #78A2E4", +"S- c #7AA6E2", +"T- c #86B1C5", +"U- c #6A879E", +"V- c #6A879A", +"W- c #708F95", +"X- c #7C9FA0", +"Y- c #5F7788", +"Z- c #576C96", +"`- c #5974B8", +" ; c #5774D8", +".; c #4B67F1", +"+; c #4661FD", +"@; c #3549D3", +"#; c #2F236D", +"$; c #A86F81", +"%; c #C17777", +"&; c #C27472", +"*; c #C17272", +"=; c #BE6F6F", +"-; c #BC6C6C", +";; c #BC6969", +">; c #BA6766", +",; c #B96363", +"'; c #B86060", +"); c #B75D5D", +"!; c #B55B5B", +"~; c #B35757", +"{; c #B25554", +"]; c #B15251", +"^; c #B04F4F", +"/; c #AF4C4C", +"(; c #AF4A49", +"_; c #763030", +":; c #291313", +"<; c #0C0C0C", +"[; c #BBBBBC", +"}; c #434241", +"|; c #49504F", +"1; c #697F7E", +"2; c #607270", +"3; c #464C4B", +"4; c #454748", +"5; c #3B3D3D", +"6; c #454848", +"7; c #4D5353", +"8; c #637D7F", +"9; c #7BA3C0", +"0; c #688EE9", +"a; c #364CD9", +"b; c #564EC6", +"c; c #8F639C", +"d; c #B06D77", +"e; c #B75A55", +"f; c #B55753", +"g; c #B25352", +"h; c #B15050", +"i; c #B04E4D", +"j; c #AE4A4A", +"k; c #AD4747", +"l; c #AC4444", +"m; c #AA4242", +"n; c #A93F3F", +"o; c #A83C3C", +"p; c #A63939", +"q; c #A53636", +"r; c #A43333", +"s; c #8F2C2C", +"t; c #451616", +"u; c #541A1A", +"v; c #663B3B", +"w; c #848383", +"x; c #1C1A1C", +"y; c #0E0F0F", +"z; c #0E0D0D", +"A; c #0D0D0C", +"B; c #BBBABB", +"C; c #BABBBA", +"D; c #D9DAD9", +"E; c #3E4645", +"F; c #5A6F74", +"G; c #7094BE", +"H; c #5A7EF1", +"I; c #3F52F7", +"J; c #4A49DD", +"K; c #6E3D9B", +"L; c #914B73", +"M; c #A13B45", +"N; c #A73735", +"O; c #A6332F", +"P; c #A42F2C", +"Q; c #A22C2B", +"R; c #A02B2C", +"S; c #9F2929", +"T; c #9E2626", +"U; c #9D2323", +"V; c #9B2020", +"W; c #9A1E1D", +"X; c #951919", +"Y; c #581010", +"Z; c #3B0909", +"`; c #7E1C1C", +" > c #671B1B", +".> c #2F2929", +"+> c #101011", +"@> c #0B0B0B", +"#> c #D8D9D8", +"$> c #3B3C3C", +"%> c #353534", +"&> c #353334", +"*> c #454949", +"=> c #6B8382", +"-> c #779FB5", +";> c #76A2EF", +">> c #5B72EE", +",> c #555CDE", +"'> c #623AA0", +")> c #762969", +"!> c #872F51", +"~> c #922C3C", +"{> c #952129", +"]> c #941619", +"^> c #950D0B", +"/> c #960B07", +"(> c #950B06", +"_> c #930907", +":> c #8F0707", +"<> c #680504", +"[> c #350200", +"}> c #4D0301", +"|> c #680D0E", +"1> c #391213", +"2> c #252E29", +"3> c #242B25", +"4> c #252A26", +"5> c #151415", +"6> c #121312", +"7> c #111211", +"8> c #10100F", +"9> c #0E0E0F", +"0> c #0D0C0D", +"a> c #0C0C0B", +"b> c #0A0A0B", +"c> c #B9BABA", +"d> c #2F2F30", +"e> c #313333", +"f> c #51656B", +"g> c #587293", +"h> c #5574C3", +"i> c #5170F4", +"j> c #4658F3", +"k> c #4A4BDB", +"l> c #5943B8", +"m> c #6B3E8F", +"n> c #793468", +"o> c #7F264C", +"p> c #7E1435", +"q> c #7E0320", +"r> c #82051B", +"s> c #70030D", +"t> c #2B0003", +"u> c #170002", +"v> c #3A0B12", +"w> c #35272C", +"x> c #3F5785", +"y> c #455FC7", +"z> c #4961B0", +"A> c #495E89", +"B> c #445664", +"C> c #3C4A49", +"D> c #0A0B0B", +"E> c #0A0A09", +"F> c #BAB9BA", +"G> c #2D2E2E", +"H> c #2E3030", +"I> c #323231", +"J> c #464C4C", +"K> c #6B8887", +"L> c #6C8FA1", +"M> c #6183BB", +"N> c #5071D2", +"O> c #4463E8", +"P> c #3E55F8", +"Q> c #414EED", +"R> c #4B45CF", +"S> c #5131AA", +"T> c #502EA3", +"U> c #2E1FA3", +"V> c #09089D", +"W> c #0A0B8D", +"X> c #202788", +"Y> c #5476B4", +"Z> c #7BAAF4", +"`> c #5879FB", +" , c #5D7FFD", +"., c #5C7FFB", +"+, c #658AF7", +"@, c #749FE8", +"#, c #6383A7", +"$, c #4B616A", +"%, c #394443", +"&, c #1C1F1F", +"*, c #100F0F", +"=, c #0B0B0C", +"-, c #0B0B0A", +";, c #0A0A0A", +">, c #090909", +",, c #B9B9B9", +"', c #333332", +"), c #303130", +"!, c #2E2D2D", +"~, c #2A2A2B", +"{, c #2B2D2D", +"], c #363F40", +"^, c #445358", +"/, c #526873", +"(, c #5C778D", +"_, c #607FA4", +":, c #5D7FBE", +"<, c #597ED6", +"[, c #577BE9", +"}, c #3E56B9", +"|, c #5E81D3", +"1, c #5574D4", +"2, c #425AD8", +"3, c #425BF1", +"4, c #3C54FB", +"5, c #3B52FC", +"6, c #4660FC", +"7, c #5574FC", +"8, c #5473FC", +"9, c #455FFC", +"0, c #4059F5", +"a, c #516EE2", +"b, c #6A91CA", +"c, c #587480", +"d, c #2E3636", +"e, c #0D0C0C", +"f, c #0C0B0C", +"g, c #0A090A", +"h, c #B8B9B8", +"i, c #D8D7D7", +"j, c #D7D7D8", +"k, c #333232", +"l, c #282B2C", +"m, c #363F41", +"n, c #4B5B5B", +"o, c #5B6F6D", +"p, c #3C4747", +"q, c #404D54", +"r, c #465861", +"s, c #495C67", +"t, c #577285", +"u, c #5E7EA0", +"v, c #5B7ABA", +"w, c #6084ED", +"x, c #5677FB", +"y, c #6388FC", +"z, c #82B3FB", +"A, c #86B8FB", +"B, c #5575FB", +"C, c #354AFC", +"D, c #4F6EF8", +"E, c #719BD3", +"F, c #62838E", +"G, c #4B6466", +"H, c #32403F", +"I, c #171919", +"J, c #0A0A0C", +"K, c #080908", +"L, c #070708", +"M, c #B9B8B9", +"N, c #B9B9B8", +"O, c #383937", +"P, c #2C2D2C", +"Q, c #252626", +"R, c #272C30", +"S, c #4E6676", +"T, c #5C7CB0", +"U, c #5A7CEB", +"V, c #4159FC", +"W, c #435CFC", +"X, c #374CFC", +"Y, c #3347FC", +"Z, c #1C27FD", +"`, c #222FFD", +" ' c #4864F7", +".' c #5C7EE9", +"+' c #7098D4", +"@' c #5A798B", +"#' c #394948", +"$' c #252A2A", +"%' c #0B0A0B", +"&' c #0B0A09", +"*' c #090808", +"=' c #070808", +"-' c #070707", +";' c #B8B7B8", +">' c #D6D7D7", +",' c #D7D6D7", +"'' c #343435", +")' c #2D2D2F", +"!' c #282929", +"~' c #2C2F2E", +"{' c #576E6D", +"]' c #6B90A6", +"^' c #658AE8", +"/' c #3245FD", +"(' c #3F56FC", +"_' c #84B6FB", +":' c #76A1DB", +"<' c #5370C0", +"[' c #4A65D9", +"}' c #455FF7", +"|' c #4661FA", +"1' c #5D7FE7", +"2' c #6D94B7", +"3' c #3C4D4D", +"4' c #0B0C0C", +"5' c #080809", +"6' c #060606", +"7' c #B7B8B7", +"8' c #D7D6D6", +"9' c #3F3F3E", +"0' c #363635", +"a' c #282829", +"b' c #1A1C1C", +"c' c #495F68", +"d' c #6B92CC", +"e' c #5474FC", +"f' c #75A0FB", +"g' c #769FA3", +"h' c #283137", +"i' c #364651", +"j' c #5B7A97", +"k' c #6C93DA", +"l' c #5979FB", +"m' c #4D6AFC", +"n' c #6283CF", +"o' c #4D676B", +"p' c #0D0D0E", +"q' c #0A0909", +"r' c #080808", +"s' c #070706", +"t' c #060605", +"u' c #D6D5D6", +"v' c #606061", +"w' c #272726", +"x' c #232223", +"y' c #212220", +"z' c #1C1C1B", +"A' c #3E4C4A", +"B' c #77A2C3", +"C' c #82B1EC", +"D' c #6A8F90", +"E' c #2B3332", +"F' c #55727E", +"G' c #6D95E0", +"H' c #658AFB", +"I' c #8EC3D8", +"J' c #283432", +"K' c #050505", +"L' c #B8B7B7", +"M' c #D6D6D5", +"N' c #C5C5C4", +"O' c #848484", +"P' c #252526", +"Q' c #181819", +"R' c #353E3D", +"S' c #4F6664", +"T' c #313D3D", +"U' c #111010", +"V' c #3F5255", +"W' c #53718E", +"X' c #688C93", +"Y' c #1D2425", +"Z' c #080707", +"`' c #050606", +" ) c #050406", +".) c #040404", +"+) c #B7B7B6", +"@) c #D3D3D2", +"#) c #292928", +"$) c #111312", +"%) c #0B0A0A", +"&) c #080807", +"*) c #080607", +"=) c #060505", +"-) c #050504", +";) c #D1D1D2", +">) c #858484", +",) c #272827", +"') c #0F100F", +")) c #0E0D0E", +"!) c #0C0D0C", +"~) c #080A09", +"{) c #090809", +"]) c #060707", +"^) c #060506", +"/) c #040505", +"() c #030303", +"_) c #B6B5B5", +":) c #CFCECF", +"<) c #CFCECE", +"[) c #BDBEBE", +"}) c #0E0D0F", +"|) c #0C0D0D", +"1) c #0C0B0B", +"2) c #0A0B0A", +"3) c #090A0A", +"4) c #070807", +"5) c #050506", +"6) c #040303", +"7) c #030403", +"8) c #020202", +"9) c #CFCFCE", +"0) c #CDCCCC", +"a) c #828282", +"b) c #252524", +"c) c #121011", +"d) c #0C0C0D", +"e) c #060706", +"f) c #020203", +"g) c #010202", +"h) c #B4B4B5", +"i) c #555554", +"j) c #CCCCCD", +"k) c #CBCCCB", +"l) c #CACBCA", +"m) c #0E0E0D", +"n) c #030404", +"o) c #010101", +"p) c #B5B4B5", +"q) c #B4B5B4", +"r) c #C9CACA", +"s) c #C8C9C9", +"t) c #C9C8C9", +"u) c #777877", +"v) c #121311", +"w) c #050405", +"x) c #040403", +"y) c #020201", +"z) c #000000", +"A) c #4F504E", +"B) c #C9C8C8", +"C) c #C7C7C8", +"D) c #C6C7C6", +"E) c #60605F", +"F) c #050404", +"G) c #000001", +"H) c #B3B4B4", +"I) c #C7C6C6", +"J) c #C5C6C6", +"K) c #C6C5C6", +"L) c #B2B3B3", +"M) c #949494", +"N) c #7E7E7E", +"O) c #171718", +"P) c #0D0E0D", +"Q) c #09090A", +"R) c #080909", +"S) c #070607", +"T) c #060504", +"U) c #020303", +"V) c #B3B3B4", +"W) c #666666", +"X) c #9F9F9F", +"Y) c #C4C3C4", +"Z) c #C2C2C3", +"`) c #C0C0BF", +" ! c #BCBBBB", +".! c #909191", +"+! c #141516", +"@! c #121211", +"#! c #0F0E0F", +"$! c #090908", +"%! c #070606", +"&! c #050605", +"*! c #020101", +"=! c #B2B3B2", +"-! c #4D4E4D", +";! c #929292", +">! c #C2C3C2", +",! c #C1C2C2", +"'! c #C2C1C2", +")! c #0B0C0B", +"!! c #030202", +"~! c #000100", +"{! c #B3B2B2", +"]! c #4B4C4B", +"^! c #464745", +"/! c #AFB0AF", +"(! c #ADAEAE", +"_! c #ABAAAA", +":! c #BFBFBE", +"~ c #565756", +",~ c #989998", +"'~ c #A0A1A0", +")~ c #A4A3A4", +"!~ c #B0B1B1", +"~~ c #B1B0B1", +"{~ c #B6B7B7", +"]~ c #787877", +"^~ c #757676", +"/~ c #747474", +"(~ c #8C8D8C", +"_~ c #9D9C9D", +":~ c #A8A8A7", +"<~ c #545353", +"[~ c #989797", +"}~ c #9F9F9E", +"|~ c #A0A1A1", +"1~ c #8C8C8B", +"2~ c #706F70", +"3~ c #B1B1B0", +"4~ c #B4B5B5", +"5~ c #777677", +"6~ c #727172", +"7~ c #6B6C6C", +"8~ c #80807F", +"9~ c #919090", +"0~ c #9E9E9F", +"a~ c #A4A5A4", +"b~ c #A6A7A6", +"c~ c #898888", +"d~ c #6E6E6D", +"e~ c #5F5F60", +"f~ c #797A7A", +"g~ c #7E7F7F", +"h~ c #777777", +"i~ c #616060", +"j~ c #626263", +"k~ c #767777", +"l~ c #767675", +"m~ c #717171", +"n~ c #6E6E6F", +"o~ c #6C6D6D", +"p~ c #6A6969", +"q~ c #676767", +"r~ c #656665", +"s~ c #676766", +"t~ c #727373", +"u~ c #5C5C5B", +"v~ c #6A6A6B", +"w~ c #7B7A7B", +"x~ c #626262", +"y~ c #6B6A6B", +"z~ c #6C6B6B", +"A~ c #B1B1B2", +"B~ c #777676", +"C~ c #747575", +"D~ c #717271", +"E~ c #6D6E6D", +"F~ c #6B6B6A", +"G~ c #686767", +"H~ c #646363", +"I~ c #5D5D5C", +"J~ c #777776", +"K~ c #878788", +"L~ c #969596", +"M~ c #9A9898", +"N~ c #9A9A99", +"O~ c #646463", +"P~ c #7B7C7C", +"Q~ c #7B7C7B", +"R~ c #707170", +"S~ c #575756", +"T~ c #696968", +"U~ c #B0B0B1", +"V~ c #ABACAB", +"W~ c #787777", +"X~ c #717170", +"Y~ c #696869", +"Z~ c #666565", +"`~ c #646465", +" { c #636363", +".{ c #605F5F", +"+{ c #575758", +"@{ c #8B8A8B", +"#{ c #949393", +"${ c #666566", +"%{ c #A5A4A4", +"&{ c #969797", +"*{ c #787778", +"={ c #636364", +"-{ c #606161", +";{ c #5D5C5C", +">{ c #585958", +",{ c #5C5C5D", +"'{ c #868787", +"){ c #7F807F", +"!{ c #606160", +"~{ c #616261", +"{{ c #656566", +"]{ c #666767", +"^{ c #ADADAC", +"/{ c #A8A9A8", +"({ c #9A9999", +"_{ c #6A6A69", +":{ c #626261", +"<{ c #5F605F", +"[{ c #818081", +"}{ c #868685", +"|{ c #636362", +"1{ c #7C7B7B", +"2{ c #939292", +"3{ c #8A8B8A", +"4{ c #676768", +"5{ c #848485", +"6{ c #818281", +"7{ c #7F7E7E", +"8{ c #7B7B7A", +"9{ c #A5A6A6", +"0{ c #9F9FA0", +"a{ c #8B8C8B", +"b{ c #818180", +"c{ c #7E7D7E", +"d{ c #7C7C7D", +"e{ c #787978", +"f{ c #636463", +"g{ c #5D5D5E", +"h{ c #616160", +"i{ c #626161", +"j{ c #7C7D7C", +"k{ c #9B9A9A", +"l{ c #666667", +"m{ c #818182", +"n{ c #7D7E7D", +"o{ c #757475", +"p{ c #5F6060", +"q{ c #707171", +"r{ c #807F80", +"s{ c #8E8E8F", +"t{ c #979696", +"u{ c #959594", +"v{ c #686869", +"w{ c #7F8080", +"x{ c #7E7E7F", +"y{ c #7C7D7D", +"z{ c #737374", +"A{ c #4C4E4E", +"B{ c #535453", +"C{ c #5B595B", +"D{ c #5F5F5E", +"E{ c #747473", +"F{ c #838384", +"G{ c #908F90", +"H{ c #919192", +"I{ c #7D7C7D", +"J{ c #818282", +"K{ c #808081", +"L{ c #7F7F80", +"M{ c #5B5A5C", +"N{ c #5C5D5D", +"O{ c #828181", +"P{ c #5A595A", +"Q{ c #676667", +"R{ c #8A8A8A", +"S{ c #7A7A7B", +"T{ c #9E9E9D", +"U{ c #838282", +"V{ c #767576", +"W{ c #868585", +"X{ c #797A79", +"Y{ c #737273", +"Z{ c #626363", +"`{ c #F5F5F5", +" ] c #FDFDFD", +".] c #6E6D6D", +"+] c #7F7E7F", +"@] c #989897", +"#] c #9C9D9C", +"$] c #5E5E5F", +"%] c #CACBCB", +"&] c #FFFFFF", +"*] c #9C9B9C", +"=] c #9B9B9A", +"-] c #666665", +";] c #626362", +">] c #838483", +",] c #8D8D8C", +"'] c #959696", +")] c #959795", +"!] c #757574", +"~] c #656666", +"{] c #7D7E7E", +"]] c #737372", +"^] c #6C6C6D", +"/] c #747374", +"(] c #979796", +"_] c #939392", +":] c #7D7D7E", +"<] c #777878", +"[] c #747373", +"}] c #717071", +"|] c #858685", +"1] c #7A7B7B", +"2] c #929393", +"3] c #7C7C7B", +"4] c #F8F8F8", +"5] c #F3F3F3", +"6] c #7A7B7A", +"7] c #929293", +"8] c #898A8A", +"9] c #898988", +"0] c #787879", +"a] c #797978", +"b] c #757675", +"c] c #89898A", +"d] c #848384", +"e] c #808180", +"f] c #757576", +"g] c #747475", +"h] c #C0BFC0", +"i] c #E6FBFA", +"j] c #83EFE8", +"k] c #41E6DC", +"l] c #18DDD1", +"m] c #20DACF", +"n] c #41DBD2", +"o] c #83E5E0", +"p] c #E6F9F8", +"q] c #888788", +"r] c #838382", +"s] c #747576", +"t] c #737473", +"u] c #A4F2EE", +"v] c #20E5DA", +"w] c #19E7DB", +"x] c #18E5D9", +"y] c #18E0D4", +"z] c #18DBD0", +"A] c #18D6CB", +"B] c #19D1C6", +"C] c #21CDC3", +"D] c #A4E8E4", +"E] c #79797A", +"F] c #7A7A79", +"G] c #767776", +"H] c #A4F1EC", +"I] c #18E1D6", +"J] c #18E7DA", +"K] c #18ECDF", +"L] c #18D7CC", +"M] c #18D2C7", +"N] c #18CCC2", +"O] c #18C7BC", +"P] c #A4E6E3", +"Q] c #6B6A6A", +"R] c #747574", +"S] c #E6FAF9", +"T] c #20DCD1", +"U] c #18E4D9", +"V] c #18E6DB", +"W] c #18DCD0", +"X] c #18D7CB", +"Y] c #19CCC2", +"Z] c #18C7BD", +"`] c #20C3BA", +" ^ c #E6F7F6", +".^ c #84E8E2", +"+^ c #19D9CE", +"@^ c #19E0D5", +"#^ c #18E1D5", +"$^ c #17DED1", +"%^ c #119D95", +"&^ c #119A93", +"*^ c #17D2C6", +"=^ c #18D0C5", +"-^ c #18CBC0", +";^ c #18C6BC", +">^ c #19C0B6", +",^ c #84DAD5", +"'^ c #41DAD0", +")^ c #19D5CA", +"!^ c #18D9CD", +"~^ c #17D9CE", +"{^ c #010F0E", +"]^ c #010E0D", +"^^ c #18CBBF", +"/^ c #18C9BE", +"(^ c #18C4BA", +"_^ c #19BFB5", +":^ c #41C6BE", +"<^ c #1FCFC4", +"[^ c #18D1C6", +"}^ c #18D5C9", +"|^ c #19D6CB", +"1^ c #119990", +"2^ c #119089", +"3^ c #18C1B7", +"4^ c #18BCB3", +"5^ c #1FBAB0", +"6^ c #20CBC1", +"7^ c #19CDC3", +"8^ c #18CFC5", +"9^ c #11958E", +"0^ c #118D86", +"a^ c #19C3B9", +"b^ c #18BBB1", +"c^ c #20B7AE", +"d^ c #8A898A", +"e^ c #41D0C8", +"f^ c #19C8BE", +"g^ c #19CAC0", +"h^ c #19CCC1", +"i^ c #18CABF", +"j^ c #010D0D", +"k^ c #17C0B6", +"l^ c #18BCB2", +"m^ c #19B8AD", +"n^ c #42C0B9", +"o^ c #83DDD9", +"p^ c #19C4BA", +"q^ c #18C5BC", +"r^ c #19C7BD", +"s^ c #17C3B9", +"t^ c #118C85", +"u^ c #118B84", +"v^ c #18BFB5", +"w^ c #19BEB5", +"x^ c #19BBB1", +"y^ c #19B8AE", +"z^ c #19B3AB", +"A^ c #83D6D1", +"B^ c #878786", +"C^ c #F6F6F6", +"D^ c #E6F8F6", +"E^ c #21C1B7", +"F^ c #18C2B8", +"G^ c #18C1B8", +"H^ c #19C0B7", +"I^ c #18BCB4", +"J^ c #18BAB1", +"K^ c #18B7AE", +"L^ c #18B4AB", +"M^ c #21B5AD", +"N^ c #E6F6F6", +"O^ c #EFEFEF", +"P^ c #838283", +"Q^ c #A4E3E0", +"R^ c #19BBB2", +"S^ c #19BCB3", +"T^ c #19BDB3", +"U^ c #18BAB0", +"V^ c #18B8AF", +"W^ c #18B5AC", +"X^ c #19B3A9", +"Y^ c #19B3AA", +"Z^ c #A4E1DD", +"`^ c #A4E2DE", +" / c #21B9B0", +"./ c #18B8AE", +"+/ c #19B7AE", +"@/ c #18B6AD", +"#/ c #19B4AC", +"$/ c #18B3AA", +"%/ c #84D6D1", +"&/ c #41C0B9", +"*/ c #20B5AC", +"=/ c #6E6F6F", +"-/ c #BEBEBD", +";/ c #6F706F", +">/ c #6D6D6C", +",/ c #5E5F5E", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" . . . ", +" + + + . . . . . . . ", +" + + + + + @ # # $ . . . . . . ", +" + + % + & # * = - ; > , ' . . . . . ", +" + + ) ! ~ { ] ^ / > ' ' ' ( _ : . . . . . . . . ", +" + + ) ) ) ) ) < [ } | 1 2 3 3 4 5 5 6 7 8 8 . . . . . ", +" + # ) ) ) ) ) 9 0 a b c 0 d e f 8 8 7 g 8 h i j k . . . . . . ", +" l # ) ) ) m n 0 o p q r s t u v w x { y z k k A A B C D f . . . . . . . ", +" # # ) ) E F 0 a G H I J K L v M N O P u Q R S T A U U f f f V V W X . . . . . . ", +" Y $ ) ) Z 9 0 ` H r J ...+.+.@.#.$.%.&.*.=.-.;.>.! ,.'.).!.~.{.~.].^.^./.(.. . . . . ", +" _.- ) 9 0 0 H p :.s t ..v M M N P %.&.*.<.[.}.}.|.1.2.3.4.5.6.7.8.9.^.(./.0.a.% b.. . . . . . . . ", +" - ; 9 n a c.H d.e. .u v f.N N P g.h.&.[.i.j.k.k.1.3.l.4.m.n.n.o.&.) p.,.q.r.s.t.u.v.w.x.y.y.z.. . . . . ", +" ; > A.0 a H q B.s ..v C.M D.N g.&.&.<.i.[.E.F.|.G.3.H.I.J.K.L.M.N.O.O.P.Q.R.S.T.U.^ V.y.y.W.z.1 1 V.. . . . . . ", +" X.> 0 a b H Y.s s L f.C.N P Z.h.&.&.`.[.j.k.1. +3.4.J.n.n.L.M..+++@+P.Q.R.#+$+%+&+i.*+=+-+;+>+,+V.'+)+)+)+!+. . . . . . . ", +" > ~+a c.{+B.e.u ]+^+/+(+P %.h._+:+:+[.k.k.<+[+4.4.I.}+n.|+M.1+O.O.2+Q.3+4+5+%+6+7+8+9+0+a+4.N b+c+d+)+e+f+g+^ ^ h+i+j+. . . . . . ", +" , ' c.H r s t u v M N N P k+_+l+[.[.m+k.k.[+3.4.n+I.}+o+M.M.p+q+r+Q.s+#+t+a+u+v+8+9+w+0+x+y+z+A+A+B+C+D+E+F+G+H+U.I+J+K+K+L+M+. . . . . . . ", +" ' ' :.r Y.s L v v N N N+g.&.O+<.[.-.P+k.1.3.4.Q+R+n.o+M.S+T+O.2+Q.Q.#+5+U+a+v+V+W+X+Y+Z+y+`+ @A+B+.@+@@@#@$@..%@&@*@=@-@L+;@>@>@,@'@)@!@. . . . . . ", +" ~@3 r s {@..v /+]@D.^@g.k+`.<.[.}./@k.2.(@l._@I.n.o+:@M.p+O.P.<@#+3+$+$+&+v+8+9+[@0+x+y+`+}@A+B+|@+@@@#@1@2@3@4@5@6@R.7@8@9@>@,@'@'@0@G+a@b@b@c@. . . . . ", +" 3 3 r s ..d@+.@.N D.g.g.`.e@=.;.E.k.2.3.H.f@}+J.g@o.h@i@O.@+j@Q.#+k@$+a+v+V+l@9+0+m@n@y+6@A+o@p@q@r@#@s@t@u@v@w@x@y@z@A@B@C@D@M E@F@G@H@b@I@b@=@J@K@L@. . . . . . ", +" 3 4 .]+M@M N N $.Z.&.N@`.[.O@>.k.1. +3.P@I.n.Q@:@M.N.R@2+P.S@4+T@$+a+U@V@W@X@w+0+y+y+Y@A+Z@|@q@`@#@ #$@.#4@w@w@x@+#@#B@##$#%#&#*#=#-#;#>#,#'#F+L@)#!#~#{#]#^#. /#/# ", +" (#5 ..v ^+M N P Z.g.l+`.<.}.}.k.1.1.3._#_@R+:#<#M.p+O.O.[#Q.s+}#$+a+v+8+8+|#0+Y+1#y+Y@-#2#.@q@@@3#4#$@3@u@5#6#x@+#7#B@C@8#$#9#0#a#b#c#c#d#b#w@.@u ,#q.{#{#e#f#g#/#/# ", +" 5 6 ..v ]@N $.P g.&.`.:+j.>./@|.3.3.Q+I.I.o+o+M.p+++O.[#Q.h#t+$+a+v+8+W@9+w+0+i#y+Y@ @j#B+.@@@k#s@l#3@3@m#n#6#x@7#o#p#$#%#%#*#=#=#q#r#s#t#u#v#w#x#x#y#z#A#B#C#f#/#/# ", +" D#6 M M E#P g.F#&.`.e@}.}.k.G#1.3.4.n+}+g@o+1+M.p+@+r+<@s+H#t+I#J#v+8+|#K#Y+i#y+L# @A+M#q@q@k# # #N#O#4@P#x@Q#R#p#C@S#T#9#*#0#=#U#c#V#d#W#X#v#Y#Z#`# $.$+$@$#$$$/#/# ", +" 5 6 M @.D.P g.%$&$:+;.m+*$1.=$3.4.-$J.o+g@M.N.R@O.P.S@Q.H#$+;$J#V@W+9+w+>$x+y+Y@,$A+B+q@'$)$#@!$3@v@4@w@6#y@+#@#p#$#~${$]$a#=#q#^$/$($t#_$w#x#`#:$y#<$[$}$|$1$$$/#/# ", +" 6 6 (+D.N+g.F#O+:+[.2$*$F.=$2.l.4.I.:#o+o+1+p+R@P.3$Q.#+$+;$J#v+4$5$|#Y+x+y+6$7$A+B+8$@@k##@l#N#3@4@w@9$y@0$a$b$c$d${$*#=#=#b#c#e$t#f$g$w#h$i$j$ $k$+$}$l$m$$$n$/#/# ", +" o$8 p$P g.&.q$<.[.}.k.G#1.3.r$n+R+n.Q@L.M.p+@+O.3$Q.#+H#$+U@v+4$s$9+t$n@u$`+Y@A+v$w$q@r@#@#@2@O#4@w@z#x$+#@#p#C@~$%#*#a#=#b#c#V#V#t#y$w#x#Z#Z# $.$z$[$A$B$C$D$E$/#/# ", +" 8 h P g.%$&.`.[.7@}.G#1.G.4.Q+I.n.n.o+p+p+F$P.<@S@#+a+9+8+v+G$H$I$K#x+J$L# @A+o@|@q@@@)$s@K$3@4@L$M$N$+#7#O$S#c$P$Q$*#a#R$q#c#t#($u#v#h$S$`#`#T$z$+$|$C$C$U$V$E$/#/# ", +" W$i ^@k+*.q$=.}.}.k.G#G.H._#f@X$Y$o+M.p+++2+P.<@#+8+y$[$Q$8$5$9+w+>$Z$y+Y@7$`$ %q@@@)$4#t@3@4@w@w@x@+#+#@#S#c$$#�#0#b#c#c#.%t#t#X#+%@%`# $T$T$[$|$|$#%$%%%] ] /#/# ", +" &%*%F#&.q$=%j.j.k.<+3.r$4._#-%g@|+M.1+O.O.P.<@s+H#u$;%V#@@o#y$K$y+x+>%Y@7$Z@.@q@@@#@#@$@3@v@P#z#N$,%a$o#S###{$&#*#=#'%c#r#V#)%y$!%w#`#`# $~%T$+$l${%C$]%^%/%] (%/#/# ", +" _%:%&.l+i.[.}.|.1.1.r$<%I.n.n.Y$M.S+p+[%[%j@#+H#t+0+}%4@g.|%s @#w#6#q@-#Z@w$q@@@k#s@$@t@O#m#w@6#y@+#@#C@1%T#%#*#2%3%4%s#V#t#g$y$w#+%`#`#5%T$T$|$A$C$;%6%/%7%(%8%/#/# ", +" 9%A *.:+[.}.*$|.1.3.-$-$I.:#Y$1+1+0%[%P.j@s+#+H#9+8$a%Y@4.b%c%d%e%f%V#y@B+|@r@@@#@$@2@w@6#P#x@+#+#7#S#C@$#%#g%=#b#h%c#V#d#t#y$w#w#Z#i%j%T$[$[$|$C$$%6%k%7%l%(%8%/#/# ", +" A A :+[.j.E.F.1.m%4.f@I.Q@L.<#M.T+O.n%o%s+#+$+a+7#p%q%r%D+0+s%t%u%v%w%W#k%]$4@u@$#t#w#f$b#x%$#@#@#C@y%d$z%*#=#2%q#c#r#)%A%y$w#x#B%`#k$5%+$@$|$C$;%6%k%C%D%E%F%G%/#/# ", +" A H%[.;.>.F.1.H.4.-$J.m.I%M.M.p+O.2+P.R.h#k@a+V@X#J%K%L%M%g.N%O%P%Q%R%S%T%U%C$C$;%B+$+A+=# $C$l$t#$#d$T#V%*#=#b#^$s#V#t#y$X#Y#W%`#X%T$Y%Z%|$B$`% &k%7%C%.&+&G%@&/#/# ", +" U U m+/@|.F.H.<%4.I.J.Q@o.M.N.O.n%P.Q.#+#&%+a+V+$&%&&&*&=&-&Q.;&>&,&'&)&!&~&+&p+{&]&^&/&(&_&:&g.=#<&Y%b#]$3%4%c#r#[&)%y$X#w#x#`#i%.$}&z$|${%|&6%k%1&2&3&+&4&5&G@/#/# ", +" U 6&>.<+1.2.<%<%J.n.K.:@M.T+++O.[#Q.#+$+$+a+V@K#p%7&8&5.9&0&$@a&b&c&d&e&f&g&A+M%1$b@h&>@G+J@g#e /#i&3#7%C$w#U#V#)%A%j&_$k&x#W% $l&T$m&l$B$;%;%k%7%7%l%+&<&n&G@o&/#/# ", +" p&D k.1.3.<%4.R+m.n.|+o.S+O.q+q&R.s+H#$+a+r&G$,$s&t&u&v&w&x&@#:&x a&y&z&A&B&I.C&$$$$D&f#f#^#q.=@a@f#E&`.k%7%`%V#F&y$G&Y#B%S$i%T$T$@$|$|$#%;% &7%l%H&+&I&J&K&L&o&/#/# ", +" p&f M&=$3.<%R+X$n.o+M.S+N&n%P.Q.#+#+5+a+u+4$8+q@O&P&Q&R&,.S&+#T&U&. *+V&W&X&Y&Z&`&`&G@G@G@F%F%F% *(%] b%P..*+*;%f$G&w#x#W%`# $z$T$m&|$C$;%U$@*C%l%+&+&n&n&#*o&`&/#/# ", +" f $*(@<%-$I.m.n.o+o.p+R@[%[#P.#+H#$+5+v+v+8+K#3#%*&***Q.=*-*4@@+1.3.8+3@#+&.;*e e e >*c%,*Z&Z&Z&'*'*F@)*0 '*!*7%T$+%@%`# $ $T$[$~*|$;%;%k%{*@*l%+&<&<&]*^*/*8.(*/#/# ", +" V V 3.4.n+-%n.:@|+S+_*O.n%Q.Q.#&$+;$J#7+W@H$:*1%<*[.[*x+h#$+w#y+*$N }*|*E@1*2*3*4*5*6*E+7*8*8*9*C&C&2*J.0*e 4*`.a*b*x#i%<$5%z$Z%|$$%;%;%{*2&D%+&}%4&c*#*/*d*`&y /#/# ", +" V W r$_#J.n.o+o+S+p+O.2+Q.#+h#$+a+%+4$8+W@K#2#;%o+e*-+D+f*g*[*,#h*i*j*k*j*l*/&j*m*n*(&(&(&l*l*l*o*o*&@x+,#p*4*x |$C$W% $.$z$|$q*B$#%;%%%7%l%.&+&<&J&r*s*t*a%y u*/#/# ", +" v*{.-$J.n.o+C+.+p+_*M.P.R.H#T@I#v+v+8+9+9+0+4#<&w*x*x*x*_&y*^&-+z*A*=&=&7.y*B*C*| D*E*E*E*2*2*2*{ E*F*M.]&j*/&z*S@G* $k$H*[$|$I*;%;%1&<*l%.&+&<&]*r*J*t*a%K*u*'*/#/# ", +" W ~.I.n.o+C+M.p+T+L*M*N*O*2$C+#&v+4$8+K#0+m@o@]%`./#P*Q*R*P*Q*Q*R*S*]&R*i*T*i*U*i*=&=&V*=&=&=&W*y*X*Y*w y*7.| E*Z*`*H*+*[$~*C$`%`%k%7%7%.&I& =]*#*.=t*a%+=@=u*#=/#/# ", +" ~.$=R+o+|+M.p+F$2+%=&=*===-=;=>=,=8+[@0+I$y+'=)=U$k.,#R*_&M%M%Q*!=~=1*{=]=^=,#/=(=_=:=<=[=]&]&]&R*}=B+|%|=|=i*9&1=`*C$}$|$A$2=6%k%{*C%3=+&4=5=r*#*t*6=7=`*@='*'*/#/# ", +" ].^.Q@o+h@N.++q+3$8=9=0=a=b=c=d=e=f=g=h=i=j=k=v+l=+&`+U&m=n=o=p=q=r=s=t=u=v=w=x=y=z=A=B=C={&D=E==+M.&.X*[=Q*_&F=$#`*|$m&C$C$;%k%<*2&G=3&H=I=r*#*t*J=a%K=L=M='*N=/#/# ", +" ^.^.o+o.p+F$O.<@<@O=P=Q=R=S=T=U=V=W=X=Y=Z=`= -.-+-@-#-$-%-&-*-=---;->-,-'-)-!-~-{-]-^-/-(-_-:-<-R&3@[-M%_&X*}-w@`*k%~*q*C$#%k%<*7%G=+&+&5=]*^*|-J=J=`*@=1-2-Z&3-/#/# ", +" 4-(.:@p+p+O.P.j@Q.#+;$5-6-7-8-9-0-a-b-c-d-e-f-g-h-i-j-k-l-m-n-o-p-q-r-s-t-u-v-w-x-y-z-A-B-C-D-E-F-3.s%_&1*}-$@a%7%Z%A$C$;%%%1&7%l%G-}%H-]*I-J*t*a%`*J-K-L-M-3-N-/#/# ", +" (.O-N.R@O.q+S@Q.#+t+%+6+P-Q-R-S-T-U-V-W-X-Y-Z-`- ;.;+;@;#;$;%;&;*;=;-;;;>;,;';);!;~;{;];^;/;(;_;:;t M%e*w*+#M-<*~*|$C$;%U$k%<*l%G=H=<&]*c*t*d*a%`*@=1-2-M-<;[;c%/#/# ", +" (.).p+O.2+j@R.};}#5+J#v+8+|;1;2;3;4;v+Y@A+5;J#6;7;8;9;0;a;b;c;d;e;f;g;h;i;j;k;l;m;n;o;p;q;r;s;t;u;v;w;! b#L-;%|$m&x;C$]%1&7%l%3&+&<&]*c*a*t*a%`*`*y;L-z;A;<;B;C;/#/# ", +" O-D;O.n%[#P.#+$+%+&+v+v+W@X+0+x+y+y+ @A+o@|@q@@@3#$@E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;W;X;Y;Z;`; >.>%%a%I*}$Z%B$;%;%k%7%l%G-+& =I=G*s*t*J=+>`*@=L-M-M-<;@>C;e /#/# ", +" % #>[%P.Q.#+#&;$u+v+8+9+9+$>x+i#Y@Y@ @ %p@q@%>&>l#2@.#4@*>=>->;>>>,>'>)>!>~>{>]>^>/>(>_>:><>[>}>|>1>2>3>4> $Z%B$C$U$%%<*l%l%I&<&5>G*6>t*7>`*8>9>L-2-0>a>@>b>e c>/#/# ", +" % b.P.o%h#H#$+a+6+G$W@9+$>x+x+`+Y@6@o@w$'$r@#@l#K$O#O#4@d>x@e>f>g>h>i>j>k>l>m>n>o>p>q>r>s>t>u>v>w>x>y>z>A>B>C>x#|&/%k%D%3&E%<&]*]*/*t*6=7=J-@=L-2-M-<;@>D>E>F>F@/#/# ", +" u.u.S@#+#&$+a+6+G$W@|#w+x+y+>%Y@7$j#w$q@@@@@#@$@3@v@m#w@x@z@G>H>I>J>K>L>M>N>O>P>Q>R>S>T>U>V>W>X>Y>Z>`> ,.,+,@,#,$,%,&,l%+&H=n&]*#*t*t*a%`**,y;2-M-<;=,-,;,>,,,,,/#/# ", +" u.w.s+t+;$a+a+7+8+9+0+>$x+'=Y@,$B+B+q@@@@@#@',N#O#),M$x@+#@#!,C@$#~,x%{,],^,/,(,_,:,<,[,},|,1,2,3,4,5,6,7,8,9,0,a,b,c,d,<&<&r*#*/*t*K*+>@=1-L-e,<;f,D>g,>,>,,,h,/#/# ", +" i,j,#&$+U+6+v+W+s$X+$>x+'=6$}@o@p@q@'$k#4#$@k,3@5#M$x@z@+#@#C@S#~$%#*#]$3%b#c#V#l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,t*a%`*`*K-L-M-<;a>J,;,>,K,L,M,N,/#/# ", +" j,9.H#a+u+v+8+l@9+0+n@Z$L# @O,B+.@'$%>#@$@N#I>4@),d>N$a$A@P,##$#V%*#0#2%b#Q,V#V#t#y$X#Y#S$v#5%T$T$T$R,S,T,U,V,W,X,Y,Z,`, '.'+'@'#'$'`*y;L-M-M-<;%'&'>,*'='-'C&;'/#/# ", +" >','a+&+v+8+l@K#$>x+y+Y@Y@j#v$.@@@@@''$@K$3@L$L$M$,%)'@#C@$#$#9#*#!'2%4%c#V#V#t#y$w#Y#x#`# $.$T$[$|$C$y#~'{']'^'/'('_':'<'['}'|'1'2'3'3&0><;4'D>;,g,5'='L,6';'7'/#/# ", +" 8'y.a+7+9'8+9+>$Z+J$`+Y@A+B+B+0'@@)$l#k,3@4@w@M$x@+#@#p#C@$#%#*#a'2%b#c#V#.%t#y$v#h$x#W%y#<$}&l$|$q*2=;%]%7%b'c'd'e'f'g'h'i'j'k'l'm'n'o'p'a>4';,g,q'r'-'s't'T T /#/# ", +" y.u'E@D+v'$+0+x+y+6$`+A+v$|@+@@@#@$@t@3@4@w@x@x@,%7#p#C@$#%#z%a#2%b#w's#V#W#y$x'k&y'`#y#.$T$+$|$z'I*6%%%7%3=l%}$A'B'C'D't*a%+&E'F'G'H'I'J'J,b>E>K,K,-'-'6'K'L'8*/#/# ", +" M'1 1 1 '@N'8*O'=$Y@A+A+B++@r@k#l#$@N#4@4@M$x$z@+#C@p#1%%#*#]$'%b#w'P'V#)%W#w#+%x#`# $l&T$[$l$q*C$;%%%Q'7%l%+& =<&R'S'T'a%a%U'@=H-V'W'X'Y';,E>>,r'Z's'`' ).)+)E+/#/# ", +" 1 V.V.'+)+)+@)f+f+i*S.-%#+Y@$@k,t@u@m#w@x@+#+#@#1%y%8#z%#)=#3%q#c#V#t#W#y$h$k&i$:$ $T$[$l$|$C$;%^%7%7%C%+&+&<&G*I-a*/*+>`*@=L-L-L-a%$)%);,q'r'&)*)6'=)-).)9@E+/#/# ", +" d+@)e+f+;)^ ^ i+U.y /#>)< p+4@w@x@+#G>@#C@$#~$%#*#=#,)w'e$V#V#j&y$w#x#x#j$ $T$+*~*|$C$;%^%<*7%l%+&4=<&]*^*6>t*a%`*')y;))p'!)@>@>;,~){)&)])`'^)/).)()_)4*/#/# ", +" &.^ i+U.H+K+:)<)b@D$[)1*! +#@#C@c$T#9#*#=#'%b#r#V#.%u#y$w#k&B%i% $T$H*~*|$C$I*6%7%7%3&.&+&<&J&c*a*6=7>+=@=@=})M-|)1)2)2)3)r'4)-'^)5).)6)7)8)_)4*/#/# ", +" *.P N $.P ^@K+9)<)L+L+>@>@0)'@'@,,a)j.v+1@a#=#b#c#V#b)A%y$w#@%x#j$y#T$T$[$|${%I*]%<*{*7%.&+&<&]*G*J*6>c)7=@=L-1-M-d)<;@>;,E>*'r'-'e)5)/).)6)f)g)4*h)/#/# ", +" `.i)i)P P g.F#&.&$`.:+[.7@>@j)'@)@k)a@l)b@g#=&|%F==%9#V#A%y$w#Y#i$i% $<$T$[$l$C$#%;%k%7%2&E%+&4=I=c*s*t*a%K=J-@=m)))e,a>@>;,g,>,r'*)6'K'K'n)()8)8)o)p)q)/#/# ", +" j.i.k+N+g.g.g.g.&.l+q$`.[.}.}.M&F.3.3.4.G+b@b@r)=@s)t)q.(%y { u)Y@w#B%`# $<$z$[$|$C$C$ &k%7%7%E%+&<&5=]*J*v)J=a%`*@=9>M-M-<;@>b>q'K,&)Z'6'6'w).)x)8)g)y)z)q)3*/#/# ", +" A)-.`._+*.O+f*`.f*`.e@[.[.-.}.}.F.1.3.<%4.I.-%o+L.h@=@B)L@L@C)q.{#D)^#C#s%E)K#4@_$|$z'$%;%k%k%D%l%+& =I=]*c*t*J=a%@=J-1-M-M-<;@>;,;,{)r'&)e)`'K'F)x)()y)o)G)z)H)o*/#/# ", +" 1.}.-.i.[.=.[.[.=%[.7@7@j.}.>.k.M&1.G.3.4.f@I.m.o+o.M.R@<#.*e*e*/#q.I)J)K)f#$$$$$$L)M)N)) 3@%%Q'O)E%+&}%n&^*^*t*6=a%`**,M=P)M-!)f,%'Q)>,R)-'S)6'T)F)7)U)8)o)G)z)z)V)V)/#/# ", +" -%3.G#M&k.k.}.}.}.}.2$2$/@}.P+*$|.<+1.G.3.<%Q+I.R+Q@o+o.h@_*[%W)/#/#/#/#/#X)Q*x*N'D&Y)D$E$E$Z)`) !C&.!}.@*+!5=]*I-t*@!a%K=8>#!z;M-0>@>%'q'$!K,Z'])%!&!.)n)f)8)*!z)z)z)z)V)=!/#/# ", +" o+I.4.m%[+ +=$G#|.-!|.k.M&|.F.k.<+-!(@G.H.4._#_#I.n.:#o+C+.+++2+P.;!/#/#/#/#/#B#R*i*y*D*{ E$>!(%,!'!F%5&G@G@`)j*F=S@w@`#7>`*K=@=L-z;<;)!-,%)Q)r'r'-'6'=)w).)()!!g)~!z)z)z)z){!L)/#/# ", +" p+M.:#I.n+4.4.]!H.3. +G.1. +2.=$G.3.(@3.r$4.4.I.I.m.n.o+o.M.^!++2+P.P.1*/#/#/#/#/#M%R*^&A*2*/!l*3*l*/&(!_!@&G@o&`&:!>,>,f!S)%!K'/).)()g!8)h!z)z)z)z)z)z)l*(&/#/# ", +" P.3.&+U+[#O.M.o+:#n.m.J.}+I.I.I.I._@_#I.I.I.n.g@n.o+o+<#C+M.p+T+O.P.P.P.P.P.N s%/#/#/#/#i!j!k!l!E*j*m!3*V)(&{ | =&x*[=n!/#/#/#o!Z&Z&Z&c%c%e F>p!,,q!p$3@@%M-K'.)n)f)8)*!z)z)z)z)z)z)z)l*(&/#/# ", +" P./=r!s!G O.8+5+j@p+C+K.Q@n.K.:#n.X$n.:#Q@o+o+o+o+M.M.M..+++r+P.P.P.P.P.P.P.M ! /#/#/#/#!=t!9&u!7.2*v!w!(&j*x!y!z!x*Q*!=/#/#/#/#/#/#A!P.[!c>e ,,M,B!C&;'T.C!D!g. $8)E!E!z)z)z)z)z)z)z)(&(&/#/# ", +" P.G%[;o*k!F!A!s!M v+8+$+n%p+M.o+|+o.M.M.M.M.M.S+0%p+++O.O.P.P.P.P.P.P.P.P.P.P.P.`.A!/#/#/#M%G!x*=&7.E*2*{ H!| y*^&I!J!K!/#/#/#/#/#/#1*P.P.P.P.P.B!;'9*8*8*9@E+q)=!8!|!v+6'z)z)z)z)z)z)(&/&/#/# ", +" P.c%E+E+E++)4*L!u!B#M!w*k.9+v+#+P.O.p+p+p+p+T+T+O.O.r+P.P.P.P.P.P.P.P.P.P.P.P.P.P.k.p.M!/#!=_&R*i*V*E&7.| 7.N!-+x*O!B#/#/#/#/#/#/#/#a&P.P.P.P.P.P.P.P.P!+)E+6*4*4*h)3*o*Q!Q*p.x+b##*z)/&/&/#/#P. ", +" P.R!p)3*R*/&S!T!U!w!j*V!W!j!X!Y&M.a+#+Q.P.P.n%P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.) D+M)Y!Z!`!x*i*T* ~-+^&x*R*_&X)/#/#/#/#/#/#e*! P.P.P.P.P.P.P.P.P.P.P.P.P.P..~.~o*L){!l*+~@~#~b%/&/&/#/#P.P.P.P.P. ", +" P.B!Q!o*%@!*$~;*%~T*j*{ &~*~=~| E*-~;~a p+P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.o+@.>~-*} ,~'~R*)~9&]&`!j!_&E=/#/#/#/#/#/=x 1=O.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.o*l*(&+~!~~~/&/&/&/#P.P.P.P.P.P.P.P.P.P.P. ", +" P.{~l*(&!*}-]~0*^~/~s![-(~_~=&E&=&=&=&y*:~E@F=..4.n.p+P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.2+n.*$<~s !*. a)C![~}~|~|~/#/#e*1*/#e*1~. 2~K.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.3~/&/&/&P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.O. ", +" P.4~/&/&}-*+5~F=F=s!6~5.V&S.7~-*8~9~0~9&R*R*a~b~X)c~d~s &.3.p+#+Q.Q.P.P.P.P.P.P.P.P.R@4.}.p$r e~}*i&V&/~f~g~N):&[*D+h~W)i~) P+J.P.P.O.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.$+0 j~ ", +" P.Q!L!L!*+k~l~/~/~}=m~2~n~o~p.p~w q~r~s~t~S&M)}~Y!}~i!_&,.:&< 9 M 3.Q.$+#+Q.P.P.P.P.P.P.P.M u~! W)v~5.^~w~[-h~-*S.)*x~0 ..F#M&Y$o+P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.O.P...i&y~z~ ", +" P.A~2*H!B~^~C~s!s!D~5.n~E~p.F~.*G~W)}*H~g*! m I~Q J~K~L~F!M~N~F!|%. S.O~v I.a+$+#+Q.P.P.P.P.P.P.P.p.m~J~P~Q~0*R~p.W)1=a S~*.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.M.g.W).*q~T~i& ", +" P.U~V~| !@W~s!-*-*X~V&d~S.< i&Y~s~Z~`~ {1=.{9 a H I +{M :.Y~. @{E@#{#{M!>)}-m~Y&N p+v+$+Q.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.Q.P.n.`.! W)N%Y&${q~w ", +" P.j*7.N!A*A*%{&{U&*{w*S.p.< .*w W)Y&={x~-{) A.;{H >{M@M P g.`.}.7@,{1!D+|%C!A!'{){}-s! {[.Q.a+#+Q.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.Q.n.f*H x~!{~{x~={}*{{]{ ", +" P.^{/{l!e*%{=&T.V*V*x*({;*h~_{q~W)}* {:{! ) 0 u~r .v ]@N+&.`.-.1.3.4.n.<#}.<{6~[{}{>)[*[-p=R&9 3.$+$+Q.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.Q.M.F#f.A.0 9 ) ! 1=|{ {N%Z~ ", +" P.0!-+-+%@!*1{!@2{!=x*x*c+`!Q*e*3{*+4{1=) n 0 H s .v (+^@&.=%}.G#3._@Q@M.O.P.P.P.o+5{S&6{:&7{=*8{]~< ..n.#+Q.Q.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.Q.O.l+%.B.s I H ,{F E ! 1=1=j~H~ ", +" P.7.i*9{!*}-]~0*^~/~-*. x&,.X)_&'~0{n!e*a{}-4{c s M@M D.%.&.=%P+1.l.J.o+S+O.P.P.P.P.S&a)b{D+c{d{. f~*+e{h~-*f{g.M.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.Q.P.;.q$$.N M L K r c a g{9 ) ! h{i{ ", +" P.=&]&]&}-*+5~F=F=s!6~5.V&S.7~5.j{a{/=/#X*k{e*s%1~!*l{v h.`.[.k. +4.J.o+p+P.P.P.P.P.S&m{:&;~n{P~8{p=*+J~0*o{s!/~F=S.! `.n.M.O.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.0 g.P.P.P.P.3.[.[.o+;.P N M v t I H u~I~9 ) e~p{ ", +" P.b~Q*Q**+k~l~/~/~}=m~2~n~o~p.p~w q~r~s~q{r{s{%~/=t{6.u{A!b%v{M [+4.Q@C+p+2+P.P.P.P.a)[*w{x{y{b%!*}-*+J~F=z{-*-*-*s!/~F=F=< 9 &.3.n.p+P.Q.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.N 0 P.P.Y$k.2.A{k.M.[.g.B{N M v ..K C{:.a 0 n D{ ", +" P.c+_&_&B~^~C~s!s!D~5.n~E~p.F~.*G~W)}*H~g*! m I~Z~E{F{G{H{.!&@M!|%I{.*N 0%P.P.P.P.P.J{K{L{x{[-. !*}-W~-&F=s!-*-*-*-*-*-*-*s!/~F=-*.*0 P }.I.O.Q.Q.Q.P.P.P.P.P.P.P.P.P.P.P.P.P.3.W)p+_#-%R+4.2.1.M.[.O+&.%.O N ^+O M.s r M{,{N{ ", +" P.R*i!X)O{B~s!-*-*X~V&d~S.< i&Y~s~Z~`~ {1=.{9 a H I +{M P{Q{W~!@C!A!|%R{x&N)< ..n.P.6{:&D+N)b%S{f~e{h~0*/~s!-*-*-*-*-*-*-*-*-*-*-*s!/~F=5.q~9 ..&.I.P.#+Q.Q.P.P.P.P.1.I.L.O.H#4$o+Y@|@!$4@G>$#C@y+>.i.`.&.g.#.N +#v+..s Y.r H ", +" P.[=!=T{!=!=N~M!U{V{w*S.p.< .*w W)Y&={x~-{) A.;{H >{M@M P g.`.}.}.{+< [ ~ '{W{O'S&[-b{L{N)[-%@!*X{D!0*F=/~Y{-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*s!/~/~V&q~1=H g.n.#+v P `.&$Z{K{I!e#6 `{ ]`{k F%s%.]n%$#u#x#T$<.O+g.o+l$&.>~v .. .s ", +" P.+]#{@]N~#]_~X*X*X*k{,#S&F=_{q~W)}* {:{! ) 0 u~r .v ]@N+&.`.-.1.3.4.n.<#2$Z w*b%J{:&D+N)d{. !**+h~0*F=s!}=-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*s!s!s!w*$]G e~U&%]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]'*x~a'~*;%`.*#A+P N N M S~]+ ", +" P.8+v+1.W)D+A!,#/=1**]=]e*s%s%,#O'F=4{1=) n 0 H s .v (+^@&.=%}.G#3._@Q@M.O.P.P.P.o+D+;~[-. !*v&*+k~F=/~s!-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-];]z{c%&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]_&-#l%+&2$F#g.P O N M ", +" P.#+8+9+#+_+w b%>],]=+e*s%%~&{'])];!!@!]~]c s M@M D.%.&.=%P+1.l.J.o+S+O.P.P.P.P.D+{]d{. !*v&W~0*F=/~]]-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*^].**+G+&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]o*O#]*a%f*&.g.<~P 8) ", +" Q.a+ v+p+M W)/]c{|%=+:=(],._]_];!,#~ V{`~v h.`.[.k. +4.J.o+p+P.P.P.P.P.:]y{P~w~p=<]h~V{/~[]}=-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*}]}]l*&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]|]2&K=[.:+f*A+z) ", +" 8+#+R+N 1=7~1]|%=+,.2]&@M!a&a&^=~ B~${N [+4.Q@C+p+2+P.P.P.P.[-3]. f~}-h~0*F=/~t~-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*F=x&4]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]5]q@L-}.x@>, ", +" $+P.4.g.H q~6]1~7],#a&1~R{8];*x&|!*+-]Z.0%P.P.P.P.P.b%. !*}-*+h~0*F=s!-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*}-R*&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]9 4)@>O. ", +" Q.O.I.F.N q~b%A!C!|%9]U&~ !@O'S&a)0]w M o+P.b%1]!*a]h~0*b]z{-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*[-8*&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]b%>,<+ ", +" P.O.M.o+g.w =*c]U&|]d]a)e]:&D+{]d{e{. !*}-*+0*f]g]s!-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*O{h]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]i]j]k]l]m]n]o]p]&]&]&]&]&]&]&]&]&]q]>, ", +" P.P.P.P.p+N < =*r]b{e]N):]d{%@S{}-v&W~0*s]t]}=-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*~ c%&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]u]v]w]x]y]z]A]B]C]D]&]&]&]&]&]&]&]&]&]!*K, z) ", +" P.Q.#+$+M. .Z*E]%@!*. F]v&*{G]F=[]t~-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*R{{ &]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]H]I]J]K]J]I]l]L]M]N]O]P]&]&]&]&]&]&]&]&]&]r S) z) ", +" P.#+$+a+f@H Q]/~t]R]f]T&s!-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*A!!=&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]S]T]y]U]V]U]y]W]X]B]Y]Z]`] ^&]&]&]&]&]&]&]&]&]@#o)z) ", +" P.Q.$+a+#+1.H q~< S.m~s!s!-*-*-*-*-*-*-*-*-*-*-*-*-*-*A!E@&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&].^+^l]@^#^$^%^&^*^=^-^;^>^,^&]&]&]&]&]&]&]&]&]E%x) ", +" P.#+a+a+P.k.s {q~p.m~/~s!-*-*-*-*-*-*-*-*-*-*-*A!M%&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]'^)^!^z]~^{^z)z)]^^^/^(^_^:^&]&]&]&]&]&]&]&]J$@> ", +" Q. $+M.}...) W)S.s!/~s!-*-*-*-*-*-*-*-*A!{ &]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]<^[^}^|^1^z)z)z)z)2^;^3^4^5^&]&]&]&]&]&]&]c @= ", +" Q.o+}.M 0 Y&V&F=/~s!-*-*-*-*-*|%V)&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]6^7^8^[^9^z)z)z)z)0^a^_^b^c^&]&]&]&]&]&]Q]K& ", +" #+P.n.k.&.H q~m~0*/~s!-*-*d^*@&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]e^f^g^h^i^]^z)z)j^k^_^l^m^n^&]&]&]&]&]i~O) ", +" Q.O.n.3.`.a .*s!F=/~x&1*&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]o^p^q^O]r^s^t^u^v^w^x^y^z^A^&]&]&]&]:#B$ ", +" P.O.M.n.`.9 p.B^|%C^&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]D^E^3^F^G^3^H^v^I^J^K^L^M^N^&]&]O^w@Z# ", +" P.P.O.O.M.!@P^E&&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]Q^R^S^T^S^R^U^V^W^X^Y^Z^&]&]m~b#t# ", +" P.P.d [*S&E$&]&]&]&]&]&]&]&]&]&]&]&]&]&]`^ /./+/@/#/$/Y^M^Z^&]Q*q@S#0# ", +" L{$~:&o*&]&]&]&]&]&]&]&]&]&]&]&]&]N^%/&/$/*/&/%/N^x 4$k,9$ ", +" . }-B~x&E$&]&]&]&]&]&]&]&]&]&]&]&]&]&]&]/&0 H$z+B+ ", +" h~/~m~=/m~a)/#-/V 5] ]5]^.{~M!i&l+N.3$5+8+ ", +" ;/>/i&G~N%i{,/a .M g.[.F._@o+ ", +" ", +" ", +" ", +" "}; diff --git a/src/Mod/Ship/InitGui.py b/src/Mod/Ship/InitGui.py index 77298ad84..e735befa1 100644 --- a/src/Mod/Ship/InitGui.py +++ b/src/Mod/Ship/InitGui.py @@ -1,68 +1,68 @@ -#*************************************************************************** -#* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * -#* * -#* 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 * -#* * -#*************************************************************************** - -class ShipWorkbench ( Workbench ): - """ @brief Workbench of Ship design module. Here toolbars & icons are append. """ - from shipUtils import Paths, Translator - import ShipGui - - Icon = Paths.iconsPath() + "/Ico.png" - MenuText = str(Translator.translate("Ship design")) - ToolTip = str(Translator.translate("Ship design")) - - def Initialize(self): - from shipUtils import Translator - # ToolBar - list = ["Ship_LoadExample", "Ship_CreateShip", "Ship_OutlineDraw", "Ship_AreasCurve", "Ship_Hydrostatics"] - self.appendToolbar("Ship design",list) - list = ["Ship_Weights", "Ship_CreateTank", "Ship_GZ"] - self.appendToolbar("Weights",list) - # Simulation stuff only if pyOpenCL & numpy are present - hasOpenCL = True - hasNumpy = True - try: - import pyopencl - except ImportError: - hasOpenCL = False - msg = Translator.translate("pyOpenCL not installed, ship simulations disabled\n") - App.Console.PrintWarning(msg) - try: - import numpy - except ImportError: - hasNumpy = False - msg = Translator.translate("numpy not installed, ship simulations disabled\n") - App.Console.PrintWarning(msg) - if hasOpenCL and hasNumpy: - list = ["Ship_CreateSim", "Ship_RunSim", "Ship_StopSim"] - self.appendToolbar("Simulation",list) - - # Menu - list = ["Ship_LoadExample", "Ship_CreateShip", "Ship_OutlineDraw", "Ship_AreasCurve", "Ship_Hydrostatics"] - self.appendMenu("Ship design",list) - list = ["Ship_Weights", "Ship_CreateTank", "Ship_GZ"] - self.appendMenu("Weights",list) - if hasOpenCL and hasNumpy: - list = ["Ship_CreateSim", "Ship_RunSim", "Ship_StopSim"] - self.appendMenu("Simulation",list) - -Gui.addWorkbench(ShipWorkbench()) +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 * +#* * +#*************************************************************************** + +class ShipWorkbench ( Workbench ): + """ @brief Workbench of Ship design module. Here toolbars & icons are append. """ + from shipUtils import Paths, Translator + import ShipGui + + Icon = Paths.iconsPath() + "/Ico.png" + MenuText = str(Translator.translate("Ship design")) + ToolTip = str(Translator.translate("Ship design")) + + def Initialize(self): + from shipUtils import Translator + # ToolBar + list = ["Ship_LoadExample", "Ship_CreateShip", "Ship_OutlineDraw", "Ship_AreasCurve", "Ship_Hydrostatics"] + self.appendToolbar("Ship design",list) + list = ["Ship_Weights", "Ship_CreateTank", "Ship_GZ"] + self.appendToolbar("Weights",list) + # Simulation stuff only if pyOpenCL & numpy are present + hasOpenCL = True + hasNumpy = True + try: + import pyopencl + except ImportError: + hasOpenCL = False + msg = Translator.translate("pyOpenCL not installed, ship simulations disabled\n") + App.Console.PrintWarning(msg) + try: + import numpy + except ImportError: + hasNumpy = False + msg = Translator.translate("numpy not installed, ship simulations disabled\n") + App.Console.PrintWarning(msg) + if hasOpenCL and hasNumpy: + list = ["Ship_CreateSim", "Ship_RunSim", "Ship_StopSim", "Ship_TrackSim"] + self.appendToolbar("Simulation",list) + + # Menu + list = ["Ship_LoadExample", "Ship_CreateShip", "Ship_OutlineDraw", "Ship_AreasCurve", "Ship_Hydrostatics"] + self.appendMenu("Ship design",list) + list = ["Ship_Weights", "Ship_CreateTank", "Ship_GZ"] + self.appendMenu("Weights",list) + if hasOpenCL and hasNumpy: + list = ["Ship_CreateSim", "Ship_RunSim", "Ship_StopSim", "Ship_TrackSim"] + self.appendMenu("Simulation",list) + +Gui.addWorkbench(ShipWorkbench()) diff --git a/src/Mod/Ship/Makefile.am b/src/Mod/Ship/Makefile.am index f2477550b..2c643646c 100644 --- a/src/Mod/Ship/Makefile.am +++ b/src/Mod/Ship/Makefile.am @@ -46,6 +46,8 @@ nobase_data_DATA = \ Icons/SimRunIco.xpm \ Icons/SimStopIco.png \ Icons/SimStopIco.xpm \ + Icons/SimPostIco.png \ + Icons/SimPostIco.xpm \ Icons/Tank.png \ Icons/Tank.xcf \ Icons/Tank.xpm \ @@ -102,7 +104,13 @@ nobase_data_DATA = \ simRun/clSim/initialization.py \ simRun/clSim/Utils.py \ simRun/Sim/__init__.py \ - simRun/Sim/initialization.py + simRun/Sim/initialization.py \ + simRun/Sim/matrixGen.py \ + simRun/Sim/computeSources.py \ + simRun/Sim/fsEvolution.py \ + simPost/__init__.py \ + simPost/TaskPanel.py \ + simPost/TaskPanel.ui CLEANFILES = $(BUILT_SOURCES) diff --git a/src/Mod/Ship/ShipGui.py b/src/Mod/Ship/ShipGui.py index 821bb01ac..4848a6609 100644 --- a/src/Mod/Ship/ShipGui.py +++ b/src/Mod/Ship/ShipGui.py @@ -1,169 +1,183 @@ -#*************************************************************************** -#* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * -#* * -#* 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 * -#* * -#*************************************************************************** - -from PyQt4 import QtCore, QtGui -import FreeCAD, FreeCADGui, os - -class LoadExample: - def Activated(self): - import shipLoadExample - shipLoadExample.load() - - def GetResources(self): - from shipUtils import Paths, Translator - IconPath = Paths.iconsPath() + "/LoadIco.png" - MenuText = str(Translator.translate('Load an example ship geometry')) - ToolTip = str(Translator.translate('Load an example ship geometry able to be converted into a ship.')) - return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} - -class CreateShip: - def Activated(self): - import shipCreateShip - shipCreateShip.load() - - def GetResources(self): - from shipUtils import Paths, Translator - IconPath = Paths.iconsPath() + "/Ico.png" - MenuText = str(Translator.translate('Create a new ship')) - ToolTip = str(Translator.translate('Create a new ship in order to work with them')) - return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} - -class OutlineDraw: - def Activated(self): - import shipOutlineDraw - shipOutlineDraw.load() - - def GetResources(self): - from shipUtils import Paths, Translator - IconPath = Paths.iconsPath() + "/OutlineDrawIco.png" - MenuText = str(Translator.translate('Outline draw')) - ToolTip = str(Translator.translate('Plot ship outline draw')) - return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} - -class AreasCurve: - def Activated(self): - import shipAreasCurve - shipAreasCurve.load() - - def GetResources(self): - from shipUtils import Paths, Translator - IconPath = Paths.iconsPath() + "/AreaCurveIco.png" - MenuText = str(Translator.translate('Areas curve')) - ToolTip = str(Translator.translate('Plot transversal areas curve')) - return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} - -class Hydrostatics: - def Activated(self): - import shipHydrostatics - shipHydrostatics.load() - - def GetResources(self): - from shipUtils import Paths, Translator - IconPath = Paths.iconsPath() + "/HydrostaticsIco.png" - MenuText = str(Translator.translate('Hydrostatics')) - ToolTip = str(Translator.translate('Plot ship hydrostatics')) - return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} - -class SetWeights: - def Activated(self): - import tankWeights - tankWeights.load() - - def GetResources(self): - from shipUtils import Paths, Translator - IconPath = Paths.iconsPath() + "/Weight.png" - MenuText = str(Translator.translate('Set ship weights')) - ToolTip = str(Translator.translate('Set ship weights, tanks must be added later')) - return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} - -class CreateTank: - def Activated(self): - import tankCreateTank - tankCreateTank.load() - - def GetResources(self): - from shipUtils import Paths, Translator - IconPath = Paths.iconsPath() + "/Tank.png" - MenuText = str(Translator.translate('Create a new tank')) - ToolTip = str(Translator.translate('Create a new ship tank')) - return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} - -class GZ: - def Activated(self): - import tankGZ - tankGZ.load() - - def GetResources(self): - from shipUtils import Paths, Translator - IconPath = Paths.iconsPath() + "/HydrostaticsIco.png" - MenuText = str(Translator.translate('GZ curve')) - ToolTip = str(Translator.translate('Transversal stability GZ curve computation')) - return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} - -class CreateSim: - def Activated(self): - import simCreate - simCreate.load() - - def GetResources(self): - from shipUtils import Paths, Translator - IconPath = Paths.iconsPath() + "/SimCreateIco.png" - MenuText = str(Translator.translate('Create a new simulation')) - ToolTip = str(Translator.translate('Create a new simulation in order to process later')) - return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} - -class RunSim: - def Activated(self): - import simRun - simRun.load() - - def GetResources(self): - from shipUtils import Paths, Translator - IconPath = Paths.iconsPath() + "/SimRunIco.png" - MenuText = str(Translator.translate('Run a simulation')) - ToolTip = str(Translator.translate('Run a simulation')) - return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} - -class StopSim: - def Activated(self): - import simRun - simRun.stop() - - def GetResources(self): - from shipUtils import Paths, Translator - IconPath = Paths.iconsPath() + "/SimStopIco.png" - MenuText = str(Translator.translate('Stop active simulation')) - ToolTip = str(Translator.translate('Stop active simulation')) - return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} - -FreeCADGui.addCommand('Ship_LoadExample', LoadExample()) -FreeCADGui.addCommand('Ship_CreateShip', CreateShip()) -FreeCADGui.addCommand('Ship_OutlineDraw', OutlineDraw()) -FreeCADGui.addCommand('Ship_AreasCurve', AreasCurve()) -FreeCADGui.addCommand('Ship_Hydrostatics', Hydrostatics()) -FreeCADGui.addCommand('Ship_Weights', SetWeights()) -FreeCADGui.addCommand('Ship_CreateTank', CreateTank()) -FreeCADGui.addCommand('Ship_GZ', GZ()) -FreeCADGui.addCommand('Ship_CreateSim', CreateSim()) -FreeCADGui.addCommand('Ship_RunSim', RunSim()) -FreeCADGui.addCommand('Ship_StopSim', StopSim()) +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 * +#* * +#*************************************************************************** + +from PyQt4 import QtCore, QtGui +import FreeCAD, FreeCADGui, os + +class LoadExample: + def Activated(self): + import shipLoadExample + shipLoadExample.load() + + def GetResources(self): + from shipUtils import Paths, Translator + IconPath = Paths.iconsPath() + "/LoadIco.png" + MenuText = str(Translator.translate('Load an example ship geometry')) + ToolTip = str(Translator.translate('Load an example ship geometry able to be converted into a ship.')) + return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} + +class CreateShip: + def Activated(self): + import shipCreateShip + shipCreateShip.load() + + def GetResources(self): + from shipUtils import Paths, Translator + IconPath = Paths.iconsPath() + "/Ico.png" + MenuText = str(Translator.translate('Create a new ship')) + ToolTip = str(Translator.translate('Create a new ship in order to work with them')) + return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} + +class OutlineDraw: + def Activated(self): + import shipOutlineDraw + shipOutlineDraw.load() + + def GetResources(self): + from shipUtils import Paths, Translator + IconPath = Paths.iconsPath() + "/OutlineDrawIco.png" + MenuText = str(Translator.translate('Outline draw')) + ToolTip = str(Translator.translate('Plot ship outline draw')) + return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} + +class AreasCurve: + def Activated(self): + import shipAreasCurve + shipAreasCurve.load() + + def GetResources(self): + from shipUtils import Paths, Translator + IconPath = Paths.iconsPath() + "/AreaCurveIco.png" + MenuText = str(Translator.translate('Areas curve')) + ToolTip = str(Translator.translate('Plot transversal areas curve')) + return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} + +class Hydrostatics: + def Activated(self): + import shipHydrostatics + shipHydrostatics.load() + + def GetResources(self): + from shipUtils import Paths, Translator + IconPath = Paths.iconsPath() + "/HydrostaticsIco.png" + MenuText = str(Translator.translate('Hydrostatics')) + ToolTip = str(Translator.translate('Plot ship hydrostatics')) + return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} + +class SetWeights: + def Activated(self): + import tankWeights + tankWeights.load() + + def GetResources(self): + from shipUtils import Paths, Translator + IconPath = Paths.iconsPath() + "/Weight.png" + MenuText = str(Translator.translate('Set ship weights')) + ToolTip = str(Translator.translate('Set ship weights, tanks must be added later')) + return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} + +class CreateTank: + def Activated(self): + import tankCreateTank + tankCreateTank.load() + + def GetResources(self): + from shipUtils import Paths, Translator + IconPath = Paths.iconsPath() + "/Tank.png" + MenuText = str(Translator.translate('Create a new tank')) + ToolTip = str(Translator.translate('Create a new ship tank')) + return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} + +class GZ: + def Activated(self): + import tankGZ + tankGZ.load() + + def GetResources(self): + from shipUtils import Paths, Translator + IconPath = Paths.iconsPath() + "/HydrostaticsIco.png" + MenuText = str(Translator.translate('GZ curve')) + ToolTip = str(Translator.translate('Transversal stability GZ curve computation')) + return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} + +class CreateSim: + def Activated(self): + import simCreate + simCreate.load() + + def GetResources(self): + from shipUtils import Paths, Translator + IconPath = Paths.iconsPath() + "/SimCreateIco.png" + MenuText = str(Translator.translate('Create a new simulation')) + ToolTip = str(Translator.translate('Create a new simulation in order to process later')) + return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} + +class RunSim: + def Activated(self): + import simRun + simRun.load() + + def GetResources(self): + from shipUtils import Paths, Translator + IconPath = Paths.iconsPath() + "/SimRunIco.png" + MenuText = str(Translator.translate('Run a simulation')) + ToolTip = str(Translator.translate('Run a simulation')) + return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} + +class StopSim: + def Activated(self): + import simRun + simRun.stop() + + def GetResources(self): + from shipUtils import Paths, Translator + IconPath = Paths.iconsPath() + "/SimStopIco.png" + MenuText = str(Translator.translate('Stop active simulation')) + ToolTip = str(Translator.translate('Stop active simulation')) + return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} + +class TrackSim: + def Activated(self): + import simPost + simPost.load() + + def GetResources(self): + from shipUtils import Paths, Translator + IconPath = Paths.iconsPath() + "/SimPostIco.png" + MenuText = str(Translator.translate('Track simulation')) + ToolTip = str(Translator.translate('Track simulation')) + return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} + + +FreeCADGui.addCommand('Ship_LoadExample', LoadExample()) +FreeCADGui.addCommand('Ship_CreateShip', CreateShip()) +FreeCADGui.addCommand('Ship_OutlineDraw', OutlineDraw()) +FreeCADGui.addCommand('Ship_AreasCurve', AreasCurve()) +FreeCADGui.addCommand('Ship_Hydrostatics', Hydrostatics()) +FreeCADGui.addCommand('Ship_Weights', SetWeights()) +FreeCADGui.addCommand('Ship_CreateTank', CreateTank()) +FreeCADGui.addCommand('Ship_GZ', GZ()) +FreeCADGui.addCommand('Ship_CreateSim', CreateSim()) +FreeCADGui.addCommand('Ship_RunSim', RunSim()) +FreeCADGui.addCommand('Ship_StopSim', StopSim()) +FreeCADGui.addCommand('Ship_TrackSim', TrackSim()) diff --git a/src/Mod/Ship/SimInstance.py b/src/Mod/Ship/SimInstance.py index 3d047e3a1..85740d034 100644 --- a/src/Mod/Ship/SimInstance.py +++ b/src/Mod/Ship/SimInstance.py @@ -1,657 +1,673 @@ -#*************************************************************************** -#* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * -#* * -#* 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 time -from math import * -import threading - -# COIN -from pivy.coin import * -from pivy import coin - -# FreeCAD -import FreeCAD,FreeCADGui -from FreeCAD import Base, Vector -import Part - -# Ship design module -from shipUtils import Paths, Translator, Math - -class FreeSurfaceFace: - def __init__(self, pos, normal, l, b): - """ Face storage. - @param pos Face position. - @param normal Face normal. - @param l Element length (distance between elements at x direction) - @param b Element beam (distance between elements at y direction) - """ - self.pos = pos - self.normal = normal - self.area = l*b - - def __init__(self, pos, normal, area): - """ Face storage. - @param pos Face position. - @param normal Face normal. - @param area Element area - """ - self.pos = pos - self.normal = normal - self.area = area - -class ShipSimulation: - def __init__(self, obj, fsMeshData, waves): - """ Creates a new simulation instance on active document. - @param obj Created Part::FeaturePython object. - @param fsMeshData [L,B,N] Free surface mesh data, with lenght - (x), Beam (y) and desired number of points. - @param waves [[A,T,phi,heading],] Waves involved - """ - # Add uniqueness property to identify Tank instances - obj.addProperty("App::PropertyBool","IsShipSimulation","ShipSimulation", str(Translator.translate("True if is a valid ship simulation instance"))).IsShipSimulation=True - # Compute free surface mesh - self.createFSMesh(obj,fsMeshData) - # Store waves - obj.addProperty("App::PropertyVectorList","Waves","ShipSimulation", str(Translator.translate("Waves (Amplitude,period,phase)"))).Waves=[] - obj.addProperty("App::PropertyFloatList","Waves_Dir","ShipSimulation", str(Translator.translate("Waves direction (0 deg to stern waves)"))).Waves_Dir=[] - w = [] - d = [] - for i in range(0,len(waves)): - w.append(Vector(waves[i][0], waves[i][1], waves[i][2])) - d.append(waves[i][3]) - obj.Waves = w - obj.Waves_Dir = d - # Add shapes - shape = self.computeShape(obj) - if not shape: - obj.IsShipSimulation=False - return - obj.Shape = shape - obj.Proxy = self - - def onChanged(self, fp, prop): - """ Property changed, tank must be recomputed """ - if prop == "IsShipSimulation": - FreeCAD.Console.PrintWarning("Ussually you don't want to modify manually this option.\n") - - def execute(self, obj): - """ Shape recomputation called """ - obj.Shape = self.computeShape(obj) - - def createFSMesh(self, obj, fsMeshData): - """ Create or modify free surface mesh. - @param obj Created Part::FeaturePython object. - @param fsMeshData [L,B,N] Free surface mesh data, with lenght - (x), Beam (y) and desired number of points. - """ - # Study input object - try: - props = obj.PropertiesList - props.index("IsShipSimulation") - if not obj.IsShipSimulation: - msg = str(Translator.translate("Object is not a valid ship simulation.\n")) - FreeCAD.Console.PrintError(msg) - return - except ValueError: - msg = str(Translator.translate("Object is not a ship simulation.\n")) - FreeCAD.Console.PrintError(msg) - return - # Get areas and number of elements per direction - L = fsMeshData[0] - B = fsMeshData[1] - N = fsMeshData[2] - A = L*B - area = A/N - l = sqrt(area) - b = sqrt(area) - nx = int(round(L / l)) - ny = int(round(B / b)) - # Start data fields if not already exist - props = obj.PropertiesList - try: - props.index("FS_Nx") - except ValueError: - obj.addProperty("App::PropertyInteger","FS_Nx","ShipSimulation", str(Translator.translate("Free surface number of elements at x direction"))).FS_Nx=0 - try: - props.index("FS_Ny") - except ValueError: - obj.addProperty("App::PropertyInteger","FS_Ny","ShipSimulation", str(Translator.translate("Free surface number of elements at y direction"))).FS_Ny=0 - try: - props.index("FS_Position") - except ValueError: - obj.addProperty("App::PropertyVectorList","FS_Position","ShipSimulation", str(Translator.translate("Free surface elements position"))).FS_Position=[] - try: - props.index("FS_Area") - except ValueError: - obj.addProperty("App::PropertyFloatList","FS_Area","ShipSimulation", str(Translator.translate("Free surface elements area"))).FS_Area=[] - try: - props.index("FS_Normal") - except ValueError: - obj.addProperty("App::PropertyVectorList","FS_Normal","ShipSimulation", str(Translator.translate("Free surface elements normal"))).FS_Normal=[] - # Fill data - obj.FS_Nx = nx - obj.FS_Ny = ny - pos = [] - areas = [] - normal = [] - for i in range(0,nx): - for j in range(0,ny): - pos.append(Vector(-0.5*L + (i+0.5)*l,-0.5*B + (j+0.5)*b,0.0)) - areas.append(l*b) - normal.append(Vector(0.0,0.0,1.0)) - obj.FS_Position = pos[:] - obj.FS_Area = areas[:] - obj.FS_Normal = normal[:] - - def computeShape(self, obj): - """ Computes simulation involved shapes. - @param obj Created Part::FeaturePython object. - @return Shape - """ - print("[ShipSimulation] Computing mesh shape...") - nx = obj.FS_Nx - ny = obj.FS_Ny - mesh = FSMesh(obj) - planes = [] - # Create planes - Percentage = 0 - Count = 0 - print("0%") - for i in range(1,nx-1): - for j in range(1,ny-1): - Count = Count+1 - done = int(round(100 * Count / ((nx-2)*(ny-2)))) - if done != Percentage: - Percentage = done - print("%i%%" % (done)) - v0 = (mesh[i][j].pos + mesh[i-1][j].pos + mesh[i][j-1].pos + mesh[i-1][j-1].pos).multiply(0.25) - v1 = (mesh[i][j].pos + mesh[i+1][j].pos + mesh[i][j-1].pos + mesh[i+1][j-1].pos).multiply(0.25) - v2 = (mesh[i][j].pos + mesh[i+1][j].pos + mesh[i][j+1].pos + mesh[i+1][j+1].pos).multiply(0.25) - v3 = (mesh[i][j].pos + mesh[i-1][j].pos + mesh[i][j+1].pos + mesh[i-1][j+1].pos).multiply(0.25) - p = Part.makePolygon([v0,v1,v2,v3,v0]) - planes.append(Part.makeFilledFace(p.Edges)) - # Join into a compound - return Part.makeCompound(planes) - -class ViewProviderShipSimulation: - def __init__(self, obj): - """ Set this object to the proxy object of the actual view provider """ - obj.Proxy = self - - def attach(self, obj): - """ Setup the scene sub-graph of the view provider, this method is mandatory """ - return - - def updateData(self, fp, prop): - """ If a property of the handled feature has changed we have the chance to handle this here """ - return - - def getDisplayModes(self,obj): - ''' Return a list of display modes. ''' - modes=[] - return modes - - def getDefaultDisplayMode(self): - ''' Return the name of the default display mode. It must be defined in getDisplayModes. ''' - return "Flat Lines" - - def setDisplayMode(self,mode): - ''' Map the display mode defined in attach with those defined in getDisplayModes. - Since they have the same names nothing needs to be done. This method is optinal. - ''' - return mode - - def onChanged(self, vp, prop): - ''' Print the name of the property that has changed ''' - # FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n") - - def __getstate__(self): - ''' When saving the document this object gets stored using Python's cPickle module. - Since we have some un-pickable here -- the Coin stuff -- we must define this method - to return a tuple of all pickable objects or None. - ''' - return None - - def __setstate__(self,state): - ''' When restoring the pickled object from document we have the chance to set some - internals here. Since no data were pickled nothing needs to be done here. - ''' - return None - - def getIcon(self): - return """ - /* XPM */ - static char * Sim_xpm[] = { - "32 32 301 2", - " c None", - ". c #CCCCCC", - "+ c #A9A9A9", - "@ c #989898", - "# c #A1A1A1", - "$ c #C3C3C3", - "% c #C1C0C1", - "& c #BFBFBF", - "* c #A7A7A7", - "= c #808080", - "- c #5C5C5C", - "; c #565655", - "> c #4E4E4E", - ", c #676767", - "' c #898989", - ") c #B6B5B6", - "! c #BABABA", - "~ c #B9B9B9", - "{ c #A5A5A5", - "] c #7E7E7E", - "^ c #595A59", - "/ c #575656", - "( c #535353", - "_ c #505050", - ": c #4D4D4C", - "< c #474747", - "[ c #404040", - "} c #4D4D4D", - "| c #787878", - "1 c #B8B7B8", - "2 c #B6B6B6", - "3 c #888888", - "4 c #7C7C7C", - "5 c #575657", - "6 c #535354", - "7 c #4E4D4E", - "8 c #4A4A4A", - "9 c #444444", - "0 c #414141", - "a c #3E3E3E", - "b c #393938", - "c c #313131", - "d c #393939", - "e c #636363", - "f c #ABABAB", - "g c #B3B3B3", - "h c #848484", - "i c #787979", - "j c #545454", - "k c #515151", - "l c #4B4B4B", - "m c #484748", - "n c #3B3B3B", - "o c #383838", - "p c #353535", - "q c #323232", - "r c #2F2F2E", - "s c #2A2A2A", - "t c #222323", - "u c #252625", - "v c #AFAFAF", - "w c #767676", - "x c #484848", - "y c #454545", - "z c #424242", - "A c #3F3F3E", - "B c #3B3B3C", - "C c #393838", - "D c #2F2F2F", - "E c #2C2C2C", - "F c #292929", - "G c #262626", - "H c #222222", - "I c #1F1F20", - "J c #171716", - "K c #959595", - "L c #747474", - "M c #4E4E4F", - "N c #4C4B4C", - "O c #484849", - "P c #424243", - "Q c #282828", - "R c #525251", - "S c #373737", - "T c #353636", - "U c #333233", - "V c #30302F", - "W c #2C2D2D", - "X c #232323", - "Y c #201F20", - "Z c #1D1D1D", - "` c #151414", - " . c #717272", - ".. c #4C4C4C", - "+. c #484949", - "@. c #464545", - "#. c #424343", - "$. c #3A3A3A", - "%. c #5D4A49", - "&. c #7E7E86", - "*. c #56569F", - "=. c #3E3E41", - "-. c #757575", - ";. c #575757", - ">. c #222221", - ",. c #262627", - "'. c #242423", - "). c #212020", - "!. c #1A1A1A", - "~. c #121212", - "{. c #939493", - "]. c #6F6F6F", - "^. c #494949", - "/. c #464646", - "(. c #434343", - "_. c #554545", - ":. c #686863", - "<. c #939394", - "[. c #BDBDBD", - "}. c #202021", - "|. c #1E1E1E", - "1. c #171718", - "2. c #0F0F0F", - "3. c #929292", - "4. c #6C6D6D", - "5. c #464746", - "6. c #525F73", - "7. c #444648", - "8. c #3D3D3D", - "9. c #2D2C2A", - "0. c #A1A2A2", - "a. c #AAACAC", - "b. c #A6A7A7", - "c. c #A8AAAA", - "d. c #AFB0B0", - "e. c #777676", - "f. c #9A9A9A", - "g. c #1B1B1B", - "h. c #181818", - "i. c #0C0C0C", - "j. c #909090", - "k. c #6B6A6B", - "l. c #55657E", - "m. c #6990FB", - "n. c #6483CD", - "o. c #5871B2", - "p. c #434E7E", - "q. c #A97C76", - "r. c #AB7777", - "s. c #AC7070", - "t. c #A26565", - "u. c #805C5C", - "v. c #848686", - "w. c #424342", - "x. c #151515", - "y. c #0A0909", - "z. c #8F8F8F", - "A. c #676868", - "B. c #3B3A3A", - "C. c #383738", - "D. c #353534", - "E. c #45525F", - "F. c #6367AC", - "G. c #804682", - "H. c #942A39", - "I. c #991312", - "J. c #540901", - "K. c #393742", - "L. c #1C1C1C", - "M. c #191919", - "N. c #161515", - "O. c #121313", - "P. c #070707", - "Q. c #8D8E8D", - "R. c #656566", - "S. c #3E3F3F", - "T. c #2F2E2F", - "U. c #353838", - "V. c #35496A", - "W. c #3E4D88", - "X. c #354889", - "Y. c #5573D7", - "Z. c #5D80FB", - "`. c #374899", - " + c #293338", - ".+ c #101010", - "++ c #0D0D0D", - "@+ c #040404", - "#+ c #8C8C8C", - "$+ c #8B8B8B", - "%+ c #4B4A4B", - "&+ c #303030", - "*+ c #333232", - "=+ c #2F2F30", - "-+ c #232223", - ";+ c #1A1919", - ">+ c #2E3949", - ",+ c #5C7BA3", - "'+ c #36467D", - ")+ c #536F93", - "!+ c #0A0A0A", - "~+ c #010101", - "{+ c #C1C1C1", - "]+ c #B8B8B8", - "^+ c #A0A0A0", - "/+ c #3F3F3F", - "(+ c #222122", - "_+ c #202020", - ":+ c #161717", - "<+ c #141414", - "[+ c #111011", - "}+ c #0D0E0E", - "|+ c #0B0B0A", - "1+ c #000000", - "2+ c #525252", - "3+ c #686868", - "4+ c #ADADAD", - "5+ c #9E9F9F", - "6+ c #6D6D6D", - "7+ c #3C3C3C", - "8+ c #131414", - "9+ c #111111", - "0+ c #0E0E0E", - "a+ c #0B0B0B", - "b+ c #080708", - "c+ c #050504", - "d+ c #4C4D4C", - "e+ c #4D4C4D", - "f+ c #494A4A", - "g+ c #454444", - "h+ c #9D9D9D", - "i+ c #9E9E9E", - "j+ c #AEAEAE", - "k+ c #BEBEBF", - "l+ c #BEBDBD", - "m+ c #979797", - "n+ c #6A6B6A", - "o+ c #3F3F40", - "p+ c #020202", - "q+ c #030303", - "r+ c #878787", - "s+ c #69696A", - "t+ c #868685", - "u+ c #646464", - "v+ c #474647", - "w+ c #656565", - "x+ c #9E9F9E", - "y+ c #A8A8A8", - "z+ c #AFAFAE", - "A+ c #A4A4A4", - "B+ c #7A7A7A", - "C+ c #969696", - "D+ c #363636", - "E+ c #777776", - "F+ c #8C8D8D", - "G+ c #7D7D7D", - "H+ c #5E5E5E", - "I+ c #4F4F50", - "J+ c #808181", - "K+ c #707070", - "L+ c #909191", - "M+ c #9C9C9C", - "N+ c #787877", - "O+ c #696969", - "P+ c #616161", - "Q+ c #6E6E6E", - "R+ c #7C7B7C", - "S+ c #777677", - "T+ c #6F6E6E", - "U+ c #595959", - "V+ c #717171", - "W+ c #8D8D8D", - "X+ c #515051", - "Y+ c #49494A", - "Z+ c #4B4A4A", - "`+ c #606060", - " @ c #6A6A6A", - ".@ c #616162", - "+@ c #6C6D6C", - "@@ c #767777", - "#@ c #727272", - "$@ c #6B6B6B", - "%@ c #828283", - "&@ c #757475", - "*@ c #444545", - "=@ c #565656", - "-@ c #5A595A", - ";@ c #666666", - ">@ c #878687", - ",@ c #8A8A8A", - "'@ c #797979", - ")@ c #444344", - "!@ c #7F8080", - "~@ c #737373", - "{@ c #484747", - "]@ c #707170", - "^@ c #7F7F7F", - "/@ c #676867", - "(@ c #4D4C4C", - "_@ c #5F5F5F", - ":@ c #434444", - " ", - " ", - " . + ", - " @ # $ % & * ", - " = - ; > , ' ) ! ~ { ", - " ] ^ / ( _ : < [ } | # 1 2 # 3 ", - " 4 5 6 _ 7 8 < 9 0 a b c d e ' f g + h ", - " i j k 7 l m 9 0 a n o p q r s t u < | v ", - " w k > l x y z A B C p q D E F G H I J K ", - " L M N O y P Q R S T U V W F G X Y Z ` K ", - " ...+.@.#.$.%.&.*.=.-.;.>.,.'.).Z !.~.{. ", - " ].^./.(.[ c _._ :.<.[.$ ' /.}.|.!.1.2.3. ", - " 4.5.6.7.8.9.# 0.a.b.c.d.e.f.g.g.h.` i.j. ", - " k.9 l.m.n.o.p.q.r.s.t.u.v.w.g.h.x.~.y.z. ", - " A.0 a B.C.D.E.F.G.H.I.J.K.L.M.N.O.2.P.Q. ", - " R.S.n o p q T.E U.V.W.X.Y.Z.`. +.+++@+#+ ", - " $+%+&+q *+=+E F G -+I Z ;+>+,+'+)+!+~+$+ ", - " {+]+^+w /+H (+X _+Z !.:+<+[+}+|+P.1+' ", - " k 2+_ > 3+z.4+5+6+7+x.~.8+9+0+a+b+c+1+3 ", - " %+..d+e+..f+< g+h+i+j+k+l+m+n+o+P.p+q+p+1+r+ ", - " s+t+u+< (.< v+y 9 (.w+x+y+z+y+h+A+B+C+K ].D+1+h ", - " E+i+F+f.j.G+H+9 [ (.z I+J+m+f.j.K+z 9 9 9 K+L+r+/.9 (. ", - " L M+N+O+u+P+Q+R+S+T+U+y 8 - ;...9 9 9 9 9 9 9 9 (.(.k w+ ", - " V+m+' W+r+] , X+Y+(.: r+L P+k 9 z (.9 9 9 9 (.(.Z+;.- `+ ", - " ].C+w @u+.@+@@@#@$@j %@B+&@#@L $@H+2+/.0 (.*@+.} 2+=@-@ ", - " ;@| >@,@'@u+k 8 )@..!@| ~@V+#@#@#@#@L 6+..(.9 {@.._ ( ", - " e ]@^@] /@k G+w #@#@#@#@#@V+ @$@_ 9 9 9 /.Y+(@ ", - " - R.T+L ~@#@#@#@#@]._ _@_ 9 9 9 (.9 x ", - " =@_@O+L ~@#@~@L _ 9 9 :@ ", - " ;.H+ @-._ (. ", - " ", - " "}; - """ - -def FSMesh(obj, recompute=False): - """ Get free surface mesh in matrix mode. - @param obj Created Part::FeaturePython object. - @param recompute True if mesh must be recomputed, False otherwise. - @return Faces matrix - """ - nx = obj.FS_Nx - ny = obj.FS_Ny - if not recompute: - faces = [] - for i in range(0,nx): - faces.append([]) - for j in range(0,ny): - faces[i].append(FreeSurfaceFace(obj.FS_Position[j + i*ny], - obj.FS_Normal[j + i*ny], - obj.FS_Area[j + i*ny])) - return faces - # Transform positions into a mesh - pos = [] - for i in range(0,nx): - pos.append([]) - for j in range(0,ny): - pos[i].append(obj.FS_Position[j + i*ny]) - # Recompute normals and dimensions - normal = [] - l = [] - b = [] - for i in range(0,nx): - normal.append([]) - l.append([]) - b.append([]) - for j in range(0,ny): - i0 = i-1 - i1 = i+1 - fi = 1.0 - j0 = j-1 - j1 = j+1 - fj = 1.0 - if i == 0: - i0 = i - i1 = i+1 - fi = 2.0 - if i == nx-1: - i0 = i-1 - i1 = i - fi = 2.0 - if j == 0: - j0 = j - j1 = j+1 - fj = 2.0 - if j == ny-1: - j0 = j-1 - j1 = j - fj = 2.0 - l[i].append(fi*(obj.FS_Position[j + i1*ny].x - obj.FS_Position[j + i0*ny].x)) - b[i].append(fj*(obj.FS_Position[j1 + i*ny].y - obj.FS_Position[j0 + i*ny].y)) - xvec = Vector(obj.FS_Position[j + i1*ny].x - obj.FS_Position[j + i0*ny].x, - obj.FS_Position[j + i1*ny].y - obj.FS_Position[j + i0*ny].y, - obj.FS_Position[j + i1*ny].z - obj.FS_Position[j + i0*ny].z) - yvec = Vector(obj.FS_Position[j1 + i*ny].x - obj.FS_Position[j0 + i*ny].x, - obj.FS_Position[j1 + i*ny].y - obj.FS_Position[j0 + i*ny].y, - obj.FS_Position[j1 + i*ny].z - obj.FS_Position[j0 + i*ny].z) - n = Vector(xvec.cross(yvec)) # Z positive - normal[i].append(n.normalize()) - # Create faces - faces = [] - for i in range(0,nx): - faces.append([]) - for j in range(0,ny): - faces[i].append(FreeSurfaceFace(pos[i][j], normal[i][j], l[i][j], b[i][j])) - # Reconstruct mesh data - for i in range(0,nx): - for j in range(0,ny): - obj.FS_Position[j + i*ny] = faces[i][j].pos - obj.FS_Normal[j + i*ny] = faces[i][j].normal - obj.FS_Area[j + i*ny] = faces[i][j].area - return faces +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 * +#* * +#*************************************************************************** + +from math import * +import threading + +# COIN +from pivy.coin import * +from pivy import coin + +# FreeCAD +import FreeCAD,FreeCADGui +from FreeCAD import Base, Vector +import Part + +# Ship design module +from shipUtils import Paths, Translator, Math + +class FreeSurfaceFace: + def __init__(self, pos, normal, l, b): + """ Face storage. + @param pos Face position. + @param normal Face normal. + @param l Element length (distance between elements at x direction) + @param b Element beam (distance between elements at y direction) + """ + self.pos = pos + self.normal = normal + self.area = l*b + + def __init__(self, pos, normal, area): + """ Face storage. + @param pos Face position. + @param normal Face normal. + @param area Element area + """ + self.pos = pos + self.normal = normal + self.area = area + +class ShipSimulation: + def __init__(self, obj, fsMeshData, waves): + """ Creates a new simulation instance on active document. + @param obj Created Part::FeaturePython object. + @param fsMeshData [L,B,N] Free surface mesh data, with lenght + (x), Beam (y) and desired number of points. + @param waves [[A,T,phi,heading],] Waves involved + """ + # Add uniqueness property to identify Tank instances + obj.addProperty("App::PropertyBool","IsShipSimulation","ShipSimulation", str(Translator.translate("True if is a valid ship simulation instance"))).IsShipSimulation=True + # Compute free surface mesh + self.createFSMesh(obj,fsMeshData) + self.computeWaves(obj,waves) + # Store waves + obj.addProperty("App::PropertyVectorList","Waves","ShipSimulation", str(Translator.translate("Waves (Amplitude,period,phase)"))).Waves=[] + obj.addProperty("App::PropertyFloatList","Waves_Dir","ShipSimulation", str(Translator.translate("Waves direction (0 deg to stern waves)"))).Waves_Dir=[] + w = [] + d = [] + for i in range(0,len(waves)): + w.append(Vector(waves[i][0], waves[i][1], waves[i][2])) + d.append(waves[i][3]) + obj.Waves = w + obj.Waves_Dir = d + # Add shapes + shape = self.computeShape(obj) + if not shape: + obj.IsShipSimulation=False + return + obj.Shape = shape + obj.Proxy = self + + def onChanged(self, fp, prop): + """ Property changed, tank must be recomputed """ + if prop == "IsShipSimulation": + FreeCAD.Console.PrintWarning("Ussually you don't want to modify manually this option.\n") + + def execute(self, obj): + """ Shape recomputation called """ + obj.Shape = self.computeShape(obj) + + def createFSMesh(self, obj, fsMeshData): + """ Create or modify free surface mesh. + @param obj Created Part::FeaturePython object. + @param fsMeshData [L,B,N] Free surface mesh data, with lenght + (x), Beam (y) and desired number of points. + """ + # Study input object + try: + props = obj.PropertiesList + props.index("IsShipSimulation") + if not obj.IsShipSimulation: + msg = str(Translator.translate("Object is not a valid ship simulation.\n")) + FreeCAD.Console.PrintError(msg) + return + except ValueError: + msg = str(Translator.translate("Object is not a ship simulation.\n")) + FreeCAD.Console.PrintError(msg) + return + # Get areas and number of elements per direction + L = fsMeshData[0] + B = fsMeshData[1] + N = fsMeshData[2] + A = L*B + area = A/N + l = sqrt(area) + b = sqrt(area) + nx = int(round(L / l)) + ny = int(round(B / b)) + # Start data fields if not already exist + props = obj.PropertiesList + try: + props.index("FS_Nx") + except ValueError: + obj.addProperty("App::PropertyInteger","FS_Nx","ShipSimulation", str(Translator.translate("Free surface number of elements at x direction"))).FS_Nx=0 + try: + props.index("FS_Ny") + except ValueError: + obj.addProperty("App::PropertyInteger","FS_Ny","ShipSimulation", str(Translator.translate("Free surface number of elements at y direction"))).FS_Ny=0 + try: + props.index("FS_Position") + except ValueError: + obj.addProperty("App::PropertyVectorList","FS_Position","ShipSimulation", str(Translator.translate("Free surface elements position"))).FS_Position=[] + try: + props.index("FS_Area") + except ValueError: + obj.addProperty("App::PropertyFloatList","FS_Area","ShipSimulation", str(Translator.translate("Free surface elements area"))).FS_Area=[] + try: + props.index("FS_Normal") + except ValueError: + obj.addProperty("App::PropertyVectorList","FS_Normal","ShipSimulation", str(Translator.translate("Free surface elements normal"))).FS_Normal=[] + # Fill data + obj.FS_Nx = nx + obj.FS_Ny = ny + pos = [] + areas = [] + normal = [] + for i in range(0,nx): + for j in range(0,ny): + pos.append(Vector(-0.5*L + (i+0.5)*l,-0.5*B + (j+0.5)*b,0.0)) + areas.append(l*b) + normal.append(Vector(0.0,0.0,1.0)) + obj.FS_Position = pos[:] + obj.FS_Area = areas[:] + obj.FS_Normal = normal[:] + + def computeWaves(self, obj, waves): + """ Add waves effect to free surface mesh positions. + @param obj Created Part::FeaturePython object. + @param waves waves data [A,T,phase, heading]. + """ + grav = 9.81 + positions = obj.FS_Position[:] + for i in range(0, len(positions)): + for w in waves: + A = w[0] + T = w[1] + phase = w[2] + heading = pi*w[3]/180.0 + wl = 0.5 * grav / pi * T*T + k = 2.0*pi/wl + frec = 2.0*pi/T + pos = obj.FS_Position[i] + l = pos.x*cos(heading) + pos.y*sin(heading) + amp = A*sin(k*l + phase) + positions[i].z = positions[i].z + amp + obj.FS_Position = positions[:] + + def computeShape(self, obj): + """ Computes simulation involved shapes. + @param obj Created Part::FeaturePython object. + @return Shape + """ + nx = obj.FS_Nx + ny = obj.FS_Ny + mesh = FSMesh(obj) + # Create BSpline surface + surf = Part.BSplineSurface() + for i in range(1,nx-1): + u = i / float(nx-1) + surf.insertUKnot(u,i,0.000001) + for i in range(1,ny-1): + v = i / float(ny-1) + surf.insertVKnot(v,i,0.000001) + for i in range(0,nx): + for j in range(0,ny): + u = i / float(nx-1) + v = j / float(ny-1) + point = mesh[i][j].pos + surf.movePoint(u,v,point,i+1,i+1,j+1,j+1) + return surf.toShape() + +class ViewProviderShipSimulation: + def __init__(self, obj): + """ Set this object to the proxy object of the actual view provider """ + obj.Proxy = self + + def attach(self, obj): + """ Setup the scene sub-graph of the view provider, this method is mandatory """ + return + + def updateData(self, fp, prop): + """ If a property of the handled feature has changed we have the chance to handle this here """ + return + + def getDisplayModes(self,obj): + ''' Return a list of display modes. ''' + modes=[] + return modes + + def getDefaultDisplayMode(self): + ''' Return the name of the default display mode. It must be defined in getDisplayModes. ''' + return "Flat Lines" + + def setDisplayMode(self,mode): + ''' Map the display mode defined in attach with those defined in getDisplayModes. + Since they have the same names nothing needs to be done. This method is optinal. + ''' + return mode + + def onChanged(self, vp, prop): + ''' Print the name of the property that has changed ''' + # FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n") + + def __getstate__(self): + ''' When saving the document this object gets stored using Python's cPickle module. + Since we have some un-pickable here -- the Coin stuff -- we must define this method + to return a tuple of all pickable objects or None. + ''' + return None + + def __setstate__(self,state): + ''' When restoring the pickled object from document we have the chance to set some + internals here. Since no data were pickled nothing needs to be done here. + ''' + return None + + def getIcon(self): + return """ + /* XPM */ + static char * Sim_xpm[] = { + "32 32 301 2", + " c None", + ". c #CCCCCC", + "+ c #A9A9A9", + "@ c #989898", + "# c #A1A1A1", + "$ c #C3C3C3", + "% c #C1C0C1", + "& c #BFBFBF", + "* c #A7A7A7", + "= c #808080", + "- c #5C5C5C", + "; c #565655", + "> c #4E4E4E", + ", c #676767", + "' c #898989", + ") c #B6B5B6", + "! c #BABABA", + "~ c #B9B9B9", + "{ c #A5A5A5", + "] c #7E7E7E", + "^ c #595A59", + "/ c #575656", + "( c #535353", + "_ c #505050", + ": c #4D4D4C", + "< c #474747", + "[ c #404040", + "} c #4D4D4D", + "| c #787878", + "1 c #B8B7B8", + "2 c #B6B6B6", + "3 c #888888", + "4 c #7C7C7C", + "5 c #575657", + "6 c #535354", + "7 c #4E4D4E", + "8 c #4A4A4A", + "9 c #444444", + "0 c #414141", + "a c #3E3E3E", + "b c #393938", + "c c #313131", + "d c #393939", + "e c #636363", + "f c #ABABAB", + "g c #B3B3B3", + "h c #848484", + "i c #787979", + "j c #545454", + "k c #515151", + "l c #4B4B4B", + "m c #484748", + "n c #3B3B3B", + "o c #383838", + "p c #353535", + "q c #323232", + "r c #2F2F2E", + "s c #2A2A2A", + "t c #222323", + "u c #252625", + "v c #AFAFAF", + "w c #767676", + "x c #484848", + "y c #454545", + "z c #424242", + "A c #3F3F3E", + "B c #3B3B3C", + "C c #393838", + "D c #2F2F2F", + "E c #2C2C2C", + "F c #292929", + "G c #262626", + "H c #222222", + "I c #1F1F20", + "J c #171716", + "K c #959595", + "L c #747474", + "M c #4E4E4F", + "N c #4C4B4C", + "O c #484849", + "P c #424243", + "Q c #282828", + "R c #525251", + "S c #373737", + "T c #353636", + "U c #333233", + "V c #30302F", + "W c #2C2D2D", + "X c #232323", + "Y c #201F20", + "Z c #1D1D1D", + "` c #151414", + " . c #717272", + ".. c #4C4C4C", + "+. c #484949", + "@. c #464545", + "#. c #424343", + "$. c #3A3A3A", + "%. c #5D4A49", + "&. c #7E7E86", + "*. c #56569F", + "=. c #3E3E41", + "-. c #757575", + ";. c #575757", + ">. c #222221", + ",. c #262627", + "'. c #242423", + "). c #212020", + "!. c #1A1A1A", + "~. c #121212", + "{. c #939493", + "]. c #6F6F6F", + "^. c #494949", + "/. c #464646", + "(. c #434343", + "_. c #554545", + ":. c #686863", + "<. c #939394", + "[. c #BDBDBD", + "}. c #202021", + "|. c #1E1E1E", + "1. c #171718", + "2. c #0F0F0F", + "3. c #929292", + "4. c #6C6D6D", + "5. c #464746", + "6. c #525F73", + "7. c #444648", + "8. c #3D3D3D", + "9. c #2D2C2A", + "0. c #A1A2A2", + "a. c #AAACAC", + "b. c #A6A7A7", + "c. c #A8AAAA", + "d. c #AFB0B0", + "e. c #777676", + "f. c #9A9A9A", + "g. c #1B1B1B", + "h. c #181818", + "i. c #0C0C0C", + "j. c #909090", + "k. c #6B6A6B", + "l. c #55657E", + "m. c #6990FB", + "n. c #6483CD", + "o. c #5871B2", + "p. c #434E7E", + "q. c #A97C76", + "r. c #AB7777", + "s. c #AC7070", + "t. c #A26565", + "u. c #805C5C", + "v. c #848686", + "w. c #424342", + "x. c #151515", + "y. c #0A0909", + "z. c #8F8F8F", + "A. c #676868", + "B. c #3B3A3A", + "C. c #383738", + "D. c #353534", + "E. c #45525F", + "F. c #6367AC", + "G. c #804682", + "H. c #942A39", + "I. c #991312", + "J. c #540901", + "K. c #393742", + "L. c #1C1C1C", + "M. c #191919", + "N. c #161515", + "O. c #121313", + "P. c #070707", + "Q. c #8D8E8D", + "R. c #656566", + "S. c #3E3F3F", + "T. c #2F2E2F", + "U. c #353838", + "V. c #35496A", + "W. c #3E4D88", + "X. c #354889", + "Y. c #5573D7", + "Z. c #5D80FB", + "`. c #374899", + " + c #293338", + ".+ c #101010", + "++ c #0D0D0D", + "@+ c #040404", + "#+ c #8C8C8C", + "$+ c #8B8B8B", + "%+ c #4B4A4B", + "&+ c #303030", + "*+ c #333232", + "=+ c #2F2F30", + "-+ c #232223", + ";+ c #1A1919", + ">+ c #2E3949", + ",+ c #5C7BA3", + "'+ c #36467D", + ")+ c #536F93", + "!+ c #0A0A0A", + "~+ c #010101", + "{+ c #C1C1C1", + "]+ c #B8B8B8", + "^+ c #A0A0A0", + "/+ c #3F3F3F", + "(+ c #222122", + "_+ c #202020", + ":+ c #161717", + "<+ c #141414", + "[+ c #111011", + "}+ c #0D0E0E", + "|+ c #0B0B0A", + "1+ c #000000", + "2+ c #525252", + "3+ c #686868", + "4+ c #ADADAD", + "5+ c #9E9F9F", + "6+ c #6D6D6D", + "7+ c #3C3C3C", + "8+ c #131414", + "9+ c #111111", + "0+ c #0E0E0E", + "a+ c #0B0B0B", + "b+ c #080708", + "c+ c #050504", + "d+ c #4C4D4C", + "e+ c #4D4C4D", + "f+ c #494A4A", + "g+ c #454444", + "h+ c #9D9D9D", + "i+ c #9E9E9E", + "j+ c #AEAEAE", + "k+ c #BEBEBF", + "l+ c #BEBDBD", + "m+ c #979797", + "n+ c #6A6B6A", + "o+ c #3F3F40", + "p+ c #020202", + "q+ c #030303", + "r+ c #878787", + "s+ c #69696A", + "t+ c #868685", + "u+ c #646464", + "v+ c #474647", + "w+ c #656565", + "x+ c #9E9F9E", + "y+ c #A8A8A8", + "z+ c #AFAFAE", + "A+ c #A4A4A4", + "B+ c #7A7A7A", + "C+ c #969696", + "D+ c #363636", + "E+ c #777776", + "F+ c #8C8D8D", + "G+ c #7D7D7D", + "H+ c #5E5E5E", + "I+ c #4F4F50", + "J+ c #808181", + "K+ c #707070", + "L+ c #909191", + "M+ c #9C9C9C", + "N+ c #787877", + "O+ c #696969", + "P+ c #616161", + "Q+ c #6E6E6E", + "R+ c #7C7B7C", + "S+ c #777677", + "T+ c #6F6E6E", + "U+ c #595959", + "V+ c #717171", + "W+ c #8D8D8D", + "X+ c #515051", + "Y+ c #49494A", + "Z+ c #4B4A4A", + "`+ c #606060", + " @ c #6A6A6A", + ".@ c #616162", + "+@ c #6C6D6C", + "@@ c #767777", + "#@ c #727272", + "$@ c #6B6B6B", + "%@ c #828283", + "&@ c #757475", + "*@ c #444545", + "=@ c #565656", + "-@ c #5A595A", + ";@ c #666666", + ">@ c #878687", + ",@ c #8A8A8A", + "'@ c #797979", + ")@ c #444344", + "!@ c #7F8080", + "~@ c #737373", + "{@ c #484747", + "]@ c #707170", + "^@ c #7F7F7F", + "/@ c #676867", + "(@ c #4D4C4C", + "_@ c #5F5F5F", + ":@ c #434444", + " ", + " ", + " . + ", + " @ # $ % & * ", + " = - ; > , ' ) ! ~ { ", + " ] ^ / ( _ : < [ } | # 1 2 # 3 ", + " 4 5 6 _ 7 8 < 9 0 a b c d e ' f g + h ", + " i j k 7 l m 9 0 a n o p q r s t u < | v ", + " w k > l x y z A B C p q D E F G H I J K ", + " L M N O y P Q R S T U V W F G X Y Z ` K ", + " ...+.@.#.$.%.&.*.=.-.;.>.,.'.).Z !.~.{. ", + " ].^./.(.[ c _._ :.<.[.$ ' /.}.|.!.1.2.3. ", + " 4.5.6.7.8.9.# 0.a.b.c.d.e.f.g.g.h.` i.j. ", + " k.9 l.m.n.o.p.q.r.s.t.u.v.w.g.h.x.~.y.z. ", + " A.0 a B.C.D.E.F.G.H.I.J.K.L.M.N.O.2.P.Q. ", + " R.S.n o p q T.E U.V.W.X.Y.Z.`. +.+++@+#+ ", + " $+%+&+q *+=+E F G -+I Z ;+>+,+'+)+!+~+$+ ", + " {+]+^+w /+H (+X _+Z !.:+<+[+}+|+P.1+' ", + " k 2+_ > 3+z.4+5+6+7+x.~.8+9+0+a+b+c+1+3 ", + " %+..d+e+..f+< g+h+i+j+k+l+m+n+o+P.p+q+p+1+r+ ", + " s+t+u+< (.< v+y 9 (.w+x+y+z+y+h+A+B+C+K ].D+1+h ", + " E+i+F+f.j.G+H+9 [ (.z I+J+m+f.j.K+z 9 9 9 K+L+r+/.9 (. ", + " L M+N+O+u+P+Q+R+S+T+U+y 8 - ;...9 9 9 9 9 9 9 9 (.(.k w+ ", + " V+m+' W+r+] , X+Y+(.: r+L P+k 9 z (.9 9 9 9 (.(.Z+;.- `+ ", + " ].C+w @u+.@+@@@#@$@j %@B+&@#@L $@H+2+/.0 (.*@+.} 2+=@-@ ", + " ;@| >@,@'@u+k 8 )@..!@| ~@V+#@#@#@#@L 6+..(.9 {@.._ ( ", + " e ]@^@] /@k G+w #@#@#@#@#@V+ @$@_ 9 9 9 /.Y+(@ ", + " - R.T+L ~@#@#@#@#@]._ _@_ 9 9 9 (.9 x ", + " =@_@O+L ~@#@~@L _ 9 9 :@ ", + " ;.H+ @-._ (. ", + " ", + " "}; + """ + +def FSMesh(obj, recompute=False): + """ Get free surface mesh in matrix mode. + @param obj Created Part::FeaturePython object. + @param recompute True if mesh must be recomputed, False otherwise. + @return Faces matrix + """ + nx = obj.FS_Nx + ny = obj.FS_Ny + if not recompute: + faces = [] + for i in range(0,nx): + faces.append([]) + for j in range(0,ny): + faces[i].append(FreeSurfaceFace(obj.FS_Position[j + i*ny], + obj.FS_Normal[j + i*ny], + obj.FS_Area[j + i*ny])) + return faces + # Transform positions into a mesh + pos = [] + for i in range(0,nx): + pos.append([]) + for j in range(0,ny): + pos[i].append(obj.FS_Position[j + i*ny]) + # Recompute normals and dimensions + normal = [] + l = [] + b = [] + for i in range(0,nx): + normal.append([]) + l.append([]) + b.append([]) + for j in range(0,ny): + i0 = i-1 + i1 = i+1 + fi = 1.0 + j0 = j-1 + j1 = j+1 + fj = 1.0 + if i == 0: + i0 = i + i1 = i+1 + fi = 2.0 + if i == nx-1: + i0 = i-1 + i1 = i + fi = 2.0 + if j == 0: + j0 = j + j1 = j+1 + fj = 2.0 + if j == ny-1: + j0 = j-1 + j1 = j + fj = 2.0 + l[i].append(fi*(obj.FS_Position[j + i1*ny].x - obj.FS_Position[j + i0*ny].x)) + b[i].append(fj*(obj.FS_Position[j1 + i*ny].y - obj.FS_Position[j0 + i*ny].y)) + xvec = Vector(obj.FS_Position[j + i1*ny].x - obj.FS_Position[j + i0*ny].x, + obj.FS_Position[j + i1*ny].y - obj.FS_Position[j + i0*ny].y, + obj.FS_Position[j + i1*ny].z - obj.FS_Position[j + i0*ny].z) + yvec = Vector(obj.FS_Position[j1 + i*ny].x - obj.FS_Position[j0 + i*ny].x, + obj.FS_Position[j1 + i*ny].y - obj.FS_Position[j0 + i*ny].y, + obj.FS_Position[j1 + i*ny].z - obj.FS_Position[j0 + i*ny].z) + n = Vector(xvec.cross(yvec)) # Z positive + normal[i].append(n.normalize()) + # Create faces + faces = [] + for i in range(0,nx): + faces.append([]) + for j in range(0,ny): + faces[i].append(FreeSurfaceFace(pos[i][j], normal[i][j], l[i][j], b[i][j])) + # Reconstruct mesh data + for i in range(0,nx): + for j in range(0,ny): + obj.FS_Position[j + i*ny] = faces[i][j].pos + obj.FS_Normal[j + i*ny] = faces[i][j].normal + obj.FS_Area[j + i*ny] = faces[i][j].area + return faces diff --git a/src/Mod/Ship/shipAreasCurve/TaskPanel.py b/src/Mod/Ship/shipAreasCurve/TaskPanel.py index 01389551a..e027f5f9e 100644 --- a/src/Mod/Ship/shipAreasCurve/TaskPanel.py +++ b/src/Mod/Ship/shipAreasCurve/TaskPanel.py @@ -31,7 +31,6 @@ from PyQt4 import QtGui,QtCore import Preview, Plot import Instance from shipUtils import Paths, Translator -from surfUtils import Geometry from shipHydrostatics import Tools as Hydrostatics class TaskPanel: @@ -114,7 +113,7 @@ class TaskPanel: """ Set initial values for fields """ # Get objects - selObjs = Geometry.getSelectedObjs() + selObjs = Gui.Selection.getSelection() if not selObjs: msg = Translator.translate("Ship instance must be selected (no object selected)\n") App.Console.PrintError(msg) diff --git a/src/Mod/Ship/shipLoadExample/TaskPanel.py b/src/Mod/Ship/shipLoadExample/TaskPanel.py index 2ab325d7d..b325a9236 100644 --- a/src/Mod/Ship/shipLoadExample/TaskPanel.py +++ b/src/Mod/Ship/shipLoadExample/TaskPanel.py @@ -28,7 +28,6 @@ import FreeCADGui as Gui from PyQt4 import QtGui,QtCore # Module from shipUtils import Paths, Translator -from surfUtils import Geometry class TaskPanel: def __init__(self): diff --git a/src/Mod/Ship/shipOutlineDraw/Plot.py b/src/Mod/Ship/shipOutlineDraw/Plot.py index 682c15678..004ab9b40 100644 --- a/src/Mod/Ship/shipOutlineDraw/Plot.py +++ b/src/Mod/Ship/shipOutlineDraw/Plot.py @@ -27,7 +27,6 @@ from FreeCAD import Base, Vector import Part # FreeCADShip modules from shipUtils import Paths, Translator -from surfUtils import Geometry def Plot(scale, sections, shape): """ Creates the outline draw. @@ -52,7 +51,7 @@ def Plot(scale, sections, shape): x0 = xMid - 0.5*xTot y0 = 297.0 - yMid - 0.5*yTot # 297 = A3_width # Get border - edges = Geometry.getEdges([shape]) + edges = self.getEdges([shape]) border = edges[0] for i in range(0,len(edges)): border = border.oldFuse(edges[i]) # Only group objects, don't try to build more complex entities @@ -95,3 +94,31 @@ def Plot(scale, sections, shape): FreeCAD.ActiveDocument.OutlineDrawPlot.addObject(FreeCAD.ActiveDocument.OutlineDrawUpView) FreeCAD.ActiveDocument.recompute() return obj + +def getEdges(self, objs=None): + """ Returns object edges (list of them) + @param objs Object to get the faces, none if selected + object may used. + @return Selected edges. None if errors happens + """ + edges = [] + if not objs: + objs = FreeCADGui.Selection.getSelection() + if not objs: + return None + for i in range(0, len(objs)): + obj = objs[i] + if obj.isDerivedFrom('Part::Feature'): + # get shape + shape = obj.Shape + if not shape: + return None + obj = shape + if not obj.isDerivedFrom('Part::TopoShape'): + return None + objEdges = obj.Edges + if not objEdges: + continue + for j in range(0, len(objEdges)): + edges.append(objEdges[j]) + return edges diff --git a/src/Mod/Ship/shipOutlineDraw/TaskPanel.py b/src/Mod/Ship/shipOutlineDraw/TaskPanel.py index 834738a0c..c49abcd0d 100644 --- a/src/Mod/Ship/shipOutlineDraw/TaskPanel.py +++ b/src/Mod/Ship/shipOutlineDraw/TaskPanel.py @@ -30,7 +30,6 @@ from PyQt4 import QtGui,QtCore import Preview, Plot import Instance from shipUtils import Paths, Translator -from surfUtils import Geometry class TaskPanel: def __init__(self): @@ -116,7 +115,7 @@ class TaskPanel: """ Set initial values for fields """ # Get selected objects - selObjs = Geometry.getSelectedObjs() + selObjs = Gui.Selection.getSelection() if not selObjs: msg = Translator.translate("Ship instance must be selected (no object selected)\n") App.Console.PrintError(msg) diff --git a/src/Mod/Ship/simCreate/TaskPanel.py b/src/Mod/Ship/simCreate/TaskPanel.py index e14f4c964..38ea00b96 100644 --- a/src/Mod/Ship/simCreate/TaskPanel.py +++ b/src/Mod/Ship/simCreate/TaskPanel.py @@ -1,174 +1,177 @@ -#*************************************************************************** -#* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * -#* * -#* 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 modules -import FreeCAD as App -import FreeCADGui as Gui -# Qt library -from PyQt4 import QtGui,QtCore -# Module -import SimInstance -from shipUtils import Paths, Translator - -class TaskPanel: - def __init__(self): - self.ui = Paths.modulePath() + "/simCreate/TaskPanel.ui" - - def accept(self): - form = self.form - # Read waves data - w = [] - for i in range(0,form.waves.rowCount() - 1): - item = form.waves.item(i,0) - A = item.text().toFloat()[0] - item = form.waves.item(i,1) - T = item.text().toFloat()[0] - item = form.waves.item(i,2) - phi = item.text().toFloat()[0] - item = form.waves.item(i,3) - head = item.text().toFloat()[0] - w.append([A,T,phi,head]) - obj = App.ActiveDocument.addObject("Part::FeaturePython","ShipSimulation") - sim = SimInstance.ShipSimulation(obj, - [form.length.value(), form.beam.value(), form.n.value()], - w) - SimInstance.ViewProviderShipSimulation(obj.ViewObject) - return True - - def reject(self): - return True - - def clicked(self, index): - pass - - def open(self): - pass - - def needsFullSpace(self): - return True - - def isAllowedAlterSelection(self): - return False - - def isAllowedAlterView(self): - return True - - def isAllowedAlterDocument(self): - return False - - def helpRequested(self): - pass - - def setupUi(self): - mw = self.getMainWindow() - form = mw.findChild(QtGui.QWidget, "TaskPanel") - form.length = form.findChild(QtGui.QDoubleSpinBox, "Length") - form.beam = form.findChild(QtGui.QDoubleSpinBox, "Beam") - form.n = form.findChild(QtGui.QSpinBox, "N") - form.waves = form.findChild(QtGui.QTableWidget, "Waves") - self.form = form - # Initial values - if self.initValues(): - return True - self.retranslateUi() - # Connect Signals and Slots - QtCore.QObject.connect(form.length, QtCore.SIGNAL("valueChanged(double)"), self.onFS) - QtCore.QObject.connect(form.beam, QtCore.SIGNAL("valueChanged(double)"), self.onFS) - QtCore.QObject.connect(form.n, QtCore.SIGNAL("valueChanged(int)"), self.onFS) - QtCore.QObject.connect(form.waves,QtCore.SIGNAL("cellChanged(int,int)"),self.onWaves); - - def getMainWindow(self): - "returns the main window" - # using QtGui.qApp.activeWindow() isn't very reliable because if another - # widget than the mainwindow is active (e.g. a dialog) the wrong widget is - # returned - toplevel = QtGui.qApp.topLevelWidgets() - for i in toplevel: - if i.metaObject().className() == "Gui::MainWindow": - return i - raise Exception("No main window found") - - def initValues(self): - """ Set initial values for fields - """ - msg = Translator.translate("Ready to work\n") - App.Console.PrintMessage(msg) - return False - - def retranslateUi(self): - """ Set user interface locale strings. - """ - self.form.setWindowTitle(Translator.translate("Create a new ship simulation")) - self.form.findChild(QtGui.QGroupBox, "FSDataBox").setTitle(Translator.translate("Free surface")) - self.form.findChild(QtGui.QLabel, "LengthLabel").setText(Translator.translate("Length")) - self.form.findChild(QtGui.QLabel, "BeamLabel").setText(Translator.translate("Beam")) - self.form.findChild(QtGui.QLabel, "NLabel").setText(Translator.translate("Number of points")) - self.form.findChild(QtGui.QGroupBox, "WavesDataBox").setTitle(Translator.translate("Waves")) - labels = [] - labels.append(Translator.translate("Amplitude") + " [m]") - labels.append(Translator.translate("Period") + " [s]") - labels.append(Translator.translate("Phase") + " [rad]") - labels.append(Translator.translate("Heading") + " [deg]") - self.form.waves.setHorizontalHeaderLabels(labels) - - def onFS(self, value): - """ Method called when free surface data is changed. - @param value Changed value. - """ - pass - - def onWaves(self, row, column): - """ Method called when waves data is changed. - @param row Affected row. - @param col Affected column. - """ - item = self.form.waves.item(row,column) - # Row deletion - if column == 0: - if not item.text(): - self.form.waves.removeRow(row) - # Ensure that exist one empty item at the end - nRow = self.form.waves.rowCount() - last = self.form.waves.item(nRow-1,0) - if last: - if(last.text() != ''): - self.form.waves.setRowCount(nRow+1) - # Fields must be numbers - for i in range(0,self.form.waves.rowCount()-1): # Avoid last row - for j in range(0,self.form.waves.columnCount()): # Avoid name column - item = self.form.waves.item(i,j) - if not item: - item = QtGui.QTableWidgetItem('0.0') - self.form.waves.setItem(i,j,item) - continue - (number,flag) = item.text().toFloat() - if not flag: - item.setText('0.0') - -def createTask(): - panel = TaskPanel() - Gui.Control.showDialog(panel) - if panel.setupUi(): - Gui.Control.closeDialog(panel) - return None - return panel +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 modules +import FreeCAD as App +import FreeCADGui as Gui +# Qt library +from PyQt4 import QtGui,QtCore +# Module +import SimInstance +from shipUtils import Paths, Translator + +class TaskPanel: + def __init__(self): + self.ui = Paths.modulePath() + "/simCreate/TaskPanel.ui" + + def accept(self): + form = self.form + # Read waves data + w = [] + for i in range(0,form.waves.rowCount() - 1): + item = form.waves.item(i,0) + A = item.text().toFloat()[0] + item = form.waves.item(i,1) + T = item.text().toFloat()[0] + item = form.waves.item(i,2) + phi = item.text().toFloat()[0] + item = form.waves.item(i,3) + head = item.text().toFloat()[0] + w.append([A,T,phi,head]) + obj = App.ActiveDocument.addObject("Part::FeaturePython","ShipSimulation") + sim = SimInstance.ShipSimulation(obj, + [form.length.value(), form.beam.value(), form.n.value()], + w) + SimInstance.ViewProviderShipSimulation(obj.ViewObject) + return True + + def reject(self): + return True + + def clicked(self, index): + pass + + def open(self): + pass + + def needsFullSpace(self): + return True + + def isAllowedAlterSelection(self): + return False + + def isAllowedAlterView(self): + return True + + def isAllowedAlterDocument(self): + return False + + def helpRequested(self): + pass + + def setupUi(self): + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.length = form.findChild(QtGui.QDoubleSpinBox, "Length") + form.beam = form.findChild(QtGui.QDoubleSpinBox, "Beam") + form.n = form.findChild(QtGui.QSpinBox, "N") + form.waves = form.findChild(QtGui.QTableWidget, "Waves") + self.form = form + # Initial values + if self.initValues(): + return True + self.retranslateUi() + # Connect Signals and Slots + QtCore.QObject.connect(form.length, QtCore.SIGNAL("valueChanged(double)"), self.onFS) + QtCore.QObject.connect(form.beam, QtCore.SIGNAL("valueChanged(double)"), self.onFS) + QtCore.QObject.connect(form.n, QtCore.SIGNAL("valueChanged(int)"), self.onFS) + QtCore.QObject.connect(form.waves,QtCore.SIGNAL("cellChanged(int,int)"),self.onWaves); + + def getMainWindow(self): + "returns the main window" + # using QtGui.qApp.activeWindow() isn't very reliable because if another + # widget than the mainwindow is active (e.g. a dialog) the wrong widget is + # returned + toplevel = QtGui.qApp.topLevelWidgets() + for i in toplevel: + if i.metaObject().className() == "Gui::MainWindow": + return i + raise Exception("No main window found") + + def initValues(self): + """ Set initial values for fields + """ + msg = Translator.translate("Ready to work\n") + App.Console.PrintMessage(msg) + return False + + def retranslateUi(self): + """ Set user interface locale strings. + """ + self.form.setWindowTitle(Translator.translate("Create a new ship simulation")) + self.form.findChild(QtGui.QGroupBox, "FSDataBox").setTitle(Translator.translate("Free surface")) + self.form.findChild(QtGui.QLabel, "LengthLabel").setText(Translator.translate("Length")) + self.form.findChild(QtGui.QLabel, "BeamLabel").setText(Translator.translate("Beam")) + self.form.findChild(QtGui.QLabel, "NLabel").setText(Translator.translate("Number of points")) + self.form.findChild(QtGui.QGroupBox, "WavesDataBox").setTitle(Translator.translate("Waves")) + labels = [] + labels.append(Translator.translate("Amplitude") + " [m]") + labels.append(Translator.translate("Period") + " [s]") + labels.append(Translator.translate("Phase") + " [rad]") + labels.append(Translator.translate("Heading") + " [deg]") + self.form.waves.setHorizontalHeaderLabels(labels) + + def onFS(self, value): + """ Method called when free surface data is changed. + @param value Changed value. + """ + pass + + def onWaves(self, row, column): + """ Method called when waves data is changed. + @param row Affected row. + @param col Affected column. + """ + item = self.form.waves.item(row,column) + # Row deletion + if column == 0: + if not item.text(): + self.form.waves.removeRow(row) + # Ensure that exist one empty item at the end + nRow = self.form.waves.rowCount() + if not nRow: + self.form.waves.setRowCount(1) + else: + last = self.form.waves.item(nRow-1,0) + if last: + if(last.text() != ''): + self.form.waves.setRowCount(nRow+1) + # Fields must be numbers + for i in range(0,self.form.waves.rowCount()-1): # Avoid last row + for j in range(0,self.form.waves.columnCount()): # Avoid name column + item = self.form.waves.item(i,j) + if not item: + item = QtGui.QTableWidgetItem('0.0') + self.form.waves.setItem(i,j,item) + continue + (number,flag) = item.text().toFloat() + if not flag: + item.setText('0.0') + +def createTask(): + panel = TaskPanel() + Gui.Control.showDialog(panel) + if panel.setupUi(): + Gui.Control.closeDialog(panel) + return None + return panel diff --git a/src/Mod/Ship/simPost/TaskPanel.py b/src/Mod/Ship/simPost/TaskPanel.py new file mode 100644 index 000000000..9c6ca53c3 --- /dev/null +++ b/src/Mod/Ship/simPost/TaskPanel.py @@ -0,0 +1,156 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 modules +import FreeCAD as App +import FreeCADGui as Gui +# Qt library +from PyQt4 import QtGui,QtCore +# pyOpenCL +import pyopencl as cl +# Module +import SimInstance +from shipUtils import Paths, Translator +from simRun import Simulation +Sim = Simulation.FreeCADShipSimulation +# from Simulation import FreeCADShipSimulation as Sim + +class TaskPanel: + def __init__(self): + self.ui = Paths.modulePath() + "/simPost/TaskPanel.ui" + + def accept(self): + return True + + def reject(self): + return True + + def clicked(self, index): + pass + + def open(self): + pass + + def needsFullSpace(self): + return True + + def isAllowedAlterSelection(self): + return False + + def isAllowedAlterView(self): + return True + + def isAllowedAlterDocument(self): + return False + + def helpRequested(self): + pass + + def setupUi(self): + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.time = form.findChild(QtGui.QLabel, "TimeLabel") + form.first = form.findChild(QtGui.QPushButton, "First") + form.prev = form.findChild(QtGui.QPushButton, "Prev") + form.now = form.findChild(QtGui.QPushButton, "Now") + form.next = form.findChild(QtGui.QPushButton, "Next") + form.last = form.findChild(QtGui.QPushButton, "Last") + self.form = form + # Initial values + if self.initValues(): + return True + self.retranslateUi() + # Connect Signals and Slots + QtCore.QObject.connect(form.first, QtCore.SIGNAL("pressed()"), self.onFirst) + QtCore.QObject.connect(form.prev, QtCore.SIGNAL("pressed()"), self.onPrev) + QtCore.QObject.connect(form.now, QtCore.SIGNAL("pressed()"), self.onNow) + QtCore.QObject.connect(form.next, QtCore.SIGNAL("pressed()"), self.onNext) + QtCore.QObject.connect(form.last, QtCore.SIGNAL("pressed()"), self.onLast) + + def getMainWindow(self): + "returns the main window" + # using QtGui.qApp.activeWindow() isn't very reliable because if another + # widget than the mainwindow is active (e.g. a dialog) the wrong widget is + # returned + toplevel = QtGui.qApp.topLevelWidgets() + for i in toplevel: + if i.metaObject().className() == "Gui::MainWindow": + return i + raise Exception("No main window found") + + def initValues(self): + """ Set initial values for fields + """ + msg = Translator.translate("Ready to work\n") + App.Console.PrintMessage(msg) + return False + + def retranslateUi(self): + """ Set user interface locale strings. + """ + self.form.setWindowTitle(Translator.translate("Track simulation")) + self.form.findChild(QtGui.QPushButton, "Now").setText(Translator.translate("Now")) + + def onFirst(self): + """ Called when first frame button is pressed. + """ + + def onPrev(self): + """ Called when previous frame button is pressed. + """ + + def onNow(self): + """ Called when actual frame button is pressed. + """ + sim = Sim() + pos = sim.sim.FS_Position[:] + nx = sim.FS['Nx'] + ny = sim.FS['Ny'] + for i in range(0, nx): + for j in range(0, ny): + pos[i*ny+j].z = float(sim.FS['pos'][i,j][2]) + sim.sim.FS_Position = pos[:] + App.ActiveDocument.recompute() + self.form.time.setText("t = %g s" % (sim.t)) + + def onNext(self): + """ Called when next frame button is pressed. + """ + + def onLast(self): + """ Called when last frame button is pressed. + """ + +def createTask(): + try: + simulator = Sim() + except: + msg = Translator.translate("Can't find any active simulation!\n") + App.Console.PrintError(msg) + return + panel = TaskPanel() + Gui.Control.showDialog(panel) + if panel.setupUi(): + Gui.Control.closeDialog(panel) + return None + return panel diff --git a/src/Mod/Ship/simPost/TaskPanel.ui b/src/Mod/Ship/simPost/TaskPanel.ui new file mode 100644 index 000000000..dd43f4c9d --- /dev/null +++ b/src/Mod/Ship/simPost/TaskPanel.ui @@ -0,0 +1,81 @@ + + + TaskPanel + + + + 0 + 0 + 300 + 102 + + + + + 0 + 1 + + + + + 0 + 100 + + + + + 300 + 16777215 + + + + Track simulation + + + + + + |< + + + + + + + < + + + + + + + > + + + + + + + >| + + + + + + + Now + + + + + + + t = 0 s + + + + + + + + diff --git a/src/Mod/Ship/simPost/__init__.py b/src/Mod/Ship/simPost/__init__.py new file mode 100644 index 000000000..64c597c02 --- /dev/null +++ b/src/Mod/Ship/simPost/__init__.py @@ -0,0 +1,40 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 modules +import FreeCAD +import FreeCADGui + +# Qt libraries +from PyQt4 import QtGui,QtCore + +# Main object +import TaskPanel + +def load(): + """ Loads the tool """ + TaskPanel.createTask() + +def stop(): + """ Stops the simulation """ + TaskPanel.stopSimulation() diff --git a/src/Mod/Ship/simRun/Sim/__init__.py b/src/Mod/Ship/simRun/Sim/__init__.py index f5acc886b..aabf4a621 100644 --- a/src/Mod/Ship/simRun/Sim/__init__.py +++ b/src/Mod/Ship/simRun/Sim/__init__.py @@ -21,4 +21,7 @@ #* * #*************************************************************************** -import initialization +from initialization import * +from matrixGen import * +from computeSources import * +from fsEvolution import * diff --git a/src/Mod/Ship/simRun/Sim/computeSources.py b/src/Mod/Ship/simRun/Sim/computeSources.py new file mode 100644 index 000000000..fb57daa4e --- /dev/null +++ b/src/Mod/Ship/simRun/Sim/computeSources.py @@ -0,0 +1,69 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 * +#* * +#*************************************************************************** + +# numpy +import numpy as np + +grav=9.81 + +class simComputeSources: + def __init__(self, context=None, queue=None): + """ Constructor. + @param context OpenCL context where apply. Only for compatibility, + must be None. + @param queue OpenCL command queue. Only for compatibility, + must be None. + """ + self.context = context + self.queue = queue + + def execute(self, fs, A): + """ Compute potential sources (for velocity potential and + acceleration potential). + @param fs Free surface instance. + @param A Linear system matrix. + """ + self.fs = fs + # Allocate memory + nx = self.fs['Nx'] + ny = self.fs['Ny'] + nF = nx*ny + nB = 0 # No body for the moment + N = nx*ny + nB + b = np.ndarray(N, dtype=np.float32) + bb = np.ndarray(N, dtype=np.float32) + s = np.ndarray(N, dtype=np.float32) + ss = np.ndarray(N, dtype=np.float32) + # Create independent terms + for i in range(0,nx): + for j in range(0,ny): + b[i*ny+j] = self.fs['velPot'][i,j] + bb[i*ny+j] = self.fs['accPot'][i,j] + # Solve systems + s = np.linalg.solve(A, b) + ss = np.linalg.solve(A, bb) + # Store sources + for i in range(0,nx): + for j in range(0,ny): + self.fs['velSrc'][i,j] = s[i*ny+j] + self.fs['accSrc'][i,j] = ss[i*ny+j] diff --git a/src/Mod/Ship/simRun/Sim/fsEvolution.py b/src/Mod/Ship/simRun/Sim/fsEvolution.py new file mode 100644 index 000000000..14fdf4ba3 --- /dev/null +++ b/src/Mod/Ship/simRun/Sim/fsEvolution.py @@ -0,0 +1,177 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 * +#* * +#*************************************************************************** + +# numpy +import numpy as np + +grav=9.81 + +class simFSEvolution: + def __init__(self, context=None, queue=None): + """ Constructor. + @param context OpenCL context where apply. Only for compatibility, + must be None. + @param queue OpenCL command queue. Only for compatibility, + must be None. + """ + self.context = context + self.queue = queue + + def execute(self, fs, waves, dt, t): + """ Compute free surface for next time step. + @param fs Free surface instance. + @param waves Waves instance. + @param dt Time step. + @param t Actual time (without adding dt). + """ + self.fs = fs + nx = self.fs['Nx'] + ny = self.fs['Ny'] + nF = nx*ny + grad = self.evaluateGradient() + # In order to improve results in really long simulations free surface + # will performed considering external waves and second order effects + # in two different ways. First external waves at time t will be + # substracted, then second order waves will be computed, and finally + # external waves at t+dt will be added. + for i in range(0,nx): + for j in range(0,ny): + pos = np.copy(self.fs['pos'][i,j]) + # Substract external waves at time t. + for w in waves['data']: + A = w[0] + T = w[1] + phase = w[2] + heading = np.pi*w[3]/180.0 + wl = 0.5 * grav / np.pi * T*T + k = 2.0*np.pi/wl + frec = 2.0*np.pi/T + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + amp = A*np.sin(k*l - frec*t + phase) + pos[2] = pos[2] - amp + amp = - grav/frec*A*np.sin(k*l - frec*t + phase) + self.fs['velPot'][i,j] = self.fs['velPot'][i,j] - amp + amp = grav*A*np.cos(k*l - frec*t + phase) + self.fs['accPot'][i,j] = self.fs['accPot'][i,j] - amp + # Now compute second order waves using position copy, + # where external waves are excluded, in order impose + # free surface boundary condition relative to second + # order phenomena. + self.fs['velPot'][i,j] = self.fs['velPot'][i,j] + \ + dt*self.fs['accPot'][i,j] + # self.fs['accPot'][i,j] = self.fs['accPot'][i,j] + \ + # grav*pos[2] + # Restore external waves to velocity and acceleration + # potentials. + for w in waves['data']: + A = w[0] + T = w[1] + phase = w[2] + heading = np.pi*w[3]/180.0 + wl = 0.5 * grav / np.pi * T*T + k = 2.0*np.pi/wl + frec = 2.0*np.pi/T + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + amp = - grav/frec*A*np.sin(k*l - frec*(t+dt) + phase) + self.fs['velPot'][i,j] = self.fs['velPot'][i,j] + amp + amp = grav*A*np.cos(k*l - frec*(t+dt) + phase) + self.fs['accPot'][i,j] = self.fs['accPot'][i,j] + amp + # Update free surface point position + gradVal = np.dot(np.abs(grad[i*ny+j]),grad[i*ny+j]) + gradVal = np.copysign(np.sqrt(np.abs(gradVal)), gradVal) + self.fs['pos'][i,j][2] = self.fs['pos'][i,j][2] + dt*gradVal + # Impose values at beach (far free surface) + for i in range(0,nx): + for j in [0,ny-1]: + self.beach(i,j, waves, dt, t) + for j in range(0,ny): + for i in [0,nx-1]: + self.beach(i,j, waves, dt, t) + + def evaluateGradient(self): + """ Evaluate potential gradients over free surface. + @return Potential gradients. + """ + nx = self.fs['Nx'] + ny = self.fs['Ny'] + nF = nx*ny + grad = np.ndarray((nF,3), dtype=np.float32) + for i in range(0,nx): + for j in range(0,ny): + pos = self.fs['pos'][i,j] + grad[i*ny+j] = self.gradientphi(pos) + gradVal = np.dot(np.abs(grad[i*ny+j]),grad[i*ny+j]) + gradVal = np.copysign(np.sqrt(np.abs(gradVal)), gradVal) + return grad + + def gradientphi(self, pos): + """ Compute gradient over desired position. + @param pos Point to evaluate. + @return Potential gradient. + """ + nx = self.fs['Nx'] + ny = self.fs['Ny'] + grad = np.zeros(3, dtype=np.float32) + for i in range(0,nx): + for j in range(0,ny): + # Get source position (desingularized) + srcPos = np.copy(self.fs['pos'][i,j]) + area = self.fs['area'][i,j] + srcPos[2] = srcPos[2] + np.sqrt(area) + src = self.fs['velSrc'][i,j] + # Get distance between points + d = pos-srcPos + grad = grad + d/np.dot(d,d)*src*area + # Discard Z induced effect by desingularization + grad[2] = 0. + return grad + + def beach(self, i,j, waves, dt, t): + """ Compute far free surface where only + incident waves can be taken into account. + @param i First free surface cell index. + @param j Second free surface cell index. + @param waves Waves instance. + @param dt Time step. + @param t Actual time (without adding dt). + """ + pos = self.fs['pos'][i,j] + pos[2] = 0. + self.fs['velPot'][i,j] = 0. + self.fs['accPot'][i,j] = 0. + for w in waves['data']: + A = w[0] + T = w[1] + phase = w[2] + heading = np.pi*w[3]/180.0 + wl = 0.5 * grav / np.pi * T*T + k = 2.0*np.pi/wl + frec = 2.0*np.pi/T + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + amp = A*np.sin(k*l - frec*(t+dt) + phase) + self.fs['pos'][i,j][2] = self.fs['pos'][i,j][2] + amp + amp = - grav/frec*A*np.sin(k*l - frec*(t+dt) + phase) + self.fs['velPot'][i,j] = self.fs['velPot'][i,j] + amp + amp = grav*A*np.cos(k*l - frec*(t+dt) + phase) + self.fs['accPot'][i,j] = self.fs['accPot'][i,j] + amp + \ No newline at end of file diff --git a/src/Mod/Ship/simRun/Sim/initialization.py b/src/Mod/Ship/simRun/Sim/initialization.py index 1c443ca85..e89192c14 100644 --- a/src/Mod/Ship/simRun/Sim/initialization.py +++ b/src/Mod/Ship/simRun/Sim/initialization.py @@ -26,9 +26,9 @@ import numpy as np grav=9.81 -class perform: +class simInitialization: def __init__(self, FSmesh, waves, context=None, queue=None): - """ Constructor, includes program loading. + """ Constructor. @param FSmesh Initial free surface mesh. @param waves Considered simulation waves (A,T,phi,heading). @param context OpenCL context where apply. Only for compatibility, @@ -40,6 +40,11 @@ class perform: self.queue = queue self.loadData(FSmesh, waves) self.execute() + # Compute time step + self.dt = 0.1 + for w in self.waves['data']: + if(self.dt > w[1]/200.0): + self.dt = w[1]/200.0 def loadData(self, FSmesh, waves): """ Convert data to numpy format. @@ -51,12 +56,12 @@ class perform: nW = len(waves) # Mesh data p = np.ndarray((nx,ny, 3), dtype=np.float32) - v = np.ndarray((nx,ny, 3), dtype=np.float32) - f = np.ndarray((nx,ny, 3), dtype=np.float32) n = np.ndarray((nx,ny, 3), dtype=np.float32) - a = np.ndarray((nx,ny, 1), dtype=np.float32) - phi = np.ndarray((nx,ny, 1), dtype=np.float32) - Phi = np.ndarray((nx,ny, 1), dtype=np.float32) + a = np.ndarray((nx,ny), dtype=np.float32) + phi = np.ndarray((nx,ny), dtype=np.float32) + Phi = np.ndarray((nx,ny), dtype=np.float32) + s = np.ndarray((nx,ny), dtype=np.float32) + ss = np.ndarray((nx,ny), dtype=np.float32) for i in range(0, nx): for j in range(0, ny): pos = FSmesh[i][j].pos @@ -65,18 +70,16 @@ class perform: p[i,j,0] = pos.x p[i,j,1] = pos.y p[i,j,2] = pos.z - v[i,j,0] = 0. - v[i,j,1] = 0. - v[i,j,2] = 0. - f[i,j,0] = 0. - f[i,j,1] = 0. - f[i,j,2] = 0. n[i,j,0] = normal.x n[i,j,1] = normal.y n[i,j,2] = normal.z a[i,j] = area - self.fs = {'Nx':nx, 'Ny':ny, 'pos':p, 'vel':v, 'acc':f, \ - 'normal':n, 'area':a, 'velPot':phi, 'accPot':Phi} + phi[i,j] = 0. + Phi[i,j] = 0. + s[i,j] = 0. + ss[i,j] = 0. + self.fs = {'Nx':nx, 'Ny':ny, 'pos':p, 'normal':n, 'area':a, \ + 'velPot':phi, 'accPot':Phi, 'velSrc':s, 'accSrc':ss} # Waves data w = np.ndarray((nW, 4), dtype=np.float32) for i in range(0,nW): @@ -85,6 +88,11 @@ class perform: w[i,2] = waves[i][2] w[i,3] = waves[i][3] self.waves = {'N':nW, 'data':w} + # Linear system matrix + nF = nx*ny + nB = 0 # No body for the moment + N = nx*ny + nB + self.A = np.ndarray((N, N), dtype=np.float32) def execute(self): """ Compute initial conditions. """ @@ -92,6 +100,7 @@ class perform: ny = self.fs['Ny'] for i in range(0,nx): for j in range(0,ny): + self.fs['pos'][i,j][2] = 0. for w in self.waves['data']: A = w[0] T = w[1] @@ -104,11 +113,7 @@ class perform: l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) amp = A*np.sin(k*l + phase) self.fs['pos'][i,j][2] = self.fs['pos'][i,j][2] + amp - amp = frec*A*np.cos(k*l + phase) - self.fs['vel'][i,j][2] = self.fs['vel'][i,j][2] - amp - amp = frec*frec*A*np.sin(k*l + phase) - self.fs['acc'][i,j][2] = self.fs['acc'][i,j][2] - amp - amp = grav/frec*A*np.sin(k*l + phase) + amp = - grav/frec*A*np.sin(k*l + phase) self.fs['velPot'][i,j] = self.fs['velPot'][i,j] + amp amp = grav*A*np.cos(k*l + phase) self.fs['accPot'][i,j] = self.fs['accPot'][i,j] + amp diff --git a/src/Mod/Ship/simRun/Sim/matrixGen.py b/src/Mod/Ship/simRun/Sim/matrixGen.py new file mode 100644 index 000000000..4eab537bc --- /dev/null +++ b/src/Mod/Ship/simRun/Sim/matrixGen.py @@ -0,0 +1,79 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 * +#* * +#*************************************************************************** + +# numpy +import numpy as np + +grav=9.81 + +class simMatrixGen: + def __init__(self, context=None, queue=None): + """ Constructor. + @param context OpenCL context where apply. Only for compatibility, + must be None. + @param queue OpenCL command queue. Only for compatibility, + must be None. + """ + self.context = context + self.queue = queue + + def execute(self, fs, A): + """ Compute system matrix. + @param fs Free surface instance. + @param A Linear system matrix. + """ + self.fs = fs + nx = self.fs['Nx'] + ny = self.fs['Ny'] + nF = nx*ny + nB = 0 # No body for the moment + N = nx*ny + nB + # Fluid sources rows + for i in range(0,nx): + for j in range(0,ny): + # Append fluid effect + pos = self.fs['pos'][i,j] + A[i*ny+j,0:nF] = self.fluidEffect(pos) + # Append body effect + # ... + + def fluidEffect(self, pos): + """ Compute fluid effect terms over desired position. Desingularized + sources must taken into account. + @param pos Point to evaluate. + @return Fluid effect row. + """ + nx = self.fs['Nx'] + ny = self.fs['Ny'] + nF = nx*ny + row = np.ndarray(nF, dtype=np.float32) + for i in range(0,nx): + for j in range(0,ny): + # Get source position (desingularized) + source = np.copy(self.fs['pos'][i,j]) + area = self.fs['area'][i,j] + source[2] = source[2] + np.sqrt(area) + # Get distance between points + d = np.linalg.norm(pos-source) + row[i*ny+j] = np.log(d)*area + return row \ No newline at end of file diff --git a/src/Mod/Ship/simRun/Simulation.py b/src/Mod/Ship/simRun/Simulation.py index a06f6b0d2..aa8373df8 100644 --- a/src/Mod/Ship/simRun/Simulation.py +++ b/src/Mod/Ship/simRun/Simulation.py @@ -21,7 +21,6 @@ #* * #*************************************************************************** -import time from math import * import threading @@ -49,11 +48,12 @@ class Singleton(type): class FreeCADShipSimulation(threading.Thread): __metaclass__ = Singleton - def __init__ (self, device, endTime, output, FSmesh, waves): + def __init__ (self, device, endTime, output, simInstance, FSmesh, waves): """ Thread constructor. @param device Device to use. @param endTime Maximum simulation time. @param output [Rate,Type] Output rate, Type=0 if FPS, 1 if IPF. + @param simInstance Simulaation instance. @param FSmesh Free surface mesh faces. @param waves Waves parameters (A,T,phi,heading) """ @@ -71,6 +71,7 @@ class FreeCADShipSimulation(threading.Thread): # Storage data self.endTime = endTime self.output = output + self.sim = simInstance self.FSmesh = FSmesh self.waves = waves @@ -80,19 +81,37 @@ class FreeCADShipSimulation(threading.Thread): self.active = True # Simulation stuff if self.device == None: - from Sim import initialization + from Sim import * else: - from clSim import initialization - msg = Translator.translate("\t[Sim]: Initializating OpenCL...\n") + from clSim import * + msg = Translator.translate("\t[Sim]: Initializating...\n") FreeCAD.Console.PrintMessage(msg) - init = initialization.perform(self.FSmesh,self.waves,self.context,self.queue) - msg = Translator.translate("\t[Sim]: Iterating (outputs will be noticed)...\n") + init = simInitialization(self.FSmesh,self.waves,self.context,self.queue) + matGen = simMatrixGen(self.context,self.queue) + solver = simComputeSources(self.context,self.queue) + fsEvol = simFSEvolution(self.context,self.queue) + A = init.A + FS = init.fs + waves = init.waves + dt = init.dt + self.t = 0.0 + self.FS = FS + nx = FS['Nx'] + ny = FS['Ny'] + msg = Translator.translate("\t[Sim]: Iterating...\n") FreeCAD.Console.PrintMessage(msg) - while self.active: - print("Im thread, Im running...") - time.sleep(1) - # ... - print("Im thread, step done!") + while self.active and self.t < self.endTime: + msg = Translator.translate("\t\t[Sim]: Generating linear system matrix...\n") + FreeCAD.Console.PrintMessage(msg) + matGen.execute(FS, A) + msg = Translator.translate("\t\t[Sim]: Solving linear systems...\n") + FreeCAD.Console.PrintMessage(msg) + solver.execute(FS, A) + msg = Translator.translate("\t\t[Sim]: Time integrating...\n") + FreeCAD.Console.PrintMessage(msg) + fsEvol.execute(FS, waves, dt, self.t) + self.t = self.t + dt + FreeCAD.Console.PrintMessage('t = %g s\n' % (self.t)) # Set thread as stopped (and prepare it to restarting) self.active = False threading.Event().set() diff --git a/src/Mod/Ship/simRun/TaskPanel.py b/src/Mod/Ship/simRun/TaskPanel.py index d2c34b8b7..58faa2b2d 100644 --- a/src/Mod/Ship/simRun/TaskPanel.py +++ b/src/Mod/Ship/simRun/TaskPanel.py @@ -69,7 +69,7 @@ class TaskPanel: msg = Translator.translate("Launching simulation...\n") App.Console.PrintMessage(msg) # Build simulation thread - simulator = Sim(device, endTime, output, FSMesh, waves) + simulator = Sim(device, endTime, output, self.sim, FSMesh, waves) simulator.start() msg = Translator.translate("Done!\n") App.Console.PrintMessage(msg) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 82813a607..1c2bd9a33 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -1350,6 +1350,8 @@ void SketchObject::rebuildExternalGeometry(void) break; } } + + rebuildVertexIndex(); } std::vector SketchObject::getCompleteGeometry(void) const @@ -1491,8 +1493,6 @@ void SketchObject::Restore(XMLReader &reader) { // read the father classes Part::Part2DObject::Restore(reader); - Constraints.acceptGeometry(getCompleteGeometry()); - rebuildVertexIndex(); } void SketchObject::onChanged(const App::Property* prop) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index fd795eb93..1eaa0cd99 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -1636,15 +1636,7 @@ void CmdSketcherConstrainAngle::activated(int iMsg) const std::vector &ConStr = dynamic_cast(selection[0].getObject())->Constraints.getValues(); Sketcher::Constraint *constr = ConStr[ConStr.size() -1]; - float sf = 1.f; - Gui::Document *doc = getActiveGuiDocument(); - if (doc && doc->getInEdit() && doc->getInEdit()->isDerivedFrom(SketcherGui::ViewProviderSketch::getClassTypeId())) { - SketcherGui::ViewProviderSketch *vp = dynamic_cast(doc->getInEdit()); - sf = vp->getScaleFactor(); - - constr->LabelDistance = 2. * sf; - vp->draw(); // Redraw - } + updateDatumDistance(getActiveGuiDocument(), constr); //updateActive(); getSelection().clearSelection(); diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index eb0aa74fe..3822e1214 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -25,6 +25,7 @@ #ifndef _PreComp_ #endif +#include #include #include @@ -142,15 +143,20 @@ public: virtual void mouseMove(Base::Vector2D onSketchPos) { - setPositionText(onSketchPos); - if (Mode==STATUS_SEEK_First) { + setPositionText(onSketchPos); if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) { renderSuggestConstraintsCursor(sugConstr1); return; } } else if (Mode==STATUS_SEEK_Second){ + float length = (onSketchPos - EditCurve[0]).Length(); + float angle = (onSketchPos - EditCurve[0]).GetAngle(Base::Vector2D(1.f,0.f)); + SbString text; + text.sprintf(" (%.1f,%.1fdeg)", length, angle * 180 / M_PI); + setPositionText(onSketchPos, text); + EditCurve[1] = onSketchPos; sketchgui->drawEdit(EditCurve); if (seekAutoConstraint(sugConstr2, onSketchPos, onSketchPos - EditCurve[0])) { @@ -301,15 +307,21 @@ public: virtual void mouseMove(Base::Vector2D onSketchPos) { - setPositionText(onSketchPos); if (Mode==STATUS_SEEK_First) { + setPositionText(onSketchPos); if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) { renderSuggestConstraintsCursor(sugConstr1); return; } } else if (Mode==STATUS_SEEK_Second) { + float dx = onSketchPos.fX - EditCurve[0].fX; + float dy = onSketchPos.fY - EditCurve[0].fY; + SbString text; + text.sprintf(" (%.1f x %.1f)", dx, dy); + setPositionText(onSketchPos, text); + EditCurve[2] = onSketchPos; EditCurve[1] = Base::Vector2D(onSketchPos.fX ,EditCurve[0].fY); EditCurve[3] = Base::Vector2D(EditCurve[0].fX,onSketchPos.fY); @@ -488,50 +500,106 @@ class DrawSketchHandlerLineSet: public DrawSketchHandler { public: DrawSketchHandlerLineSet() - : Mode(STATUS_SEEK_First),LineMode(LINE_MODE_Line),EditCurve(2), - firstVertex(-1),firstCurve(-1),previousCurve(-1),previousPosId(-1), - isTangent(false) {} + : Mode(STATUS_SEEK_First),SegmentMode(SEGMENT_MODE_Line), + TransitionMode(TRANSITION_MODE_Free),suppressTransition(false),EditCurve(2), + firstVertex(-1),firstCurve(-1),previousCurve(-1),previousPosId(Sketcher::none) {} virtual ~DrawSketchHandlerLineSet() {} /// mode table - enum SelectMode { + enum SELECT_MODE { STATUS_SEEK_First, /**< enum value ----. */ STATUS_SEEK_Second, /**< enum value ----. */ STATUS_Do, STATUS_Close }; - enum SelectLineMode + enum SEGMENT_MODE { - LINE_MODE_Arc, - LINE_MODE_Line + SEGMENT_MODE_Arc, + SEGMENT_MODE_Line + }; + + enum TRANSITION_MODE + { + TRANSITION_MODE_Free, + TRANSITION_MODE_Tangent, + TRANSITION_MODE_Perpendicular_L, + TRANSITION_MODE_Perpendicular_R }; virtual void registerPressedKey(bool pressed, int key) { - if (key == SoKeyboardEvent::A && pressed && previousCurve != -1) { - if (LineMode != LINE_MODE_Arc) { - Base::Vector2D onSketchPos = EditCurve[isTangent ? 2 : 1]; - LineMode = LINE_MODE_Arc; - if (previousCurve != -1) - isTangent = true; - else - isTangent = false; - EditCurve.resize(32); - mouseMove(onSketchPos); // trigger an update of EditCurve + if (Mode != STATUS_SEEK_Second) + return; // SegmentMode can be changed only in STATUS_SEEK_Second mode + + if (key == SoKeyboardEvent::M && pressed && previousCurve != -1) { + // loop through the following modes: + // SEGMENT_MODE_Line, TRANSITION_MODE_Free / TRANSITION_MODE_Tangent + // SEGMENT_MODE_Line, TRANSITION_MODE_Perpendicular_L + // SEGMENT_MODE_Line, TRANSITION_MODE_Tangent / TRANSITION_MODE_Free + // SEGMENT_MODE_Arc, TRANSITION_MODE_Tangent + // SEGMENT_MODE_Arc, TRANSITION_MODE_Perpendicular_L + // SEGMENT_MODE_Arc, TRANSITION_MODE_Perpendicular_R + + Base::Vector2D onSketchPos; + if (SegmentMode == SEGMENT_MODE_Line) + onSketchPos = EditCurve[EditCurve.size()-1]; + else + onSketchPos = EditCurve[29]; + + const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(previousCurve); + + if (SegmentMode == SEGMENT_MODE_Line) { + switch (TransitionMode) { + case TRANSITION_MODE_Free: + if (geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { // 3rd mode + SegmentMode = SEGMENT_MODE_Arc; + TransitionMode = TRANSITION_MODE_Tangent; + } + else // 1st mode + TransitionMode = TRANSITION_MODE_Perpendicular_L; + break; + case TRANSITION_MODE_Perpendicular_L: // 2nd mode + if (geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) + TransitionMode = TRANSITION_MODE_Free; + else + TransitionMode = TRANSITION_MODE_Tangent; + break; + case TRANSITION_MODE_Tangent: + if (geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) // 1st mode + TransitionMode = TRANSITION_MODE_Perpendicular_L; + else { // 3rd mode + SegmentMode = SEGMENT_MODE_Arc; + TransitionMode = TRANSITION_MODE_Tangent; + } + break; + default: // unexpected mode + TransitionMode = TRANSITION_MODE_Free; + break; + } } else { - Base::Vector2D onSketchPos = EditCurve[29]; - LineMode = LINE_MODE_Line; - if (previousCurve != -1) { - const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(previousCurve); - if (geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) - isTangent = true; - else - isTangent = false; + switch (TransitionMode) { + case TRANSITION_MODE_Tangent: // 4th mode + TransitionMode = TRANSITION_MODE_Perpendicular_L; + break; + case TRANSITION_MODE_Perpendicular_L: // 5th mode + TransitionMode = TRANSITION_MODE_Perpendicular_R; + break; + default: // 6th mode (Perpendicular_R) + unexpexted mode + SegmentMode = SEGMENT_MODE_Line; + if (geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) + TransitionMode = TRANSITION_MODE_Tangent; + else + TransitionMode = TRANSITION_MODE_Free; + break; } - EditCurve.resize(isTangent ? 3 : 2); - mouseMove(onSketchPos); // trigger an update of EditCurve } + + if (SegmentMode == SEGMENT_MODE_Line) + EditCurve.resize(TransitionMode == TRANSITION_MODE_Free ? 2 : 3); + else + EditCurve.resize(32); + mouseMove(onSketchPos); // trigger an update of EditCurve } } @@ -542,31 +610,59 @@ public: virtual void mouseMove(Base::Vector2D onSketchPos) { - setPositionText(onSketchPos); + suppressTransition = false; if (Mode==STATUS_SEEK_First) { + setPositionText(onSketchPos); if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) { renderSuggestConstraintsCursor(sugConstr1); return; } } else if (Mode==STATUS_SEEK_Second){ - if (LineMode == LINE_MODE_Line) { - EditCurve[isTangent ? 2 : 1] = onSketchPos; - if (isTangent) { + if (SegmentMode == SEGMENT_MODE_Line) { + EditCurve[EditCurve.size()-1] = onSketchPos; + if (TransitionMode == TRANSITION_MODE_Tangent) { Base::Vector2D Tangent(dirVec.x,dirVec.y); EditCurve[1].ProjToLine(EditCurve[2] - EditCurve[0], Tangent); + if (EditCurve[1] * Tangent < 0) { + EditCurve[1] = EditCurve[2]; + suppressTransition = true; + } + else + EditCurve[1] = EditCurve[0] + EditCurve[1]; + } + else if (TransitionMode == TRANSITION_MODE_Perpendicular_L || + TransitionMode == TRANSITION_MODE_Perpendicular_R) { + Base::Vector2D Perpendicular(-dirVec.y,dirVec.x); + EditCurve[1].ProjToLine(EditCurve[2] - EditCurve[0], Perpendicular); EditCurve[1] = EditCurve[0] + EditCurve[1]; } + sketchgui->drawEdit(EditCurve); - if (!isTangent) { + + float length = (EditCurve[1] - EditCurve[0]).Length(); + float angle = (EditCurve[1] - EditCurve[0]).GetAngle(Base::Vector2D(1.f,0.f)); + + SbString text; + text.sprintf(" (%.1f,%.1fdeg)", length, angle * 180 / M_PI); + setPositionText(EditCurve[1], text); + + if (TransitionMode == TRANSITION_MODE_Free) { if (seekAutoConstraint(sugConstr2, onSketchPos, onSketchPos - EditCurve[0])) { renderSuggestConstraintsCursor(sugConstr2); return; } } } - else if (LineMode == LINE_MODE_Arc) { - Base::Vector2D Tangent(dirVec.x,dirVec.y); + else if (SegmentMode == SEGMENT_MODE_Arc) { + Base::Vector2D Tangent; + if (TransitionMode == TRANSITION_MODE_Tangent) + Tangent = Base::Vector2D(dirVec.x,dirVec.y); + else if (TransitionMode == TRANSITION_MODE_Perpendicular_L) + Tangent = Base::Vector2D(-dirVec.y,dirVec.x); + else if (TransitionMode == TRANSITION_MODE_Perpendicular_R) + Tangent = Base::Vector2D(dirVec.y,-dirVec.x); + float theta = Tangent.GetAngle(onSketchPos - EditCurve[0]); arcRadius = (onSketchPos - EditCurve[0]).Length()/(2.0*sin(theta)); // At this point we need a unit normal vector pointing torwards @@ -580,11 +676,10 @@ public: float y3 = onSketchPos.fY; if ((x2*y3-x3*y2)-(x1*y3-x3*y1)+(x1*y2-x2*y1) > 0) arcRadius *= -1; + if (boost::math::isnan(arcRadius) || boost::math::isinf(arcRadius)) + arcRadius = 0.f; - Base::Vector3d centerVec = dirVec % Base::Vector3d(0.f,0.f,1.0); - centerVec.Normalize(); // this step should actually be redundant - - CenterPoint = EditCurve[0] + Base::Vector2D(arcRadius * centerVec.x, arcRadius * centerVec.y); + CenterPoint = EditCurve[0] + Base::Vector2D(arcRadius * Tangent.fY, -arcRadius * Tangent.fX); float rx = EditCurve[0].fX - CenterPoint.fX; float ry = EditCurve[0].fY - CenterPoint.fY; @@ -594,6 +689,8 @@ public: float rxe = onSketchPos.fX - CenterPoint.fX; float rye = onSketchPos.fY - CenterPoint.fY; float arcAngle = atan2(-rxe*ry + rye*rx, rxe*rx + rye*ry); + if (boost::math::isnan(arcAngle) || boost::math::isinf(arcAngle)) + arcAngle = 0.f; if (arcRadius >= 0 && arcAngle > 0) arcAngle -= 2*M_PI; if (arcRadius < 0 && arcAngle < 0) @@ -611,6 +708,11 @@ public: EditCurve[31] = EditCurve[0]; sketchgui->drawEdit(EditCurve); + + SbString text; + text.sprintf(" (%.1fR,%.1fdeg)", std::abs(arcRadius), arcAngle * 180 / M_PI); + setPositionText(onSketchPos, text); + if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f))) { renderSuggestConstraintsCursor(sugConstr2); return; @@ -622,35 +724,45 @@ public: virtual bool pressButton(Base::Vector2D onSketchPos) { - if (Mode==STATUS_SEEK_First) { - // remember our first point - firstVertex = getHighestVertexIndex() + 1; - firstCurve = getHighestCurveIndex() + 1; - // TODO: here we should check if there is a preselected point - // and set up a transition from the neighbouring segment. - // (peviousCurve, previousPosId, dirVec, isTangent) - // in that case we should set firstCurve and firstVertex to -1 - // in order to disable closing the wire - if (LineMode == LINE_MODE_Line) - EditCurve.resize(isTangent ? 3 : 2); - else if (LineMode == LINE_MODE_Arc) + if (Mode == STATUS_SEEK_First) { + + EditCurve[0] = onSketchPos; // this may be overwritten if previousCurve is found + + // here we check if there is a preselected point and + // we set up a transition from the neighbouring segment. + // (peviousCurve, previousPosId, dirVec, TransitionMode) + for (int i=0; i < sugConstr1.size(); i++) + if (sugConstr1[i].Type == Sketcher::Coincident) { + const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(sugConstr1[i].GeoId); + if ((geom->getTypeId() == Part::GeomLineSegment::getClassTypeId() || + geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) && + (sugConstr1[i].PosId == Sketcher::start || + sugConstr1[i].PosId == Sketcher::end)) { + previousCurve = sugConstr1[i].GeoId; + previousPosId = sugConstr1[i].PosId; + updateTransitionData(previousCurve,previousPosId); // -> dirVec, EditMode[0] + if (geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) + TransitionMode = TRANSITION_MODE_Tangent; + sugConstr1.erase(sugConstr1.begin()+i); // actually we should clear the vector completely + break; + } + } + + // in case a transition is set up, firstCurve and firstVertex should + // remain set to -1 in order to disable closing the wire + if (previousCurve == -1) { + // remember our first point + firstVertex = getHighestVertexIndex() + 1; + firstCurve = getHighestCurveIndex() + 1; + } + + if (SegmentMode == SEGMENT_MODE_Line) + EditCurve.resize(TransitionMode == TRANSITION_MODE_Free ? 2 : 3); + else if (SegmentMode == SEGMENT_MODE_Arc) EditCurve.resize(32); - EditCurve[0] = onSketchPos; Mode = STATUS_SEEK_Second; } - else if (Mode==STATUS_SEEK_Second) { - if (LineMode == LINE_MODE_Line) { - EditCurve[isTangent ? 2 : 1] = onSketchPos; - if (isTangent) { - Base::Vector2D Tangent(dirVec.x,dirVec.y); - EditCurve[1].ProjToLine(EditCurve[2] - EditCurve[0], Tangent); - EditCurve[1] = EditCurve[0] + EditCurve[1]; - } - } - else if (LineMode == LINE_MODE_Arc) - EditCurve[29] = onSketchPos; // not so important - sketchgui->drawEdit(EditCurve); - applyCursor(); + else if (Mode == STATUS_SEEK_Second) { // exit on clicking exactly at the same position (e.g. double click) if (onSketchPos == EditCurve[0]) { unsetCursor(); @@ -659,7 +771,7 @@ public: sketchgui->drawEdit(EditCurve); sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider } - if (sketchgui->getPreselectPoint() == firstVertex) + if (sketchgui->getPreselectPoint() == firstVertex && firstVertex != -1) Mode = STATUS_Close; else Mode = STATUS_Do; @@ -671,7 +783,7 @@ public: { if (Mode == STATUS_Do || Mode == STATUS_Close) { - if (LineMode == LINE_MODE_Line) { + if (SegmentMode == SEGMENT_MODE_Line) { // open the transaction Gui::Command::openCommand("Add line to sketch wire"); // issue the geometry @@ -680,7 +792,11 @@ public: sketchgui->getObject()->getNameInDocument(), EditCurve[0].fX,EditCurve[0].fY,EditCurve[1].fX,EditCurve[1].fY); } - else if (LineMode == LINE_MODE_Arc) { // We're dealing with an Arc + else if (SegmentMode == SEGMENT_MODE_Arc) { // We're dealing with an Arc + if (!boost::math::isnormal(arcRadius)) { + Mode = STATUS_SEEK_Second; + return true; + } Gui::Command::openCommand("Add arc to sketch wire"); Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.addGeometry(Part.ArcOfCircle" @@ -691,15 +807,24 @@ public: } // issue the constraint if (previousCurve != -1) { - int lastCurve = previousCurve+1; - int lastStartPosId = (LineMode == LINE_MODE_Arc && startAngle > endAngle) ? 2 : 1; - int lastEndPosId = (LineMode == LINE_MODE_Arc && startAngle > endAngle) ? 1 : 2; - // in case of a tangency constraint, the coincident constraint is redundant + int lastCurve = getHighestCurveIndex(); + Sketcher::PointPos lastStartPosId = (SegmentMode == SEGMENT_MODE_Arc && startAngle > endAngle) ? + Sketcher::end : Sketcher::start; + Sketcher::PointPos lastEndPosId = (SegmentMode == SEGMENT_MODE_Arc && startAngle > endAngle) ? + Sketcher::start : Sketcher::end; + // in case of a tangency constraint, the coincident constraint is redundant + std::string constrType = "Coincident"; + if (!suppressTransition) { + if (TransitionMode == TRANSITION_MODE_Tangent) + constrType = "Tangent"; + else if (TransitionMode == TRANSITION_MODE_Perpendicular_L || + TransitionMode == TRANSITION_MODE_Perpendicular_R) + constrType = "Perpendicular"; + } Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('%s',%i,%i,%i,%i)) ", - sketchgui->getObject()->getNameInDocument(), - isTangent ? "Tangent" : "Coincident", - previousCurve, previousPosId /* == 2 */, lastCurve, lastStartPosId); + sketchgui->getObject()->getNameInDocument(), constrType.c_str(), + previousCurve, previousPosId, lastCurve, lastStartPosId); if (Mode == STATUS_Close) { int firstGeoId; Sketcher::PointPos firstPosId; @@ -750,61 +875,74 @@ public: // remember the vertex for the next rounds constraint.. previousCurve = getHighestCurveIndex(); - previousPosId = (LineMode == LINE_MODE_Arc && startAngle > endAngle) ? 1 : 2; + previousPosId = (SegmentMode == SEGMENT_MODE_Arc && startAngle > endAngle) ? + Sketcher::start : Sketcher::end; // cw arcs are rendered in reverse // setup for the next line segment - // Use updated endPoint as autoconstraints can modify the position - // Need to determine if the previous element was a line or an arc or ??? - const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(getHighestCurveIndex()); - if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { - const Part::GeomLineSegment *lineSeg = dynamic_cast(geom); - EditCurve[0] = Base::Vector2D(lineSeg->getEndPoint().x, lineSeg->getEndPoint().y); - dirVec.Set(lineSeg->getEndPoint().x - lineSeg->getStartPoint().x, - lineSeg->getEndPoint().y - lineSeg->getStartPoint().y, - 0.f); - } - else if (geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { - assert(LineMode == LINE_MODE_Arc); - const Part::GeomArcOfCircle *arcSeg = dynamic_cast(geom); - if (startAngle > endAngle) { - EditCurve[0] = Base::Vector2D(arcSeg->getStartPoint().x,arcSeg->getStartPoint().y); - dirVec = Base::Vector3d(0.f,0.f,-1.0) % (arcSeg->getStartPoint()-arcSeg->getCenter()); - } - else { // cw arcs are rendered in reverse - EditCurve[0] = Base::Vector2D(arcSeg->getEndPoint().x,arcSeg->getEndPoint().y); - dirVec = Base::Vector3d(0.f,0.f,1.0) % (arcSeg->getEndPoint()-arcSeg->getCenter()); - } - } - dirVec.Normalize(); + // calculate dirVec and EditCurve[0] + updateTransitionData(previousCurve,previousPosId); applyCursor(); Mode = STATUS_SEEK_Second; - isTangent = (LineMode == LINE_MODE_Arc); - LineMode = LINE_MODE_Line; - EditCurve.resize(isTangent ? 3 : 2); - EditCurve[1] = EditCurve[0]; - if (isTangent) + if (SegmentMode == SEGMENT_MODE_Arc) { + TransitionMode = TRANSITION_MODE_Tangent; + EditCurve.resize(3); EditCurve[2] = EditCurve[0]; - sketchgui->drawEdit(EditCurve); + } + else { + TransitionMode = TRANSITION_MODE_Free; + EditCurve.resize(2); + } + SegmentMode = SEGMENT_MODE_Line; + EditCurve[1] = EditCurve[0]; + mouseMove(onSketchPos); // trigger an update of EditCurve } } return true; } protected: - SelectMode Mode; - SelectLineMode LineMode; + SELECT_MODE Mode; + SEGMENT_MODE SegmentMode; + TRANSITION_MODE TransitionMode; + bool suppressTransition; std::vector EditCurve; int firstVertex; int firstCurve; - int previousPosId; int previousCurve; + Sketcher::PointPos previousPosId; std::vector sugConstr1, sugConstr2; Base::Vector2D CenterPoint; Base::Vector3d dirVec; - bool isTangent; float startAngle, endAngle, arcRadius; + + void updateTransitionData(int GeoId, Sketcher::PointPos PosId) { + + // Use updated startPoint/endPoint as autoconstraints can modify the position + const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(GeoId); + if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { + const Part::GeomLineSegment *lineSeg = dynamic_cast(geom); + EditCurve[0] = Base::Vector2D(lineSeg->getEndPoint().x, lineSeg->getEndPoint().y); + dirVec.Set(lineSeg->getEndPoint().x - lineSeg->getStartPoint().x, + lineSeg->getEndPoint().y - lineSeg->getStartPoint().y, + 0.f); + if (PosId == Sketcher::start) + dirVec *= -1; + } + else if (geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { + const Part::GeomArcOfCircle *arcSeg = dynamic_cast(geom); + if (PosId == Sketcher::start) { + EditCurve[0] = Base::Vector2D(arcSeg->getStartPoint().x,arcSeg->getStartPoint().y); + dirVec = Base::Vector3d(0.f,0.f,-1.0) % (arcSeg->getStartPoint()-arcSeg->getCenter()); + } + else { + EditCurve[0] = Base::Vector2D(arcSeg->getEndPoint().x,arcSeg->getEndPoint().y); + dirVec = Base::Vector3d(0.f,0.f,1.0) % (arcSeg->getEndPoint()-arcSeg->getCenter()); + } + } + dirVec.Normalize(); + } }; @@ -916,11 +1054,10 @@ public: // Display radius and start angle float radius = (onSketchPos - EditCurve[0]).Length(); - float angle = atan2f(dy_ , dx_) * 180 / M_PI; + float angle = atan2f(dy_ , dx_); - char buf[40]; - sprintf( buf, " (R%.1f,%.1f)", radius, angle); - std::string text = buf; + SbString text; + text.sprintf(" (%.1fR,%.1fdeg)", radius, angle * 180 / M_PI); setPositionText(onSketchPos, text); sketchgui->drawEdit(EditCurve); @@ -941,12 +1078,11 @@ public: EditCurve[i] = Base::Vector2D(CenterPoint.fX + dx, CenterPoint.fY + dy); } - // Display radius and end angle + // Display radius and arc angle float radius = (onSketchPos - EditCurve[0]).Length(); - char buf[40]; - sprintf( buf, " (R%.1f,%.1f)", radius, arcAngle * 180 / M_PI); - std::string text = buf; + SbString text; + text.sprintf(" (%.1fR,%.1fdeg)", radius, arcAngle * 180 / M_PI); setPositionText(onSketchPos, text); sketchgui->drawEdit(EditCurve); @@ -1154,9 +1290,8 @@ public: // Display radius for user float radius = (onSketchPos - EditCurve[0]).Length(); - char buf[40]; - sprintf( buf, "R%.1f", radius); - std::string text = buf; + SbString text; + text.sprintf(" (%.1fR)", radius); setPositionText(onSketchPos, text); sketchgui->drawEdit(EditCurve); diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp index f5a308b78..acd593f54 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp +++ b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp @@ -381,7 +381,7 @@ void DrawSketchHandler::renderSuggestConstraintsCursor(std::vectorsetPositionText(Pos, text); } diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandler.h b/src/Mod/Sketcher/Gui/DrawSketchHandler.h index 15043e1ea..84bf628c1 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandler.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandler.h @@ -89,7 +89,7 @@ public: void createAutoConstraints(const std::vector &autoConstrs, int geoId, Sketcher::PointPos pointPos=Sketcher::none); - void setPositionText(const Base::Vector2D &Pos, const std::string &text); + void setPositionText(const Base::Vector2D &Pos, const SbString &text); void setPositionText(const Base::Vector2D &Pos); void resetPositionText(void); void renderSuggestConstraintsCursor(std::vector &suggestedConstraints); diff --git a/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp b/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp index e8e2451d8..0253bb4c3 100644 --- a/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp +++ b/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp @@ -42,7 +42,6 @@ TaskDlgEditSketch::TaskDlgEditSketch(ViewProviderSketch *sketchView) : TaskDialog(),sketchView(sketchView) { assert(sketchView); - documentName = sketchView->getObject()->getDocument()->getName(); Constraints = new TaskSketcherConstrains(sketchView); General = new TaskSketcherGeneral(sketchView); Messages = new TaskSketcherMessages(sketchView); @@ -77,7 +76,7 @@ bool TaskDlgEditSketch::accept() bool TaskDlgEditSketch::reject() { - std::string document = documentName; // needed because resetEdit() deletes this instance + std::string document = getDocumentName(); // needed because resetEdit() deletes this instance Gui::Command::doCommand(Gui::Command::Gui,"Gui.getDocument('%s').resetEdit()", document.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.getDocument('%s').recompute()", document.c_str()); diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 9605f3997..5106f3c9a 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -1005,55 +1005,55 @@ void ViewProviderSketch::moveConstraint(int constNum, const Base::Vector2D &toPo draw(true); } -bool ViewProviderSketch::isConstraintAtPosition(const Base::Vector3d &constrPos, const SoNode *constraint) +Base::Vector3d ViewProviderSketch::seekConstraintPosition(const Base::Vector3d &origPos, + const Base::Vector3d &norm, + const Base::Vector3d &dir, float step, + const SoNode *constraint) { assert(edit); Gui::MDIView *mdi = Gui::Application::Instance->activeDocument()->getActiveView(); Gui::View3DInventorViewer *viewer = static_cast(mdi)->getViewer(); - SoRayPickAction rp(viewer->getViewportRegion()); - rp.setRadius(0.1f); - rp.setPickAll(true); - rp.setRay(SbVec3f(constrPos.x, constrPos.y, -1.f), SbVec3f(0, 0, 1) ); - //problem - rp.apply(edit->constrGroup); // We could narrow it down to just the SoGroup containing the constraints - // returns a copy of the point - SoPickedPoint *pp = rp.getPickedPoint(); - const SoPickedPointList ppl = rp.getPickedPointList(); + float scaled_step = step * getScaleFactor(); - if(ppl.getLength() > 1) - return true; - if (pp) { - SoPath *path = pp->getPath(); - int length = path->getLength(); - SoNode *tailFather1 = path->getNode(length-2); - SoNode *tailFather2 = path->getNode(length-3); - - // checking if a constraint is the same as the one selected - if (tailFather1 == constraint || tailFather2 == constraint) { - return false; - } else { - return true; - } - } else { - return false; - } -} - -Base::Vector3d ViewProviderSketch::seekConstraintPosition(const Base::Vector3d &suggestedPos, - const Base::Vector3d &dir, float step, - const SoNode *constraint) -{ int multiplier = 0; - Base::Vector3d freePos; - do { + Base::Vector3d relPos, freePos; + bool isConstraintAtPosition = true; + while (isConstraintAtPosition && multiplier < 10) { // Calculate new position of constraint - freePos = suggestedPos + (dir * (multiplier * step)); - multiplier++; // Increment the multiplier + relPos = norm * 0.5f + dir * multiplier; + freePos = origPos + relPos * scaled_step; + + rp.setRadius(0.1f); + rp.setPickAll(true); + rp.setRay(SbVec3f(freePos.x, freePos.y, -1.f), SbVec3f(0, 0, 1) ); + //problem + rp.apply(edit->constrGroup); // We could narrow it down to just the SoGroup containing the constraints + + // returns a copy of the point + SoPickedPoint *pp = rp.getPickedPoint(); + const SoPickedPointList ppl = rp.getPickedPointList(); + + if (ppl.getLength() <= 1 && pp) { + SoPath *path = pp->getPath(); + int length = path->getLength(); + SoNode *tailFather1 = path->getNode(length-2); + SoNode *tailFather2 = path->getNode(length-3); + + // checking if a constraint is the same as the one selected + if (tailFather1 == constraint || tailFather2 == constraint) + isConstraintAtPosition = false; + } else + isConstraintAtPosition = false; + + multiplier *= -1; // search in both sides + if (multiplier >= 0) + multiplier++; // Increment the multiplier } - while (isConstraintAtPosition(freePos, constraint)); - return freePos; + if (multiplier == 10) + relPos = norm * 0.5f; // no free position found + return relPos * step; } bool ViewProviderSketch::isSelectable(void) const @@ -1716,7 +1716,7 @@ void ViewProviderSketch::draw(bool temp) Points.push_back(start); Points.push_back(end); } - else if ((*it)->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { // add a circle + else if ((*it)->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { // add a bspline const Part::GeomBSplineCurve *spline = dynamic_cast(*it); Handle_Geom_BSplineCurve curve = Handle_Geom_BSplineCurve::DownCast(spline->handle()); @@ -1842,19 +1842,12 @@ Restart: Base::Vector3d dir = (lineSeg->getEndPoint()-lineSeg->getStartPoint()).Normalize(); Base::Vector3d norm(-dir.y,dir.x,0); - float scale = dynamic_cast(sep->getChild(1))->getScaleFactor(); - Base::Vector3d constrPos = midpos + (norm * 2.5 * scale); - - constrPos = seekConstraintPosition(constrPos, dir, 2.5 * scale, edit->constrGroup->getChild(i)); - - // Translate the Icon based on calculated position - Base::Vector3d relPos = constrPos - midpos; // Relative Position of Icons to Midpoint - relPos = relPos / scale; // Must Divide by Scale Factor + Base::Vector3d relpos = seekConstraintPosition(midpos, norm, dir, 2.5, edit->constrGroup->getChild(i)); dynamic_cast(sep->getChild(1))->abPos = SbVec3f(midpos.x, midpos.y, zConstr); //Absolute Reference //Reference Position that is scaled according to zoom - dynamic_cast(sep->getChild(1))->translation = SbVec3f(relPos.x, relPos.y, 0); + dynamic_cast(sep->getChild(1))->translation = SbVec3f(relpos.x, relpos.y, 0); } break; @@ -1921,25 +1914,16 @@ Restart: dir1 = Base::Vector3d(1,0,0); } - // Get Current Scale Factor - float scale = dynamic_cast(sep->getChild(1))->getScaleFactor(); - - Base::Vector3d constrPos1 = midpos1 + (norm1 * 2.5 * scale); - constrPos1 = seekConstraintPosition(constrPos1, dir1, scale * 2.5, edit->constrGroup->getChild(i)); - - // Translate the Icon based on calculated position - Base::Vector3d relPos1 = (constrPos1 - midpos1) / scale ; // Relative Position of Icons to Midpoint1 + Base::Vector3d relpos1 = seekConstraintPosition(midpos1, norm1, dir1, 2.5, edit->constrGroup->getChild(i)); dynamic_cast(sep->getChild(1))->abPos = SbVec3f(midpos1.x, midpos1.y, zConstr); - dynamic_cast(sep->getChild(1))->translation = SbVec3f(relPos1.x, relPos1.y, 0); + dynamic_cast(sep->getChild(1))->translation = SbVec3f(relpos1.x, relpos1.y, 0); if (Constr->FirstPos == Sketcher::none) { - Base::Vector3d constrPos2 = midpos2 + (norm2 * 2.5 * scale); - constrPos2 = seekConstraintPosition(constrPos2, dir2, 2.5 * scale, edit->constrGroup->getChild(i)); + Base::Vector3d relpos2 = seekConstraintPosition(midpos2, norm2, dir2, 2.5, edit->constrGroup->getChild(i)); - Base::Vector3d relPos2 = (constrPos2 - midpos2) / scale ; // Relative Position of Icons to Midpoint2 Base::Vector3d secondPos = midpos2 - midpos1; dynamic_cast(sep->getChild(3))->abPos = SbVec3f(secondPos.x, secondPos.y, zConstr); - dynamic_cast(sep->getChild(3))->translation = SbVec3f(relPos2.x -relPos1.x, relPos2.y -relPos1.y, 0); + dynamic_cast(sep->getChild(3))->translation = SbVec3f(relpos2.x -relpos1.x, relpos2.y -relpos1.y, 0); } } @@ -2012,32 +1996,19 @@ Restart: norm2 = Base::Vector3d(-dir2.y,dir2.x,0.); } - // Get Current Scale Factor - float scale = dynamic_cast(sep->getChild(1))->getScaleFactor(); - - Base::Vector3d constrPos1 = midpos1 + (norm1 * 2.5 * scale); - constrPos1 = seekConstraintPosition(constrPos1, dir1, scale * 2.5, edit->constrGroup->getChild(i)); - - Base::Vector3d constrPos2 = midpos2 + (norm2 * 2.5 * scale); - constrPos2 = seekConstraintPosition(constrPos2, dir2, 2.5 * scale, edit->constrGroup->getChild(i)); - - // Translate the Icon based on calculated position - Base::Vector3d relPos1 = constrPos1 - midpos1 ; // Relative Position of Icons to Midpoint1 - Base::Vector3d relPos2 = constrPos2 - midpos2 ; // Relative Position of Icons to Midpoint2 - - relPos1 = relPos1 / scale; - relPos2 = relPos2 / scale; + Base::Vector3d relpos1 = seekConstraintPosition(midpos1, norm1, dir1, 2.5, edit->constrGroup->getChild(i)); + Base::Vector3d relpos2 = seekConstraintPosition(midpos2, norm2, dir2, 2.5, edit->constrGroup->getChild(i)); dynamic_cast(sep->getChild(1))->abPos = SbVec3f(midpos1.x, midpos1.y, zConstr); //Absolute Reference //Reference Position that is scaled according to zoom - dynamic_cast(sep->getChild(1))->translation = SbVec3f(relPos1.x, relPos1.y, 0); + dynamic_cast(sep->getChild(1))->translation = SbVec3f(relpos1.x, relpos1.y, 0); Base::Vector3d secondPos = midpos2 - midpos1; dynamic_cast(sep->getChild(3))->abPos = SbVec3f(secondPos.x, secondPos.y, zConstr); //Absolute Reference //Reference Position that is scaled according to zoom - dynamic_cast(sep->getChild(3))->translation = SbVec3f(relPos2.x -relPos1.x, relPos2.y -relPos1.y, 0); + dynamic_cast(sep->getChild(3))->translation = SbVec3f(relpos2.x - relpos1.x, relpos2.y -relpos1.y, 0); } break; @@ -2148,32 +2119,19 @@ Restart: Base::Vector3d norm1 = Base::Vector3d(-dir1.y,dir1.x,0.f); Base::Vector3d norm2 = Base::Vector3d(-dir2.y,dir2.x,0.f); - // Get Current Scale Factor - float scale = dynamic_cast(sep->getChild(1))->getScaleFactor(); - - Base::Vector3d constrPos1 = midpos1 + (norm1 * 2.5 * scale); - constrPos1 = seekConstraintPosition(constrPos1, dir1, 2.5 * scale, edit->constrGroup->getChild(i)); - - Base::Vector3d constrPos2 = midpos2 + (norm2 * 2.5 * scale); - constrPos2 = seekConstraintPosition(constrPos2, dir2, 2.5 * scale, edit->constrGroup->getChild(i)); - - // Translate the Icon based on calculated position - Base::Vector3d relPos1 = constrPos1 - midpos1 ; // Relative Position of Icons to Midpoint1 - Base::Vector3d relPos2 = constrPos2 - midpos2 ; // Relative Position of Icons to Midpoint2 - - relPos1 = relPos1 / scale; - relPos2 = relPos2 / scale; + Base::Vector3d relpos1 = seekConstraintPosition(midpos1, norm1, dir1, 2.5, edit->constrGroup->getChild(i)); + Base::Vector3d relpos2 = seekConstraintPosition(midpos2, norm2, dir2, 2.5, edit->constrGroup->getChild(i)); dynamic_cast(sep->getChild(1))->abPos = SbVec3f(midpos1.x, midpos1.y, zConstr); //Absolute Reference //Reference Position that is scaled according to zoom - dynamic_cast(sep->getChild(1))->translation = SbVec3f(relPos1.x, relPos1.y, 0); + dynamic_cast(sep->getChild(1))->translation = SbVec3f(relpos1.x, relpos1.y, 0); Base::Vector3d secondPos = midpos2 - midpos1; dynamic_cast(sep->getChild(3))->abPos = SbVec3f(secondPos.x, secondPos.y, zConstr); //Absolute Reference //Reference Position that is scaled according to zoom - dynamic_cast(sep->getChild(3))->translation = SbVec3f(relPos2.x -relPos1.x, relPos2.y -relPos1.y, 0); + dynamic_cast(sep->getChild(3))->translation = SbVec3f(relpos2.x -relpos1.x, relpos2.y -relpos1.y, 0); break; } @@ -2777,9 +2735,14 @@ void ViewProviderSketch::createEditInventorNodes(void) edit->EditCurveSet = new SoLineSet; edit->EditRoot->addChild(edit->EditCurveSet); + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); + float transparency; + SbColor cursorTextColor(0,0,1); + cursorTextColor.setPackedValue((uint32_t)hGrp->GetUnsigned("CursorTextColor", cursorTextColor.getPackedValue()), transparency); + // stuff for the edit coordinates ++++++++++++++++++++++++++++++++++++++ SoMaterial *EditMaterials = new SoMaterial; - EditMaterials->diffuseColor = SbColor(0,0,1); + EditMaterials->diffuseColor = cursorTextColor; edit->EditRoot->addChild(EditMaterials); SoSeparator *Coordsep = new SoSeparator(); @@ -2867,17 +2830,17 @@ void ViewProviderSketch::unsetEditViewer(Gui::View3DInventorViewer* viewer) static_cast(root)->selectionRole.setValue(TRUE); } -void ViewProviderSketch::setPositionText(const Base::Vector2D &Pos, const std::string &text) +void ViewProviderSketch::setPositionText(const Base::Vector2D &Pos, const SbString &text) { - edit->textX->string = text.c_str(); + edit->textX->string = text; edit->textPos->translation = SbVec3f(Pos.fX,Pos.fY,zText); } void ViewProviderSketch::setPositionText(const Base::Vector2D &Pos) { - char buf[40]; - sprintf( buf, " (%.1f,%.1f)", Pos.fX,Pos.fY ); - edit->textX->string = buf; + SbString text; + text.sprintf(" (%.1f,%.1f)", Pos.fX, Pos.fY); + edit->textX->string = text; edit->textPos->translation = SbVec3f(Pos.fX,Pos.fY,zText); } diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.h b/src/Mod/Sketcher/Gui/ViewProviderSketch.h index b29f2c377..4a850ae3c 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.h +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.h @@ -43,6 +43,7 @@ class SoMarkerSet; class SoText2; class SoTranslation; +class SbString; class SbTime; struct EditData; @@ -137,10 +138,9 @@ public: /// moves a selected constraint void moveConstraint(int constNum, const Base::Vector2D &toPos); - /// checks if there is a constraint object at position vector - bool isConstraintAtPosition(const Base::Vector3d &constrPos, const SoNode *constraint); /// finds a free position for placing a constraint icon - Base::Vector3d seekConstraintPosition(const Base::Vector3d &suggestedPos, + Base::Vector3d seekConstraintPosition(const Base::Vector3d &origPos, + const Base::Vector3d &norm, const Base::Vector3d &dir, float step, const SoNode *constraint); @@ -200,7 +200,7 @@ protected: /// build up the visual of the constraints void rebuildConstraintsVisual(void); - void setPositionText(const Base::Vector2D &Pos, const std::string &txt); + void setPositionText(const Base::Vector2D &Pos, const SbString &txt); void setPositionText(const Base::Vector2D &Pos); void resetPositionText(void); diff --git a/src/Mod/Web/Gui/BrowserView.cpp b/src/Mod/Web/Gui/BrowserView.cpp index 81c02dd8b..04739a351 100644 --- a/src/Mod/Web/Gui/BrowserView.cpp +++ b/src/Mod/Web/Gui/BrowserView.cpp @@ -114,7 +114,7 @@ BrowserView::BrowserView(QWidget* parent) connect(view, SIGNAL(loadProgress(int)), this, SLOT(onLoadProgress(int))); connect(view, SIGNAL(loadFinished(bool)), - this, SLOT(onLoadFinished())); + this, SLOT(onLoadFinished(bool))); connect(view, SIGNAL(linkClicked(const QUrl &)), this, SLOT(onLinkClicked(const QUrl &))); connect(view->page(), SIGNAL(downloadRequested(const QNetworkRequest &)), @@ -242,12 +242,14 @@ void BrowserView::onLoadProgress(int step) bar->setValue(step); } -void BrowserView::onLoadFinished() +void BrowserView::onLoadFinished(bool ok) { - QProgressBar* bar = Sequencer::instance()->getProgressBar(); - bar->setValue(100); - bar->hide(); - getMainWindow()->statusBar()->showMessage(QString()); + if (ok) { + QProgressBar* bar = Sequencer::instance()->getProgressBar(); + bar->setValue(100); + bar->hide(); + getMainWindow()->statusBar()->showMessage(QString()); + } isLoading = false; } diff --git a/src/Mod/Web/Gui/BrowserView.h b/src/Mod/Web/Gui/BrowserView.h index c32dfd659..553ccd160 100644 --- a/src/Mod/Web/Gui/BrowserView.h +++ b/src/Mod/Web/Gui/BrowserView.h @@ -92,10 +92,10 @@ public: protected Q_SLOTS: void onLoadStarted(); void onLoadProgress(int); - void onLoadFinished(); - void onLinkClicked ( const QUrl & url ) ; + void onLoadFinished(bool); + void onLinkClicked (const QUrl& url); bool chckHostAllowed(const QString& host); - void onDownloadRequested(const QNetworkRequest & request); + void onDownloadRequested(const QNetworkRequest& request); private: WebView* view;