From a23338832813cb90dcb777a9afd375065e70e312 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 29 Apr 2013 14:30:26 +0200 Subject: [PATCH 001/160] Make information if tree item is expanded/collapsed persistent --- src/App/DocumentObject.h | 32 ++++++--- src/Gui/Document.cpp | 15 +++- src/Gui/Tree.cpp | 98 +++++++++++++++++--------- src/Gui/Tree.h | 3 + src/Gui/ViewProviderDocumentObject.cpp | 5 +- 5 files changed, 104 insertions(+), 49 deletions(-) diff --git a/src/App/DocumentObject.h b/src/App/DocumentObject.h index 78616408c..079c361c8 100644 --- a/src/App/DocumentObject.h +++ b/src/App/DocumentObject.h @@ -38,6 +38,15 @@ namespace App class Document; class DocumentObjectPy; +enum ObjectStatus { + Touch = 0, + Error = 1, + New = 2, + Recompute = 3, + Restore = 4, + Expand = 16 +}; + /** Return object for feature execution */ class AppExport DocumentObjectExecReturn @@ -105,9 +114,11 @@ public: virtual App::DocumentObjectExecReturn *recompute(void); /// return the status bits unsigned long getStatus() const {return StatusBits.to_ulong();} + bool testStatus(ObjectStatus pos) const {return StatusBits.test((size_t)pos);} + void setStatus(ObjectStatus pos, bool on) {StatusBits.set((size_t)pos, on);} //@} - /// returns a list of objects this object is pointing to by Links + /// returns a list of objects this object is pointing to by Links std::vector getOutList(void) const; /// get all objects link to this object std::vector getInList(void) const; @@ -129,7 +140,7 @@ public: /** Called in case of loosing a link * Get called by the document when a object got deleted a link property of this - * object ist pointing to. The standard behaivour of the DocumentObject implementation + * object ist pointing to. The standard behaviour of the DocumentObject implementation * is to reset the links to nothing. You may overide this method to implement *additional or different behavior. */ @@ -160,14 +171,15 @@ protected: * The first 8 bits are used for the base system the rest can be used in * descendent classes to to mark special stati on the objects. * The bits and their meaning are listed below: - * 0 - object is marked as 'touched' - * 1 - object is marked as 'erroneous' - * 2 - object is marked as 'new' - * 3 - object is marked as 'recompute', i.e. the object gets recomputed now - * 4 - object is marked as 'restoring', i.e. the object gets loaded at the moment - * 5 - reserved - * 6 - reserved - * 7 - reserved + * 0 - object is marked as 'touched' + * 1 - object is marked as 'erroneous' + * 2 - object is marked as 'new' + * 3 - object is marked as 'recompute', i.e. the object gets recomputed now + * 4 - object is marked as 'restoring', i.e. the object gets loaded at the moment + * 5 - reserved + * 6 - reserved + * 7 - reserved + * 16 - object is marked as 'expanded' in the tree view */ std::bitset<32> StatusBits; diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index f93aab1ee..eca63b7d4 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -695,9 +695,20 @@ void Document::RestoreDocFile(Base::Reader &reader) for (i=0 ;iRestore(xmlReader); + if (expanded) { + Gui::ViewProviderDocumentObject* vp = static_cast(pObj); + this->signalExpandObject(*vp, Gui::Expand); + } xmlReader.readEndElement("ViewProvider"); } xmlReader.readEndElement("ViewProviderData"); @@ -784,7 +795,9 @@ void Document::SaveDocFile (Base::Writer &writer) const const App::DocumentObject* doc = it->first; ViewProvider* obj = it->second; writer.Stream() << writer.ind() << "getNameInDocument() << "\">" << std::endl; + << doc->getNameInDocument() << "\" " + << "expanded=\"" << (doc->testStatus(App::Expand) ? 1:0) + << "\">" << std::endl; obj->Save(writer); writer.Stream() << writer.ind() << "" << std::endl; } diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index 4faa227fd..c2b328445 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -112,6 +112,10 @@ TreeWidget::TreeWidget(QWidget* parent) this, SLOT(onTestStatus())); connect(this, SIGNAL(itemEntered(QTreeWidgetItem*, int)), this, SLOT(onItemEntered(QTreeWidgetItem*))); + connect(this, SIGNAL(itemCollapsed(QTreeWidgetItem*)), + this, SLOT(onItemCollapsed(QTreeWidgetItem*))); + connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)), + this, SLOT(onItemExpanded(QTreeWidgetItem*))); connect(this, SIGNAL(itemSelectionChanged()), this, SLOT(onItemSelectionChanged())); @@ -572,12 +576,30 @@ void TreeWidget::onTestStatus(void) void TreeWidget::onItemEntered(QTreeWidgetItem * item) { // object item selected - if ( item && item->type() == TreeWidget::ObjectType ) { + if (item && item->type() == TreeWidget::ObjectType) { DocumentObjectItem* obj = static_cast(item); obj->displayStatusInfo(); } } +void TreeWidget::onItemCollapsed(QTreeWidgetItem * item) +{ + // object item collapsed + if (item && item->type() == TreeWidget::ObjectType) { + DocumentObjectItem* obj = static_cast(item); + obj->setExpandedStatus(false); + } +} + +void TreeWidget::onItemExpanded(QTreeWidgetItem * item) +{ + // object item expanded + if (item && item->type() == TreeWidget::ObjectType) { + DocumentObjectItem* obj = static_cast(item); + obj->setExpandedStatus(true); + } +} + void TreeWidget::scrollItemToTop(Gui::Document* doc) { std::map::iterator it; @@ -810,52 +832,52 @@ void DocumentItem::slotChangeObject(const Gui::ViewProviderDocumentObject& view) std::string objectName = obj->getNameInDocument(); std::map::iterator it = ObjectMap.find(objectName); if (it != ObjectMap.end()) { - // use new grouping style - std::set children; - std::vector group = view.claimChildren(); - for (std::vector::iterator jt = group.begin(); jt != group.end(); ++jt) { - if(*jt){ - const char* internalName = (*jt)->getNameInDocument(); - if (internalName) { - std::map::iterator kt = ObjectMap.find(internalName); - if (kt != ObjectMap.end()) { - children.insert(kt->second); - QTreeWidgetItem* parent = kt->second->parent(); - if (parent && parent != it->second) { - if (it->second != kt->second) { - int index = parent->indexOfChild(kt->second); - parent->takeChild(index); - it->second->addChild(kt->second); - } - else { - Base::Console().Warning("Gui::DocumentItem::slotChangedObject(): Object references to itself.\n"); - } + // use new grouping style + std::set children; + std::vector group = view.claimChildren(); + for (std::vector::iterator jt = group.begin(); jt != group.end(); ++jt) { + if (*jt) { + const char* internalName = (*jt)->getNameInDocument(); + if (internalName) { + std::map::iterator kt = ObjectMap.find(internalName); + if (kt != ObjectMap.end()) { + children.insert(kt->second); + QTreeWidgetItem* parent = kt->second->parent(); + if (parent && parent != it->second) { + if (it->second != kt->second) { + int index = parent->indexOfChild(kt->second); + parent->takeChild(index); + it->second->addChild(kt->second); + } + else { + Base::Console().Warning("Gui::DocumentItem::slotChangedObject(): Object references to itself.\n"); } - } - else { - Base::Console().Warning("Gui::DocumentItem::slotChangedObject(): Cannot reparent unknown object.\n"); } } else { - Base::Console().Warning("Gui::DocumentItem::slotChangedObject(): Group references unknown object.\n"); + Base::Console().Warning("Gui::DocumentItem::slotChangedObject(): Cannot reparent unknown object.\n"); } } - } - // move all children which are not part of the group anymore to this item - int count = it->second->childCount(); - for (int i=0; i < count; i++) { - QTreeWidgetItem* child = it->second->child(i); - if (children.find(child) == children.end()) { - it->second->takeChild(i); - this->addChild(child); + else { + Base::Console().Warning("Gui::DocumentItem::slotChangedObject(): Group references unknown object.\n"); } } - this->treeWidget()->expandItem(it->second); + } + // move all children which are not part of the group anymore to this item + int count = it->second->childCount(); + for (int i=0; i < count; i++) { + QTreeWidgetItem* child = it->second->child(i); + if (children.find(child) == children.end()) { + it->second->takeChild(i); + this->addChild(child); + } + } // set the text label std::string displayName = obj->Label.getValue(); it->second->setText(0, QString::fromUtf8(displayName.c_str())); - } else { + } + else { Base::Console().Warning("Gui::DocumentItem::slotChangedObject(): Cannot change unknown object.\n"); } } @@ -1226,6 +1248,12 @@ void DocumentObjectItem::displayStatusInfo() } +void DocumentObjectItem::setExpandedStatus(bool on) +{ + App::DocumentObject* Obj = viewObject->getObject(); + Obj->setStatus(App::Expand, on); +} + void DocumentObjectItem::setData (int column, int role, const QVariant & value) { QTreeWidgetItem::setData(column, role, value); diff --git a/src/Gui/Tree.h b/src/Gui/Tree.h index be1126d6e..b0e6b1287 100644 --- a/src/Gui/Tree.h +++ b/src/Gui/Tree.h @@ -96,6 +96,8 @@ protected Q_SLOTS: private Q_SLOTS: void onItemSelectionChanged(void); void onItemEntered(QTreeWidgetItem * item); + void onItemCollapsed(QTreeWidgetItem * item); + void onItemExpanded(QTreeWidgetItem * item); void onTestStatus(void); private: @@ -176,6 +178,7 @@ public: Gui::ViewProviderDocumentObject* object() const; void testStatus(); void displayStatusInfo(); + void setExpandedStatus(bool); void setData(int column, int role, const QVariant & value); protected: diff --git a/src/Gui/ViewProviderDocumentObject.cpp b/src/Gui/ViewProviderDocumentObject.cpp index 7bedbf042..026b6f36d 100644 --- a/src/Gui/ViewProviderDocumentObject.cpp +++ b/src/Gui/ViewProviderDocumentObject.cpp @@ -58,7 +58,6 @@ ViewProviderDocumentObject::ViewProviderDocumentObject() sPixmap = "Feature"; } - ViewProviderDocumentObject::~ViewProviderDocumentObject() { // Make sure that the property class does not destruct our string list @@ -139,12 +138,12 @@ void ViewProviderDocumentObject::attach(App::DocumentObject *pcObj) // Retrieve the supported display modes of the view provider aDisplayModesArray = this->getDisplayModes(); - if( aDisplayModesArray.empty() ) + if (aDisplayModesArray.empty()) aDisplayModesArray.push_back(""); // We must collect the const char* of the strings and give it to PropertyEnumeration, // but we are still responsible for them, i.e. the property class must not delete the literals. - for ( std::vector::iterator it = aDisplayModesArray.begin(); it != aDisplayModesArray.end(); ++it ) { + for (std::vector::iterator it = aDisplayModesArray.begin(); it != aDisplayModesArray.end(); ++it) { aDisplayEnumsArray.push_back( it->c_str() ); } aDisplayEnumsArray.push_back(0); // null termination From b36cc0e43a88bdc20d47798b2af9b57ab59db466 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 29 Apr 2013 16:54:25 +0200 Subject: [PATCH 002/160] Add property classes to type system --- src/App/Application.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/App/Application.cpp b/src/App/Application.cpp index 655ef445e..e5b27962d 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -1007,7 +1007,10 @@ void Application::initTypes(void) App ::PropertyPercent ::init(); App ::PropertyEnumeration ::init(); App ::PropertyIntegerList ::init(); + App ::PropertyIntegerSet ::init(); + App ::PropertyMap ::init(); App ::PropertyString ::init(); + App ::PropertyUUID ::init(); App ::PropertyFont ::init(); App ::PropertyStringList ::init(); App ::PropertyLink ::init(); From 6551cc4d81750a9467628ae60f030f8a623b077c Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 29 Apr 2013 21:12:45 +0200 Subject: [PATCH 003/160] Command to reorient sketch --- src/Mod/PartDesign/Gui/Workbench.cpp | 1 + src/Mod/Sketcher/Gui/Command.cpp | 83 ++++++++++++++++++++++++++++ src/Mod/Sketcher/Gui/Workbench.cpp | 1 + 3 files changed, 85 insertions(+) diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 1cdb6c3ca..977f110bd 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -205,6 +205,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Sketcher_LeaveSketch" << "Sketcher_ViewSketch" << "Sketcher_MapSketch" + << "Sketcher_ReorientSketch" << geom << cons << "Separator" diff --git a/src/Mod/Sketcher/Gui/Command.cpp b/src/Mod/Sketcher/Gui/Command.cpp index 0dc6a3e2e..4ad5ae9d5 100644 --- a/src/Mod/Sketcher/Gui/Command.cpp +++ b/src/Mod/Sketcher/Gui/Command.cpp @@ -166,6 +166,88 @@ bool CmdSketcherNewSketch::isActive(void) return false; } +DEF_STD_CMD_A(CmdSketcherReorientSketch); + +CmdSketcherReorientSketch::CmdSketcherReorientSketch() + :Command("Sketcher_ReorientSketch") +{ + sAppModule = "Sketcher"; + sGroup = QT_TR_NOOP("Sketcher"); + sMenuText = QT_TR_NOOP("Reorient sketch..."); + sToolTipText = QT_TR_NOOP("Reorient the selected sketch"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; +} + +void CmdSketcherReorientSketch::activated(int iMsg) +{ + Sketcher::SketchObject* sketch = Gui::Selection().getObjectsOfType().front(); + if (sketch->Support.getValue()) { + int ret = QMessageBox::question(Gui::getMainWindow(), + qApp->translate("Sketcher_ReorientSketch","Sketch has support"), + qApp->translate("Sketcher_ReorientSketch","Sketch with a support face cannot be reoriented.\n" + "Do you want to detach it from the support?"), + QMessageBox::Yes|QMessageBox::No); + if (ret == QMessageBox::No) + return; + sketch->Support.setValue(0); + } + + // ask user for orientation + SketchOrientationDialog Dlg; + + if (Dlg.exec() != QDialog::Accepted) + return; // canceled + Base::Vector3d p = Dlg.Pos.getPosition(); + Base::Rotation r = Dlg.Pos.getRotation(); + + // do the right view direction + std::string camstring; + switch(Dlg.DirType){ + case 0: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n " + "position 0 0 87 \\n orientation 0 0 1 0 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n " + "aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }"; + break; + case 1: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n " + "position 0 0 -87 \\n orientation -1 0 0 3.1415927 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n " + "aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }"; + break; + case 2: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n " + "position 0 -87 0 \\n orientation -1 0 0 4.712389\\n nearDistance -112.88701\\n farDistance 287.28702\\n " + "aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + case 3: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n " + "position 0 87 0 \\n orientation 0 0.70710683 0.70710683 3.1415927\\n nearDistance -112.88701\\n farDistance 287.28702\\n " + "aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + case 4: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n " + "position 87 0 0 \\n orientation 0.57735026 0.57735026 0.57735026 2.0943952 \\n nearDistance -112.887\\n farDistance 287.28699\\n " + "aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + case 5: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n " + "position -87 0 0 \\n orientation -0.57735026 0.57735026 0.57735026 4.1887903 \\n nearDistance -112.887\\n farDistance 287.28699\\n " + "aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + } + + openCommand("Reorient Sketch"); + doCommand(Doc,"App.ActiveDocument.%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))" + ,sketch->getNameInDocument(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); + doCommand(Gui,"Gui.ActiveDocument.setEdit('%s')",sketch->getNameInDocument()); +} + +bool CmdSketcherReorientSketch::isActive(void) +{ + return Gui::Selection().countObjectsOfType + (Sketcher::SketchObject::getClassTypeId()) == 1; +} + DEF_STD_CMD_A(CmdSketcherMapSketch); CmdSketcherMapSketch::CmdSketcherMapSketch() @@ -345,6 +427,7 @@ void CreateSketcherCommands(void) Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); rcCmdMgr.addCommand(new CmdSketcherNewSketch()); + rcCmdMgr.addCommand(new CmdSketcherReorientSketch()); rcCmdMgr.addCommand(new CmdSketcherMapSketch()); rcCmdMgr.addCommand(new CmdSketcherLeaveSketch()); rcCmdMgr.addCommand(new CmdSketcherViewSketch()); diff --git a/src/Mod/Sketcher/Gui/Workbench.cpp b/src/Mod/Sketcher/Gui/Workbench.cpp index ead382363..fda421b15 100644 --- a/src/Mod/Sketcher/Gui/Workbench.cpp +++ b/src/Mod/Sketcher/Gui/Workbench.cpp @@ -98,6 +98,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Sketcher_LeaveSketch" << "Sketcher_ViewSketch" << "Sketcher_MapSketch" + << "Sketcher_ReorientSketch" << geom << cons ; From fba4d14f797d6f21ce29a636739a7f576ab39c50 Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 2 May 2013 14:02:55 +0200 Subject: [PATCH 004/160] Implement Copy/Paste for PropertyEnumeration --- src/App/PropertyStandard.cpp | 23 +++++++++++++++++++++++ src/App/PropertyStandard.h | 3 +++ 2 files changed, 26 insertions(+) diff --git a/src/App/PropertyStandard.cpp b/src/App/PropertyStandard.cpp index fb73ec4d0..9f6c37b6c 100644 --- a/src/App/PropertyStandard.cpp +++ b/src/App/PropertyStandard.cpp @@ -509,6 +509,29 @@ void PropertyEnumeration::setPyObject(PyObject *value) } } +Property *PropertyEnumeration::Copy(void) const +{ + PropertyEnumeration *p= new PropertyEnumeration(); + p->_lValue = _lValue; + if (_CustomEnum) { + p->_CustomEnum = true; + p->setEnumVector(getEnumVector()); + } + return p; +} + +void PropertyEnumeration::Paste(const Property &from) +{ + aboutToSetValue(); + const PropertyEnumeration& prop = dynamic_cast(from); + _lValue = prop._lValue; + if (prop._CustomEnum) { + this->_CustomEnum = true; + this->setEnumVector(prop.getEnumVector()); + } + hasSetValue(); +} + //************************************************************************** //************************************************************************** // PropertyIntegerConstraint diff --git a/src/App/PropertyStandard.h b/src/App/PropertyStandard.h index e611dd070..b23d9e4d7 100644 --- a/src/App/PropertyStandard.h +++ b/src/App/PropertyStandard.h @@ -183,6 +183,9 @@ public: virtual void Save (Base::Writer &writer) const; virtual void Restore(Base::XMLReader &reader); + virtual Property *Copy(void) const; + virtual void Paste(const Property &from); + private: bool _CustomEnum; const char** _EnumArray; From 746ab2ec786341f07614340b8543e74ade2ec21a Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 2 May 2013 17:37:56 +0200 Subject: [PATCH 005/160] Add framebuffer support to Inventor viewer --- src/Gui/Flag.cpp | 73 +++++++- src/Gui/Flag.h | 22 +++ src/Gui/GLPainter.cpp | 2 + src/Gui/GLPainter.h | 16 ++ src/Gui/MouseSelection.cpp | 114 ++++++++++++ src/Gui/MouseSelection.h | 35 +++- src/Gui/SoFCDB.cpp | 4 + src/Gui/View3DInventorViewer.cpp | 170 ++++++++++++++---- src/Gui/View3DInventorViewer.h | 40 +++-- .../Inspection/Gui/ViewProviderInspection.cpp | 38 ++-- src/Mod/Mesh/Gui/ViewProvider.cpp | 20 ++- src/Mod/Part/Gui/ViewProvider.cpp | 1 + src/Mod/Sandbox/Gui/Command.cpp | 3 + 13 files changed, 470 insertions(+), 68 deletions(-) diff --git a/src/Gui/Flag.cpp b/src/Gui/Flag.cpp index 7ae9c269a..e95dd1528 100644 --- a/src/Gui/Flag.cpp +++ b/src/Gui/Flag.cpp @@ -28,7 +28,6 @@ #endif #include #include "View3DInventorViewer.h" -#include "GLPainter.h" #include "Flag.h" @@ -455,4 +454,76 @@ QSize FlagLayout::calculateSize(SizeType sizeType) const return totalSize; } + +TYPESYSTEM_SOURCE_ABSTRACT(Gui::GLFlagWindow, Gui::GLGraphicsItem); + +GLFlagWindow::GLFlagWindow(View3DInventorViewer* view) : _viewer(view), _flagLayout(0) +{ +} + +GLFlagWindow::~GLFlagWindow() +{ + deleteFlags(); + if (_flagLayout) + _flagLayout->deleteLater(); +} + +void GLFlagWindow::deleteFlags() +{ + if (_flagLayout) { + int ct = _flagLayout->count(); + for (int i=0; iitemAt(0)->widget(); + if (flag) { + _flagLayout->removeWidget(flag); + flag->deleteLater(); + } + } + } +} + +void GLFlagWindow::addFlag(Flag* item, FlagLayout::Position pos) +{ + if (!_flagLayout) { + _flagLayout = new FlagLayout(3); + _viewer->getGLWidget()->setLayout(_flagLayout); + } + + item->setParent(_viewer->getGLWidget()); + _flagLayout->addWidget(item, pos); + item->show(); + _viewer->scheduleRedraw(); +} + +void GLFlagWindow::removeFlag(Flag* item) +{ + if (_flagLayout) { + _flagLayout->removeWidget(item); + } +} + +void GLFlagWindow::paintGL() +{ + // draw lines for the flags + if (_flagLayout) { + // it can happen that the GL widget gets replaced internally by SoQt which + // causes to destroy the FlagLayout instance + int ct = _flagLayout->count(); + const SbViewportRegion vp = _viewer->getViewportRegion(); + SbVec2s size = vp.getViewportSizePixels(); + float aspectratio = float(size[0])/float(size[1]); + SbViewVolume vv = _viewer->getCamera()->getViewVolume(aspectratio); + for (int i=0; i(_flagLayout->itemAt(i)->widget()); + if (flag) { + SbVec3f pt = flag->getOrigin(); + vv.projectToScreen(pt, pt); + int tox = (int)(pt[0] * size[0]); + int toy = (int)((1.0f-pt[1]) * size[1]); + flag->drawLine(_viewer, tox, toy); + } + } + } +} + #include "moc_Flag.cpp" diff --git a/src/Gui/Flag.h b/src/Gui/Flag.h index 36d196a05..a5f0aaecf 100644 --- a/src/Gui/Flag.h +++ b/src/Gui/Flag.h @@ -29,9 +29,11 @@ #include #include #include +#include namespace Gui { class View3DInventorViewer; + /** * @author Werner Mayer */ @@ -98,6 +100,8 @@ private: class FlagLayout : public QLayout { + Q_OBJECT + public: enum Position { TopLeft, TopRight, BottomLeft, BottomRight }; @@ -136,6 +140,24 @@ private: QList list; }; +class GuiExport GLFlagWindow : public Gui::GLGraphicsItem +{ + TYPESYSTEM_HEADER(); + +public: + GLFlagWindow(View3DInventorViewer*); + virtual ~GLFlagWindow(); + void addFlag(Flag* item, FlagLayout::Position pos); + void removeFlag(Flag* item); + void deleteFlags(); + + void paintGL(); + +private: + View3DInventorViewer* _viewer; + FlagLayout* _flagLayout; +}; + } // namespace Gui diff --git a/src/Gui/GLPainter.cpp b/src/Gui/GLPainter.cpp index 81bffea6c..bfece7710 100644 --- a/src/Gui/GLPainter.cpp +++ b/src/Gui/GLPainter.cpp @@ -31,6 +31,8 @@ using namespace Gui; +TYPESYSTEM_SOURCE_ABSTRACT(Gui::GLGraphicsItem, Base::BaseClass); + GLPainter::GLPainter() : viewer(0), logicOp(false), lineStipple(false) { } diff --git a/src/Gui/GLPainter.h b/src/Gui/GLPainter.h index 170ce6357..287c9d1e2 100644 --- a/src/Gui/GLPainter.h +++ b/src/Gui/GLPainter.h @@ -33,6 +33,8 @@ #include #endif +#include + namespace Gui { class View3DInventorViewer; class GuiExport GLPainter @@ -71,6 +73,20 @@ private: bool lineStipple; }; +class GuiExport GLGraphicsItem : public Base::BaseClass +{ + TYPESYSTEM_HEADER(); + +public: + GLGraphicsItem() + { + } + virtual ~GLGraphicsItem() + { + } + virtual void paintGL() = 0; +}; + } // namespace Gui #endif // GUI_GLPAINTER_H diff --git a/src/Gui/MouseSelection.cpp b/src/Gui/MouseSelection.cpp index dccf87142..d4c53feae 100644 --- a/src/Gui/MouseSelection.cpp +++ b/src/Gui/MouseSelection.cpp @@ -755,6 +755,118 @@ int RectangleSelection::keyboardEvent( const SoKeyboardEvent * const e ) // ----------------------------------------------------------------------------------- +Rubberband::Rubberband() +{ + m_bWorking = false; +} + +Rubberband::~Rubberband() +{ +} + +void Rubberband::initialize() +{ + _pcView3D->setRenderFramebuffer(true); + _pcView3D->scheduleRedraw(); +} + +void Rubberband::terminate() +{ + _pcView3D->setRenderFramebuffer(false); + _pcView3D->scheduleRedraw(); +} + +void Rubberband::redraw() +{ + draw(); +} + +void Rubberband::draw () +{ + if (m_bWorking) { + const SbViewportRegion vp = _pcView3D->getViewportRegion(); + SbVec2s size = vp.getViewportSizePixels(); + + glMatrixMode(GL_PROJECTION); + glOrtho(0, size[0], size[1], 0, 0, 100); + glMatrixMode(GL_MODELVIEW); + glDisable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glLineWidth(4.0); + glColor4f(1.0f, 1.0f, 1.0f, 0.2f); + glRecti(m_iXold, m_iYold, m_iXnew, m_iYnew); + glColor4f(1.0, 1.0, 0.0, 0.5); + glLineStipple(3, 0xAAAA); + glEnable(GL_LINE_STIPPLE); + + glBegin(GL_LINE_LOOP); + glVertex2i(m_iXold, m_iYold); + glVertex2i(m_iXnew, m_iYold); + glVertex2i(m_iXnew, m_iYnew); + glVertex2i(m_iXold, m_iYnew); + glEnd(); + + glLineWidth(1.0); + glDisable(GL_LINE_STIPPLE); + glDisable(GL_BLEND); + } +} + +int Rubberband::mouseButtonEvent(const SoMouseButtonEvent * const e, const QPoint& pos) +{ + const int button = e->getButton(); + const SbBool press = e->getState() == SoButtonEvent::DOWN ? TRUE : FALSE; + + int ret = Continue; + + if (press) { + switch (button) + { + case SoMouseButtonEvent::BUTTON1: + { + m_bWorking = true; + m_iXold = m_iXnew = pos.x(); + m_iYold = m_iYnew = pos.y(); + } break; + default: + { + } break; + } + } + else { + switch (button) { + case SoMouseButtonEvent::BUTTON1: + { + releaseMouseModel(); + m_bWorking = false; + _clPoly.push_back(e->getPosition()); + ret = Finish; + } break; + default: + { + } break; + } + } + + return ret; +} + +int Rubberband::locationEvent(const SoLocation2Event * const e, const QPoint& pos) +{ + m_iXnew = pos.x(); + m_iYnew = pos.y(); + _pcView3D->render(); + return Continue; +} + +int Rubberband::keyboardEvent(const SoKeyboardEvent * const e) +{ + return Continue; +} + +// ----------------------------------------------------------------------------------- + BoxZoomSelection::BoxZoomSelection() { } @@ -765,6 +877,8 @@ BoxZoomSelection::~BoxZoomSelection() void BoxZoomSelection::terminate() { + Rubberband::terminate(); + int xmin = std::min(m_iXold, m_iXnew); int xmax = std::max(m_iXold, m_iXnew); int ymin = std::min(m_iYold, m_iYnew); diff --git a/src/Gui/MouseSelection.h b/src/Gui/MouseSelection.h index b26cdea30..a4d9813d1 100644 --- a/src/Gui/MouseSelection.h +++ b/src/Gui/MouseSelection.h @@ -67,7 +67,7 @@ public: const std::vector& getPositions() const { return _clPoly; } SbBool isInner() const { return m_bInner; } - void redraw(); + virtual void redraw(); /** @name Mouse events*/ //@{ @@ -226,12 +226,43 @@ private: // ----------------------------------------------------------------------------------- +/** + * The selection mouse model class + * Draws a rectangle for selection + * \author Werner Mayer + */ +class GuiExport Rubberband : public BaseMouseSelection +{ +public: + Rubberband(); + virtual ~Rubberband(); + + /// do nothing + virtual void initialize(); + /// do nothing + virtual void terminate(); + +protected: + virtual int mouseButtonEvent( const SoMouseButtonEvent * const e, const QPoint& pos ); + virtual int locationEvent ( const SoLocation2Event * const e, const QPoint& pos ); + virtual int keyboardEvent ( const SoKeyboardEvent * const e ); + + /// draw the rectangle + virtual void draw (); + virtual void redraw(); + +private: + bool m_bWorking; +}; + +// ----------------------------------------------------------------------------------- + /** * The box zoom mouse model class * Draws a rectangle for box zooming * \author Werner Mayer */ -class GuiExport BoxZoomSelection : public RectangleSelection +class GuiExport BoxZoomSelection : public Rubberband { public: BoxZoomSelection(); diff --git a/src/Gui/SoFCDB.cpp b/src/Gui/SoFCDB.cpp index 93f02b8e9..692b13d23 100644 --- a/src/Gui/SoFCDB.cpp +++ b/src/Gui/SoFCDB.cpp @@ -47,6 +47,7 @@ #include "propertyeditor/PropertyItem.h" #include "NavigationStyle.h" +#include "Flag.h" using namespace Gui; using namespace Gui::Inventor; @@ -130,6 +131,9 @@ void Gui::SoFCDB::init() BlenderNavigationStyle ::init(); TouchpadNavigationStyle ::init(); + GLGraphicsItem ::init(); + GLFlagWindow ::init(); + qRegisterMetaType("Base::Vector3f"); qRegisterMetaType("Base::Vector3d"); init_done = TRUE; diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index c53e8b566..e4e08fa4b 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -109,6 +109,7 @@ #include "NavigationStyle.h" #include "ViewProvider.h" #include "SpaceballEvent.h" +#include "GLPainter.h" #include @@ -137,8 +138,8 @@ SOQT_OBJECT_ABSTRACT_SOURCE(View3DInventorViewer); View3DInventorViewer::View3DInventorViewer (QWidget *parent, const char *name, SbBool embed, Type type, SbBool build) - : inherited (parent, name, embed, type, build), editViewProvider(0),navigation(0), - editing(FALSE), redirected(FALSE), allowredir(FALSE) + : inherited (parent, name, embed, type, build), editViewProvider(0), navigation(0), + framebuffer(0), editing(FALSE), redirected(FALSE), allowredir(FALSE) { Gui::Selection().Attach(this); @@ -883,10 +884,134 @@ void View3DInventorViewer::interactionLoggerCB(void * ud, SoAction* action) Base::Console().Log("%s\n", action->getTypeId().getName().getString()); } +void View3DInventorViewer::addGraphicsItem(GLGraphicsItem* item) +{ + this->graphicsItems.push_back(item); +} + +void View3DInventorViewer::removeGraphicsItem(GLGraphicsItem* item) +{ + this->graphicsItems.remove(item); +} + +std::list View3DInventorViewer::getGraphicsItems() const +{ + return graphicsItems; +} + +std::list View3DInventorViewer::getGraphicsItemsOfType(const Base::Type& type) const +{ + std::list items; + for (std::list::const_iterator it = this->graphicsItems.begin(); it != this->graphicsItems.end(); ++it) { + if ((*it)->isDerivedFrom(type)) + items.push_back(*it); + } + return items; +} + +void View3DInventorViewer::clearGraphicsItems() +{ + this->graphicsItems.clear(); +} + +void View3DInventorViewer::setRenderFramebuffer(const SbBool enable) +{ + if (!enable) { + delete framebuffer; + framebuffer = 0; + } + else if (!this->framebuffer) { + const SbViewportRegion vp = this->getViewportRegion(); + SbVec2s origin = vp.getViewportOriginPixels(); + SbVec2s size = vp.getViewportSizePixels(); + + this->glLockNormal(); + this->framebuffer = new QGLFramebufferObject(size[0],size[1],QGLFramebufferObject::Depth); + renderToFramebuffer(this->framebuffer); + } +} + +SbBool View3DInventorViewer::isRenderFramebuffer() const +{ + return this->framebuffer != 0; +} + +void View3DInventorViewer::renderToFramebuffer(QGLFramebufferObject* fbo) +{ + this->glLockNormal(); + fbo->bind(); + + glDisable(GL_TEXTURE_2D); + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); + glEnable(GL_LINE_SMOOTH); + + const SbColor col = this->getBackgroundColor(); + glClearColor(col[0], col[1], col[2], 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glDepthRange(0.1,1.0); + + SoGLRenderAction gl(SbViewportRegion(fbo->size().width(),fbo->size().height())); + gl.apply(this->backgroundroot); + gl.apply(this->getSceneManager()->getSceneGraph()); + gl.apply(this->foregroundroot); + if (this->axiscrossEnabled) { this->drawAxisCross(); } + + fbo->release(); + this->glUnlockNormal(); +} + +void View3DInventorViewer::actualRedraw() +{ + if (this->framebuffer) + renderFramebuffer(); + else + renderScene(); +} + +void View3DInventorViewer::renderFramebuffer() +{ + const SbViewportRegion vp = this->getViewportRegion(); + SbVec2s size = vp.getViewportSizePixels(); + + glDisable(GL_LIGHTING); + glViewport(0, 0, size[0], size[1]); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glDisable(GL_DEPTH_TEST); + + glClear(GL_COLOR_BUFFER_BIT); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, this->framebuffer->texture()); + glColor3f(1.0, 1.0, 1.0); + + glBegin(GL_QUADS); + glTexCoord2f(0.0f, 0.0f); + glVertex2f(-1.0, -1.0f); + glTexCoord2f(1.0f, 0.0f); + glVertex2f(1.0f, -1.0f); + glTexCoord2f(1.0f, 1.0f); + glVertex2f(1.0f, 1.0f); + glTexCoord2f(0.0f, 1.0f); + glVertex2f(-1.0f, 1.0f); + glEnd(); + + printDimension(); + navigation->redraw(); + for (std::list::iterator it = this->graphicsItems.begin(); it != this->graphicsItems.end(); ++it) + (*it)->paintGL(); + + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); +} + // Documented in superclass. Overrides this method to be able to draw // the axis cross, if selected, and to keep a continuous animation // upon spin. -void View3DInventorViewer::actualRedraw(void) +void View3DInventorViewer::renderScene(void) { // Must set up the OpenGL viewport manually, as upon resize // operations, Coin won't set it up until the SoGLRenderAction is @@ -935,29 +1060,19 @@ void View3DInventorViewer::actualRedraw(void) // using the main portion of z-buffer again (for frontbuffer highlighting) glDepthRange(0.1,1.0); - // draw lines for the flags - if (_flaglayout) { - // it can happen that the GL widget gets replaced internally by SoQt which - // causes to destroy the FlagLayout instance - int ct = _flaglayout->count(); - SbViewVolume vv = getCamera()->getViewVolume(getGLAspectRatio()); - for (int i=0; i(_flaglayout->itemAt(i)->widget()); - if (flag) { - SbVec3f pt = flag->getOrigin(); - vv.projectToScreen(pt, pt); - int tox = (int)(pt[0] * size[0]); - int toy = (int)((1.0f-pt[1]) * size[1]); - flag->drawLine(this, tox, toy); - } - } - } - // Immediately reschedule to get continous spin animation. if (this->isAnimating()) { this->scheduleRedraw(); } + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + printDimension(); navigation->redraw(); + for (std::list::iterator it = this->graphicsItems.begin(); it != this->graphicsItems.end(); ++it) + (*it)->paintGL(); + + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); } void View3DInventorViewer::setSeekMode(SbBool on) @@ -2056,16 +2171,3 @@ std::vector View3DInventorViewer::getViewProvidersOfType(const Ba } return views; } - -void View3DInventorViewer::addFlag(Flag* item, FlagLayout::Position pos) -{ - if (!_flaglayout) { - _flaglayout = new FlagLayout(3); - this->getGLWidget()->setLayout(_flaglayout); - } - - item->setParent(this->getGLWidget()); - _flaglayout->addWidget(item, pos); - item->show(); - this->scheduleRedraw(); -} diff --git a/src/Gui/View3DInventorViewer.h b/src/Gui/View3DInventorViewer.h index 8b2e295fb..fa0571292 100644 --- a/src/Gui/View3DInventorViewer.h +++ b/src/Gui/View3DInventorViewer.h @@ -24,17 +24,18 @@ #ifndef GUI_VIEW3DINVENTORVIEWER_H #define GUI_VIEW3DINVENTORVIEWER_H +#include +#include #include -#include +#include #include #include #include #include +#include #include -#include -#include class SoSeparator; @@ -45,6 +46,8 @@ class SbSphereSheetProjector; class SoEventCallback; class SbBox2s; class SoVectorizeAction; +class QGLFramebufferObject; +class QImage; namespace Gui { @@ -54,6 +57,7 @@ class NavigationStyle; class SoFCUnifiedSelection; class Document; class SoFCUnifiedSelection; +class GLGraphicsItem; /** The Inventor viewer * @@ -121,9 +125,19 @@ public: void setFeedbackSize(const int size); int getFeedbackSize(void) const; + void setRenderFramebuffer(const SbBool enable); + SbBool isRenderFramebuffer() const; + void renderToFramebuffer(QGLFramebufferObject*); + virtual void setViewing(SbBool enable); virtual void setCursorEnabled(SbBool enable); + void addGraphicsItem(GLGraphicsItem*); + void removeGraphicsItem(GLGraphicsItem*); + std::list getGraphicsItems() const; + std::list getGraphicsItemsOfType(const Base::Type&) const; + void clearGraphicsItems(); + /** @name Handling of view providers */ //@{ SbBool hasViewProvider(ViewProvider*) const; @@ -267,6 +281,8 @@ public: void setDocument(Gui::Document *pcDocument); protected: + void renderScene(); + void renderFramebuffer(); virtual void actualRedraw(void); virtual void setSeekMode(SbBool enable); virtual void afterRealizeHook(void); @@ -287,10 +303,15 @@ private: static void selectCB(void * closure, SoPath * p); static void deselectCB(void * closure, SoPath * p); static SoPath * pickFilterCB(void * data, const SoPickedPoint * pick); + void initialize(); + void drawAxisCross(void); + static void drawArrow(void); + void setCursorRepresentation(int mode); private: std::set _ViewProviderSet; std::map _ViewProviderMap; + std::list graphicsItems; ViewProvider* editViewProvider; SoFCBackgroundGradient *pcBackGround; SoSeparator * backgroundroot; @@ -302,27 +323,16 @@ private: SoEventCallback* pEventCallback; NavigationStyle* navigation; SoFCUnifiedSelection* selectionRoot; + QGLFramebufferObject* framebuffer; - void initialize(); SbBool axiscrossEnabled; int axiscrossSize; - void drawAxisCross(void); - static void drawArrow(void); - SbBool editing; QCursor editCursor; SbBool redirected; SbBool allowredir; - void setCursorRepresentation(int mode); - -public: - void addFlag(Flag*, FlagLayout::Position); - -private: - QPointer _flaglayout; - // friends friend class NavigationStyle; friend class GLPainter; diff --git a/src/Mod/Inspection/Gui/ViewProviderInspection.cpp b/src/Mod/Inspection/Gui/ViewProviderInspection.cpp index 1783b6380..b31eb4bd9 100644 --- a/src/Mod/Inspection/Gui/ViewProviderInspection.cpp +++ b/src/Mod/Inspection/Gui/ViewProviderInspection.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -388,21 +389,30 @@ public: this->deleteLater(); } + static void addFlag(Gui::View3DInventorViewer* view, const QString& text, const SoPickedPoint * point) + { + Gui::Flag* flag = new Gui::Flag; + QPalette p; + p.setColor(QPalette::Window, QColor(85,0,127)); + p.setColor(QPalette::Text, QColor(220,220,220)); + flag->setPalette(p); + flag->setText(text); + flag->setOrigin(point->getPoint()); + Gui::GLFlagWindow* flags = 0; + std::list glItems = view->getGraphicsItemsOfType(Gui::GLFlagWindow::getClassTypeId()); + if (glItems.empty()) { + flags = new Gui::GLFlagWindow(view); + view->addGraphicsItem(flags); + } + else { + flags = static_cast(glItems.front()); + } + flags->addFlag(flag, Gui::FlagLayout::BottomLeft); + } + private: QPointer widget; }; - -void addFlag(Gui::View3DInventorViewer* view, const QString& text, const SoPickedPoint * point) -{ - Gui::Flag* flag = new Gui::Flag; - QPalette p; - p.setColor(QPalette::Window, QColor(85,0,127)); - p.setColor(QPalette::Text, QColor(220,220,220)); - flag->setPalette(p); - flag->setText(text); - flag->setOrigin(point->getPoint()); - view->addFlag(flag, Gui::FlagLayout::BottomLeft); -} } void ViewProviderInspection::inspectCallback(void * ud, SoEventCallback * n) @@ -456,7 +466,7 @@ void ViewProviderInspection::inspectCallback(void * ud, SoEventCallback * n) QString info = that->inspectDistance(point); Gui::getMainWindow()->setPaneText(1,info); if (addflag) - addFlag(view, info, point); + ViewProviderProxyObject::addFlag(view, info, point); else Gui::ToolTip::showText(QCursor::pos(), info); } @@ -476,7 +486,7 @@ void ViewProviderInspection::inspectCallback(void * ud, SoEventCallback * n) QString info = that->inspectDistance(point); Gui::getMainWindow()->setPaneText(1,info); if (addflag) - addFlag(view, info, point); + ViewProviderProxyObject::addFlag(view, info, point); else Gui::ToolTip::showText(QCursor::pos(), info); break; diff --git a/src/Mod/Mesh/Gui/ViewProvider.cpp b/src/Mod/Mesh/Gui/ViewProvider.cpp index 3682f76e0..5bd84aaa6 100644 --- a/src/Mod/Mesh/Gui/ViewProvider.cpp +++ b/src/Mod/Mesh/Gui/ViewProvider.cpp @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -1258,6 +1259,11 @@ void ViewProviderMesh::faceInfoCallback(void * ud, SoEventCallback * n) view->setEditing(false); view->getWidget()->setCursor(QCursor(Qt::ArrowCursor)); view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), faceInfoCallback,ud); + std::list glItems = view->getGraphicsItemsOfType(Gui::GLFlagWindow::getClassTypeId()); + for (std::list::iterator it = glItems.begin(); it != glItems.end(); ++it) { + view->removeGraphicsItem(*it); + delete *it; + } } } else if (mbe->getButton() == SoMouseButtonEvent::BUTTON1 && mbe->getState() == SoButtonEvent::DOWN) { @@ -1276,14 +1282,24 @@ void ViewProviderMesh::faceInfoCallback(void * ud, SoEventCallback * n) return; ViewProviderMesh* that = static_cast(vp); const SoDetail* detail = point->getDetail(that->getShapeNode()); - if ( detail && detail->getTypeId() == SoFaceDetail::getClassTypeId() ) { + if (detail && detail->getTypeId() == SoFaceDetail::getClassTypeId()) { // get the boundary to the picked facet unsigned long uFacet = ((SoFaceDetail*)detail)->getFaceIndex(); that->faceInfo(uFacet); + Gui::GLFlagWindow* flags = 0; + std::list glItems = view->getGraphicsItemsOfType(Gui::GLFlagWindow::getClassTypeId()); + if (glItems.empty()) { + flags = new Gui::GLFlagWindow(view); + view->addGraphicsItem(flags); + } + else { + flags = static_cast(glItems.front()); + } + Gui::Flag* flag = new Gui::Flag; flag->setText(QObject::tr("Index: %1").arg(uFacet)); flag->setOrigin(point->getPoint()); - view->addFlag(flag, Gui::FlagLayout::TopRight); + flags->addFlag(flag, Gui::FlagLayout::TopRight); } } } diff --git a/src/Mod/Part/Gui/ViewProvider.cpp b/src/Mod/Part/Gui/ViewProvider.cpp index ac9956fe5..9bf99796a 100644 --- a/src/Mod/Part/Gui/ViewProvider.cpp +++ b/src/Mod/Part/Gui/ViewProvider.cpp @@ -73,6 +73,7 @@ # include # include # include +# include #endif /// Here the FreeCAD includes sorted by Base,App,Gui...... diff --git a/src/Mod/Sandbox/Gui/Command.cpp b/src/Mod/Sandbox/Gui/Command.cpp index ea224c528..1a7e9313d 100644 --- a/src/Mod/Sandbox/Gui/Command.cpp +++ b/src/Mod/Sandbox/Gui/Command.cpp @@ -23,6 +23,9 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# ifdef FC_OS_WIN32 +# include +# endif # include # include # include From 7bbe64f58636065762b45a155940161f6b499209 Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 2 May 2013 18:07:06 +0200 Subject: [PATCH 006/160] Fix gcc build failure --- src/Gui/Flag.cpp | 1 + src/Gui/ManualAlignment.cpp | 1 + src/Gui/ManualAlignment.h | 1 + src/Gui/SoFCSelection.cpp | 1 + src/Gui/View3DInventorViewer.cpp | 1 + 5 files changed, 5 insertions(+) diff --git a/src/Gui/Flag.cpp b/src/Gui/Flag.cpp index e95dd1528..43c66e38e 100644 --- a/src/Gui/Flag.cpp +++ b/src/Gui/Flag.cpp @@ -25,6 +25,7 @@ #ifndef _PreComp_ # include # include +# include #endif #include #include "View3DInventorViewer.h" diff --git a/src/Gui/ManualAlignment.cpp b/src/Gui/ManualAlignment.cpp index b3758a3f0..9dd0a9bcc 100644 --- a/src/Gui/ManualAlignment.cpp +++ b/src/Gui/ManualAlignment.cpp @@ -32,6 +32,7 @@ # include # include # include +# include # include # include # include diff --git a/src/Gui/ManualAlignment.h b/src/Gui/ManualAlignment.h index 78a93391f..027d90cce 100644 --- a/src/Gui/ManualAlignment.h +++ b/src/Gui/ManualAlignment.h @@ -24,6 +24,7 @@ #ifndef GUI_MANUALALIGNMENT_H #define GUI_MANUALALIGNMENT_H +#include #include #include #include diff --git a/src/Gui/SoFCSelection.cpp b/src/Gui/SoFCSelection.cpp index f3362d4c2..282ebd98f 100644 --- a/src/Gui/SoFCSelection.cpp +++ b/src/Gui/SoFCSelection.cpp @@ -25,6 +25,7 @@ #ifndef _PreComp_ # include # include +# include # include # include #endif diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index e4e08fa4b..47289e22e 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -73,6 +73,7 @@ # include # include # include +# include # include # include # include From 66bf91b07782be21067366699dfd22cd2a5a97a7 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 3 May 2013 17:03:00 +0200 Subject: [PATCH 007/160] Move GL painting of Rubberband into pimpl class --- src/Gui/MouseSelection.cpp | 102 ++++++++++++++++++++++++------------- src/Gui/MouseSelection.h | 6 +-- 2 files changed, 69 insertions(+), 39 deletions(-) diff --git a/src/Gui/MouseSelection.cpp b/src/Gui/MouseSelection.cpp index d4c53feae..6a3b52d8d 100644 --- a/src/Gui/MouseSelection.cpp +++ b/src/Gui/MouseSelection.cpp @@ -755,36 +755,36 @@ int RectangleSelection::keyboardEvent( const SoKeyboardEvent * const e ) // ----------------------------------------------------------------------------------- -Rubberband::Rubberband() +class Rubberband::Private : public Gui::GLGraphicsItem { - m_bWorking = false; -} - -Rubberband::~Rubberband() -{ -} - -void Rubberband::initialize() -{ - _pcView3D->setRenderFramebuffer(true); - _pcView3D->scheduleRedraw(); -} - -void Rubberband::terminate() -{ - _pcView3D->setRenderFramebuffer(false); - _pcView3D->scheduleRedraw(); -} - -void Rubberband::redraw() -{ - draw(); -} - -void Rubberband::draw () -{ - if (m_bWorking) { - const SbViewportRegion vp = _pcView3D->getViewportRegion(); + Gui::View3DInventorViewer* viewer; + int x_old, y_old, x_new, y_new; + bool working; +public: + Private(Gui::View3DInventorViewer* v) : viewer(v) + { + x_old = y_old = x_new = y_new = 0; + working = false; + } + ~Private() + { + } + void setWorking(bool on) + { + working = on; + } + void setCoords(int x1, int y1, int x2, int y2) + { + x_old = x1; + y_old = y1; + x_new = x2; + y_new = y2; + } + void paintGL() + { + if (!working) + return; + const SbViewportRegion vp = viewer->getViewportRegion(); SbVec2s size = vp.getViewportSizePixels(); glMatrixMode(GL_PROJECTION); @@ -795,22 +795,51 @@ void Rubberband::draw () glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glLineWidth(4.0); glColor4f(1.0f, 1.0f, 1.0f, 0.2f); - glRecti(m_iXold, m_iYold, m_iXnew, m_iYnew); + glRecti(x_old, y_old, x_new, y_new); glColor4f(1.0, 1.0, 0.0, 0.5); glLineStipple(3, 0xAAAA); glEnable(GL_LINE_STIPPLE); glBegin(GL_LINE_LOOP); - glVertex2i(m_iXold, m_iYold); - glVertex2i(m_iXnew, m_iYold); - glVertex2i(m_iXnew, m_iYnew); - glVertex2i(m_iXold, m_iYnew); + glVertex2i(x_old, y_old); + glVertex2i(x_new, y_old); + glVertex2i(x_new, y_new); + glVertex2i(x_old, y_new); glEnd(); glLineWidth(1.0); glDisable(GL_LINE_STIPPLE); glDisable(GL_BLEND); } +}; + +Rubberband::Rubberband() +{ + d = 0; +} + +Rubberband::~Rubberband() +{ +} + +void Rubberband::initialize() +{ + d = new Private(_pcView3D); + _pcView3D->addGraphicsItem(d); + _pcView3D->setRenderFramebuffer(true); + _pcView3D->scheduleRedraw(); +} + +void Rubberband::terminate() +{ + _pcView3D->removeGraphicsItem(d); + delete d; d = 0; + _pcView3D->setRenderFramebuffer(false); + _pcView3D->scheduleRedraw(); +} + +void Rubberband::draw () +{ } int Rubberband::mouseButtonEvent(const SoMouseButtonEvent * const e, const QPoint& pos) @@ -825,7 +854,7 @@ int Rubberband::mouseButtonEvent(const SoMouseButtonEvent * const e, const QPoin { case SoMouseButtonEvent::BUTTON1: { - m_bWorking = true; + d->setWorking(true); m_iXold = m_iXnew = pos.x(); m_iYold = m_iYnew = pos.y(); } break; @@ -838,8 +867,8 @@ int Rubberband::mouseButtonEvent(const SoMouseButtonEvent * const e, const QPoin switch (button) { case SoMouseButtonEvent::BUTTON1: { + d->setWorking(false); releaseMouseModel(); - m_bWorking = false; _clPoly.push_back(e->getPosition()); ret = Finish; } break; @@ -856,6 +885,7 @@ int Rubberband::locationEvent(const SoLocation2Event * const e, const QPoint& po { m_iXnew = pos.x(); m_iYnew = pos.y(); + d->setCoords(m_iXold, m_iYold, m_iXnew, m_iYnew); _pcView3D->render(); return Continue; } diff --git a/src/Gui/MouseSelection.h b/src/Gui/MouseSelection.h index a4d9813d1..0ebb4601f 100644 --- a/src/Gui/MouseSelection.h +++ b/src/Gui/MouseSelection.h @@ -67,7 +67,7 @@ public: const std::vector& getPositions() const { return _clPoly; } SbBool isInner() const { return m_bInner; } - virtual void redraw(); + void redraw(); /** @name Mouse events*/ //@{ @@ -249,10 +249,10 @@ protected: /// draw the rectangle virtual void draw (); - virtual void redraw(); private: - bool m_bWorking; + class Private; + Private* d; }; // ----------------------------------------------------------------------------------- From e18dcef6db77d2c42aee361d7d83727c223ed0ad Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 3 May 2013 18:30:25 +0200 Subject: [PATCH 008/160] Fix crash in property editor of property link is empty --- src/Gui/propertyeditor/PropertyItem.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/Gui/propertyeditor/PropertyItem.cpp b/src/Gui/propertyeditor/PropertyItem.cpp index edb518ba4..c542dc921 100644 --- a/src/Gui/propertyeditor/PropertyItem.cpp +++ b/src/Gui/propertyeditor/PropertyItem.cpp @@ -2111,9 +2111,24 @@ QVariant PropertyLinkItem::value(const App::Property* prop) const const App::PropertyLink* prop_link = static_cast(prop); App::DocumentObject* obj = prop_link->getValue(); QStringList list; - list << QString::fromAscii(obj->getDocument()->getName()); - list << QString::fromAscii(obj->getNameInDocument()); - list << QString::fromUtf8(obj->Label.getValue()); + if (obj) { + list << QString::fromAscii(obj->getDocument()->getName()); + list << QString::fromAscii(obj->getNameInDocument()); + list << QString::fromUtf8(obj->Label.getValue()); + } + else { + App::PropertyContainer* c = prop_link->getContainer(); + if (c->getTypeId().isDerivedFrom(App::DocumentObject::getClassTypeId())) { + App::DocumentObject* obj = static_cast(c); + list << QString::fromAscii(obj->getDocument()->getName()); + } + else { + list << QString::fromAscii(""); + } + list << QString::fromAscii("Null"); + list << QString::fromAscii(""); + } + return QVariant(list); } From 9ad4bb55956e2925484ee86890fb26f4726c5425 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 3 May 2013 21:23:34 +0200 Subject: [PATCH 009/160] Mark attribute 'Type' deprecated, use 'TypeId' now --- src/Base/BaseClassPy.xml | 8 +++++++- src/Base/BaseClassPyImp.cpp | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Base/BaseClassPy.xml b/src/Base/BaseClassPy.xml index 7795e901a..661816822 100644 --- a/src/Base/BaseClassPy.xml +++ b/src/Base/BaseClassPy.xml @@ -26,10 +26,16 @@ - Is the type of the FreeCAD object with module domain + Is the type of the FreeCAD object with module domain (deprecated use TypeId) + + + Is the type of the FreeCAD object with module domain + + + Module in which this class is defined diff --git a/src/Base/BaseClassPyImp.cpp b/src/Base/BaseClassPyImp.cpp index 8ba276066..879123c71 100644 --- a/src/Base/BaseClassPyImp.cpp +++ b/src/Base/BaseClassPyImp.cpp @@ -69,6 +69,13 @@ PyObject* BaseClassPy::getAllDerivedFrom(PyObject *args) } Py::String BaseClassPy::getType(void) const +{ + PyErr_SetString(PyExc_DeprecationWarning, "Use 'TypeId' instead"); + PyErr_Print(); + return Py::String(std::string(getBaseClassPtr()->getTypeId().getName())); +} + +Py::String BaseClassPy::getTypeId(void) const { return Py::String(std::string(getBaseClassPtr()->getTypeId().getName())); } From 2bbe4652291347dbd39116ff768a47b447926865 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 4 May 2013 03:16:34 +0200 Subject: [PATCH 010/160] + Make transient directory of the form ExeName_Doc_{UUID}_{HASH}_{PID} + Set some properties in Document read-only + Implement Document::saveAs + Fix PropertyUUID::setValue() + Add a field for UUID in document information panel --- src/App/Application.cpp | 17 +++ src/App/Document.cpp | 58 ++++++-- src/App/Document.h | 2 + src/App/DocumentPy.xml | 9 +- src/App/DocumentPyImp.cpp | 19 +++ src/App/PropertyStandard.cpp | 11 +- src/Gui/DlgProjectInformation.ui | 205 ++++++++++++++------------- src/Gui/DlgProjectInformationImp.cpp | 1 + src/Gui/Document.cpp | 6 +- 9 files changed, 216 insertions(+), 112 deletions(-) diff --git a/src/App/Application.cpp b/src/App/Application.cpp index e5b27962d..0ddbaa121 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -421,6 +421,23 @@ Document* Application::openDocument(const char * FileName) // read the document newDoc->restore(); + // make sure that the uuid is unique + //FIXME: See Document::saveAs() +#if 0 + std::string uuid = newDoc->Uid.getValueStr(); + for (std::map::iterator it = DocMap.begin(); it != DocMap.end(); ++it) { + if (newDoc != it->second) { + if (uuid == it->second->Uid.getValueStr()) { + Base::Uuid id; + newDoc->Uid.setValue(id); + Base::Console().Warning("Document with the UUID '%s' already exists, change to '%s'\n", + uuid.c_str(), id.getValue().c_str()); + break; + } + } + } +#endif + return newDoc; } diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 5ccde012e..2d09b27fe 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -65,6 +65,9 @@ recompute path. Also enables more complicated dependencies beyond trees. #include #include +#include +#include + #include "Document.h" #include "DocumentPy.h" @@ -525,7 +528,7 @@ Document::Document(void) #endif ADD_PROPERTY_TYPE(Label,("Unnamed"),0,Prop_None,"The name of the document"); - ADD_PROPERTY_TYPE(FileName,(""),0,Prop_None,"The path to the file where the document is saved to"); + ADD_PROPERTY_TYPE(FileName,(""),0,Prop_ReadOnly,"The path to the file where the document is saved to"); ADD_PROPERTY_TYPE(CreatedBy,(""),0,Prop_None,"The creator of the document"); ADD_PROPERTY_TYPE(CreationDate,(Base::TimeInfo::currentDateTimeString()),0,Prop_ReadOnly,"Date of creation"); ADD_PROPERTY_TYPE(LastModifiedBy,(""),0,Prop_None,0); @@ -537,18 +540,17 @@ Document::Document(void) // create the uuid for the document Base::Uuid id; ADD_PROPERTY_TYPE(Id,(""),0,Prop_None,"ID of the document"); - ADD_PROPERTY_TYPE(Uid,(id),0,Prop_None,"UUID of the document"); + ADD_PROPERTY_TYPE(Uid,(id),0,Prop_ReadOnly,"UUID of the document"); // license stuff ADD_PROPERTY_TYPE(License,("CC-BY 3.0"),0,Prop_None,"License string of the Item"); ADD_PROPERTY_TYPE(LicenseURL,("http://creativecommons.org/licenses/by/3.0/"),0,Prop_None,"URL to the license text/contract"); // create transient directory - std::string basePath = Base::FileInfo::getTempPath() + GetApplication().getExecutableName(); - Base::FileInfo TransDir(basePath + "_Doc_" + id.getValue()); + Base::FileInfo TransDir(getTransientDirectoryName(id.getValue(),FileName.getStrValue())); if (!TransDir.exists()) TransDir.createDirectory(); - ADD_PROPERTY_TYPE(TransientDir,(TransDir.filePath().c_str()),0,Prop_Transient, + ADD_PROPERTY_TYPE(TransientDir,(TransDir.filePath().c_str()),0,PropertyType(Prop_Transient|Prop_ReadOnly), "Transient directory, where the files live while the document is open"); } @@ -586,6 +588,19 @@ Document::~Document() delete d; } +std::string Document::getTransientDirectoryName(const std::string& uuid, const std::string& filename) const +{ + // Create a directory name of the form: {ExeName}_Doc_{UUID}_{HASH}_{PID} + std::stringstream s; + QCryptographicHash hash(QCryptographicHash::Sha1); + hash.addData(filename.c_str(), filename.size()); + s << Base::FileInfo::getTempPath() << GetApplication().getExecutableName() + << "_Doc_" << uuid + << "_" << hash.result().toHex().left(6).constData() + << "_" << QCoreApplication::applicationPid(); + return s.str(); +} + //-------------------------------------------------------------------------- // Exported functions //-------------------------------------------------------------------------- @@ -637,9 +652,8 @@ void Document::Restore(Base::XMLReader &reader) Label.setValue(DocLabel.c_str()); // create new transient directory - std::string basePath = Base::FileInfo::getTempPath() + GetApplication().getExecutableName(); - Base::FileInfo TransDirNew(basePath + "_Doc_" + Uid.getValueStr()); - if(!TransDirNew.exists()) + Base::FileInfo TransDirNew(getTransientDirectoryName(Uid.getValueStr(),FileName.getStrValue())); + if (!TransDirNew.exists()) TransDirNew.createDirectory(); TransientDir.setValue(TransDirNew.filePath()); @@ -857,6 +871,34 @@ void Document::exportGraphviz(std::ostream& out) boost::write_graphviz(out, DepList, boost::make_label_writer(&(names[0]))); } +bool Document::saveAs(const char* file) +{ + Base::FileInfo fi(file); + if (this->FileName.getStrValue() != file) { + this->FileName.setValue(file); + this->Label.setValue(fi.fileNamePure()); + + //FIXME: At the moment PropertyFileIncluded doesn't work when renaming this directory. + // PropertyFileIncluded shouldn't store the transient path + //FIXME: Application::openDocument() may assign a new UUID. In order to change the directoy + // name handle this in onChanged() +#if 0 + Base::Uuid id; + Base::FileInfo TransDirNew(getTransientDirectoryName(id.getValue(),this->FileName.getStrValue())); + Base::FileInfo TransDirOld(this->TransientDir.getStrValue()); + // this directory should not exist + if (!TransDirNew.exists()) { + if (TransDirOld.renameFile(TransDirNew.filePath().c_str())) { + this->Uid.setValue(id); + this->TransientDir.setValue(TransDirNew.filePath()); + } + } +#endif + } + + return save(); +} + // Save the document under the name it has been opened bool Document::save (void) { diff --git a/src/App/Document.h b/src/App/Document.h index 5e2eedd89..06a7fbdcb 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -133,6 +133,7 @@ public: //void saveAs (const char* Name); /// Save the document to the file in Property Path bool save (void); + bool saveAs(const char* file); /// Restore the document from the file in Property Path void restore (void); void exportObjects(const std::vector&, std::ostream&); @@ -303,6 +304,7 @@ protected: void _clearRedos(); /// refresh the internal dependency graph void _rebuildDependencyList(void); + std::string getTransientDirectoryName(const std::string& uuid, const std::string& filename) const; private: diff --git a/src/App/DocumentPy.xml b/src/App/DocumentPy.xml index 4a996e111..7aa4b2304 100644 --- a/src/App/DocumentPy.xml +++ b/src/App/DocumentPy.xml @@ -15,12 +15,17 @@ - Save the document to disc + Save the document to disk + + + + + Save the document under a new name to disk - Restore the document from disc + Restore the document from disk diff --git a/src/App/DocumentPyImp.cpp b/src/App/DocumentPyImp.cpp index cc9c40e62..c5225ca11 100644 --- a/src/App/DocumentPyImp.cpp +++ b/src/App/DocumentPyImp.cpp @@ -69,6 +69,25 @@ PyObject* DocumentPy::save(PyObject * args) Py_Return; } +PyObject* DocumentPy::saveAs(PyObject * args) +{ + char* fn; + if (!PyArg_ParseTuple(args, "s", &fn)) // convert args: Python->C + return NULL; // NULL triggers exception + if (!getDocumentPtr()->saveAs(fn)) { + PyErr_Format(PyExc_ValueError, "Object attribute 'FileName' is not set"); + return NULL; + } + + Base::FileInfo fi(fn); + if (!fi.isReadable()) { + PyErr_Format(PyExc_IOError, "No such file or directory: '%s'", fn); + return NULL; + } + + Py_Return; +} + PyObject* DocumentPy::restore(PyObject * args) { if (!PyArg_ParseTuple(args, "")) // convert args: Python->C diff --git a/src/App/PropertyStandard.cpp b/src/App/PropertyStandard.cpp index 9f6c37b6c..73b0df99a 100644 --- a/src/App/PropertyStandard.cpp +++ b/src/App/PropertyStandard.cpp @@ -1348,8 +1348,15 @@ void PropertyUUID::setPyObject(PyObject *value) throw Py::TypeError(error); } - // assign the string - setValue(string); + try { + // assign the string + Base::Uuid uid; + uid.setValue(string); + setValue(uid); + } + catch (const std::exception& e) { + throw Py::RuntimeError(e.what()); + } } void PropertyUUID::Save (Base::Writer &writer) const diff --git a/src/Gui/DlgProjectInformation.ui b/src/Gui/DlgProjectInformation.ui index 60b0378d1..f080e6233 100644 --- a/src/Gui/DlgProjectInformation.ui +++ b/src/Gui/DlgProjectInformation.ui @@ -40,9 +40,6 @@ 6 - - - @@ -56,32 +53,16 @@ - - - - Qt::Vertical - - - QSizePolicy::Expanding - - + + + - 91 - 240 + 0 + 25 - - - - - - Commen&t: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - textEditComment + + true @@ -108,40 +89,30 @@ - - - - - 0 - 25 - - - - - - - - - 0 - 25 - - - - - - + + - &Last modified by: + UUID: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - lineEditLastMod + + + + + + + 0 + 25 + + + + true - + Created &by: @@ -154,20 +125,66 @@ - - + + + + + 0 + 25 + + + + + + - Com&pany: + Creation &date: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - lineEditCompany + lineEditDate + + + + + + + + 0 + 25 + + + + true + + + &Last modified by: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + lineEditLastMod + + + + + + + + 0 + 25 + + + + + Last &modification date: @@ -181,29 +198,6 @@ - - - - 0 - 25 - - - - - - - - - 0 - 25 - - - - true - - - - @@ -216,32 +210,61 @@ - - + + - Creation &date: + Com&pany: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - lineEditDate + lineEditCompany - - + + 0 25 - - true + + + + + + Commen&t: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + textEditComment + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 91 + 240 + + + + @@ -304,14 +327,6 @@ - lineEditName - lineEditCreator - lineEditDate - lineEditLastMod - lineEditLastModDate - lineEditCompany - buttonOk - buttonCancel diff --git a/src/Gui/DlgProjectInformationImp.cpp b/src/Gui/DlgProjectInformationImp.cpp index 5e4b115f0..c5f878693 100644 --- a/src/Gui/DlgProjectInformationImp.cpp +++ b/src/Gui/DlgProjectInformationImp.cpp @@ -46,6 +46,7 @@ DlgProjectInformationImp::DlgProjectInformationImp( App::Document* doc, QWidget* this->setupUi(this); lineEditName->setText(QString::fromUtf8(doc->Label.getValue())); lineEditPath->setText(QString::fromUtf8(doc->FileName.getValue())); + lineEditUuid->setText(QString::fromUtf8(doc->Uid.getValueStr().c_str())); lineEditCreator->setText(QString::fromUtf8(doc->CreatedBy.getValue())); lineEditDate->setText(QString::fromUtf8(doc->CreationDate.getValue())); lineEditLastMod->setText(QString::fromUtf8(doc->LastModifiedBy.getValue())); diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index eca63b7d4..6b7fcb884 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -602,12 +602,8 @@ bool Document::saveAs(void) // save as new file name Gui::WaitCursor wc; - Command::doCommand(Command::Doc,"App.getDocument(\"%s\").FileName = \"%s\"" + Command::doCommand(Command::Doc,"App.getDocument(\"%s\").saveAs('%s')" , DocName, (const char*)fn.toUtf8()); - Command::doCommand(Command::Doc,"App.getDocument(\"%s\").Label = \"%s\"" - , DocName, (const char*)bn.toUtf8()); - Command::doCommand(Command::Doc,"App.getDocument(\"%s\").save()" - , DocName); setModified(false); getMainWindow()->appendRecentFile(fi.filePath()); From 946bd02df4adceda780d9aec61ab6a8e4732ce0f Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 4 May 2013 14:23:53 +0200 Subject: [PATCH 011/160] Improve reporting of Python exceptions --- src/App/Application.cpp | 5 +++-- src/App/DocumentObserverPython.cpp | 14 +++++++------- src/App/FeaturePython.cpp | 4 ++-- src/App/PropertyPythonObject.cpp | 10 +++++----- src/Base/Exception.h | 2 +- src/Base/Interpreter.cpp | 9 +++++++++ src/Base/Interpreter.h | 3 ++- src/Gui/Macro.cpp | 3 +-- src/Gui/PythonConsole.cpp | 2 +- src/Gui/Selection.cpp | 12 ++++++------ src/Gui/TaskView/TaskDialogPython.cpp | 22 ++++++++++----------- src/Gui/ViewProviderPythonFeature.cpp | 28 ++++++++++----------------- 12 files changed, 58 insertions(+), 56 deletions(-) diff --git a/src/App/Application.cpp b/src/App/Application.cpp index 0ddbaa121..518c11c4e 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -1228,9 +1228,10 @@ void Application::processCmdLineFiles(void) Base::Interpreter().runFile(File.filePath().c_str(), true); } else if (File.hasExtension("py")) { - try{ + try { Base::Interpreter().loadModule(File.fileNamePure().c_str()); - }catch(PyException){ + } + catch(const PyException&) { // if module load not work, just try run the script (run in __main__) Base::Interpreter().runFile(File.filePath().c_str(),true); } diff --git a/src/App/DocumentObserverPython.cpp b/src/App/DocumentObserverPython.cpp index eeac4886c..e844ca7b7 100644 --- a/src/App/DocumentObserverPython.cpp +++ b/src/App/DocumentObserverPython.cpp @@ -101,7 +101,7 @@ void DocumentObserverPython::slotCreatedDocument(const App::Document& Doc) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("%s\n", e.what()); + e.ReportException(); } } @@ -118,7 +118,7 @@ void DocumentObserverPython::slotDeletedDocument(const App::Document& Doc) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("%s\n", e.what()); + e.ReportException(); } } @@ -135,7 +135,7 @@ void DocumentObserverPython::slotRelabelDocument(const App::Document& Doc) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("%s\n", e.what()); + e.ReportException(); } } @@ -152,7 +152,7 @@ void DocumentObserverPython::slotActivateDocument(const App::Document& Doc) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("%s\n", e.what()); + e.ReportException(); } } @@ -169,7 +169,7 @@ void DocumentObserverPython::slotCreatedObject(const App::DocumentObject& Obj) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("%s\n", e.what()); + e.ReportException(); } } @@ -186,7 +186,7 @@ void DocumentObserverPython::slotDeletedObject(const App::DocumentObject& Obj) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("%s\n", e.what()); + e.ReportException(); } } @@ -206,6 +206,6 @@ void DocumentObserverPython::slotChangedObject(const App::DocumentObject& Obj, } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("%s\n", e.what()); + e.ReportException(); } } diff --git a/src/App/FeaturePython.cpp b/src/App/FeaturePython.cpp index a4b1a0e12..9348ace12 100644 --- a/src/App/FeaturePython.cpp +++ b/src/App/FeaturePython.cpp @@ -67,6 +67,7 @@ DocumentObjectExecReturn *FeaturePythonImp::execute() } catch (Py::Exception&) { Base::PyException e; // extract the Python error text + e.ReportException(); std::stringstream str; str << object->Label.getValue() << ": " << e.what(); return new App::DocumentObjectExecReturn(str.str()); @@ -104,8 +105,7 @@ void FeaturePythonImp::onChanged(const Property* prop) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("FeaturePython::onChanged (%s): %s\n", - object->Label.getValue(), e.what()); + e.ReportException(); } } diff --git a/src/App/PropertyPythonObject.cpp b/src/App/PropertyPythonObject.cpp index 0cdff1ae8..df42a5a73 100644 --- a/src/App/PropertyPythonObject.cpp +++ b/src/App/PropertyPythonObject.cpp @@ -108,7 +108,7 @@ std::string PropertyPythonObject::toString() const } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Warning("PropertyPythonObject::toString: %s\n", e.what()); + e.ReportException(); } return repr; @@ -139,7 +139,7 @@ void PropertyPythonObject::fromString(const std::string& repr) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Warning("PropertyPythonObject::fromString: %s\n", e.what()); + e.ReportException(); } } @@ -165,7 +165,7 @@ void PropertyPythonObject::loadPickle(const std::string& str) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Warning("PropertyPythonObject::loadPickle: %s\n", e.what()); + e.ReportException(); } } @@ -283,7 +283,7 @@ void PropertyPythonObject::Save (Base::Writer &writer) const } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Warning("PropertyPythonObject::Save: %s\n", e.what()); + e.ReportException(); } saveObject(writer); @@ -350,7 +350,7 @@ void PropertyPythonObject::Restore(Base::XMLReader &reader) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Warning("PropertyPythonObject::Restore: %s\n", e.what()); + e.ReportException(); this->object = Py::None(); load_failed = true; } diff --git a/src/Base/Exception.h b/src/Base/Exception.h index 19bd9155c..d2c4a1ecd 100644 --- a/src/Base/Exception.h +++ b/src/Base/Exception.h @@ -48,7 +48,7 @@ public: Exception &operator=(const Exception &inst); virtual const char* what(void) const throw(); - void ReportException (void) const; + virtual void ReportException (void) const; inline void setMessage(const char * sMessage); inline void setMessage(const std::string& sMessage); diff --git a/src/Base/Interpreter.cpp b/src/Base/Interpreter.cpp index b9676bb9b..548265d98 100644 --- a/src/Base/Interpreter.cpp +++ b/src/Base/Interpreter.cpp @@ -71,9 +71,18 @@ PyException::PyException(void) _stackTrace = PP_last_error_trace; /* exception traceback text */ +} +PyException::~PyException() throw() +{ + PyGILStateLocker locker; PyErr_Clear(); // must be called to keep Python interpreter in a valid state (Werner) +} +void PyException::ReportException (void) const +{ + Base::Console().Error("%s%s: %s\n", + _stackTrace.c_str(), _errorType.c_str(), what()); } // --------------------------------------------------------- diff --git a/src/Base/Interpreter.h b/src/Base/Interpreter.h index a055e8aa2..fb61ccb73 100644 --- a/src/Base/Interpreter.h +++ b/src/Base/Interpreter.h @@ -54,11 +54,12 @@ class BaseExport PyException : public Exception public: /// constructor does the whole job PyException(void); - ~PyException() throw() {} + ~PyException() throw(); /// this function returns the stack trace const std::string &getStackTrace(void) const {return _stackTrace;} const std::string &getErrorType(void) const {return _errorType;} + void ReportException (void) const; protected: std::string _stackTrace; diff --git a/src/Gui/Macro.cpp b/src/Gui/Macro.cpp index 47a82ea20..e2bb6c507 100644 --- a/src/Gui/Macro.cpp +++ b/src/Gui/Macro.cpp @@ -240,8 +240,7 @@ void MacroManager::run(MacroType eType,const char *sName) throw; } catch (const Base::PyException& e) { - Base::Console().Error("%s%s: %s\n", - e.getStackTrace().c_str(), e.getErrorType().c_str(), e.what()); + e.ReportException(); } catch (const Base::Exception& e) { qWarning("%s",e.what()); diff --git a/src/Gui/PythonConsole.cpp b/src/Gui/PythonConsole.cpp index 3f8eb7d48..8783922fa 100644 --- a/src/Gui/PythonConsole.cpp +++ b/src/Gui/PythonConsole.cpp @@ -130,7 +130,7 @@ InteractiveInterpreter::InteractiveInterpreter() Base::PyGILStateLocker lock; PyObject* module = PyImport_ImportModule("code"); if (!module) - throw Base::PyException(); + throw Base::PyException(); PyObject* func = PyObject_GetAttrString(module, "InteractiveInterpreter"); PyObject* args = Py_BuildValue("()"); d = new InteractiveInterpreterP; diff --git a/src/Gui/Selection.cpp b/src/Gui/Selection.cpp index a42da3a64..d9ba9ca99 100644 --- a/src/Gui/Selection.cpp +++ b/src/Gui/Selection.cpp @@ -173,7 +173,7 @@ void SelectionObserverPython::addSelection(const SelectionChanges& msg) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("%s\n", e.what()); + e.ReportException(); } } @@ -192,7 +192,7 @@ void SelectionObserverPython::removeSelection(const SelectionChanges& msg) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("%s\n", e.what()); + e.ReportException(); } } @@ -209,7 +209,7 @@ void SelectionObserverPython::setSelection(const SelectionChanges& msg) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("%s\n", e.what()); + e.ReportException(); } } @@ -226,7 +226,7 @@ void SelectionObserverPython::clearSelection(const SelectionChanges& msg) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("%s\n", e.what()); + e.ReportException(); } } @@ -245,7 +245,7 @@ void SelectionObserverPython::setPreselection(const SelectionChanges& msg) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("%s\n", e.what()); + e.ReportException(); } } @@ -264,7 +264,7 @@ void SelectionObserverPython::removePreselection(const SelectionChanges& msg) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("%s\n", e.what()); + e.ReportException(); } } diff --git a/src/Gui/TaskView/TaskDialogPython.cpp b/src/Gui/TaskView/TaskDialogPython.cpp index fbdb964d8..c921eb110 100644 --- a/src/Gui/TaskView/TaskDialogPython.cpp +++ b/src/Gui/TaskView/TaskDialogPython.cpp @@ -238,7 +238,7 @@ bool TaskWatcherPython::shouldShow() } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("TaskWatcherPython::shouldShow: %s\n", e.what()); + e.ReportException(); } if (!this->Filter.empty()) @@ -329,7 +329,7 @@ void TaskDialogPython::open() } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("TaskDialogPython::open: %s\n", e.what()); + e.ReportException(); } } @@ -346,7 +346,7 @@ void TaskDialogPython::clicked(int i) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("TaskDialogPython::clicked: %s\n", e.what()); + e.ReportException(); } } @@ -363,7 +363,7 @@ bool TaskDialogPython::accept() } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("TaskDialogPython::accept: %s\n", e.what()); + e.ReportException(); } return TaskDialog::accept(); @@ -382,7 +382,7 @@ bool TaskDialogPython::reject() } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("TaskDialogPython::reject: %s\n", e.what()); + e.ReportException(); } return TaskDialog::reject(); @@ -400,7 +400,7 @@ void TaskDialogPython::helpRequested() } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("TaskDialogPython::helpRequested: %s\n", e.what()); + e.ReportException(); } } @@ -418,7 +418,7 @@ QDialogButtonBox::StandardButtons TaskDialogPython::getStandardButtons(void) con } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("TaskDialogPython::getStandardButtons: %s\n", e.what()); + e.ReportException(); } return TaskDialog::getStandardButtons(); @@ -441,7 +441,7 @@ bool TaskDialogPython::isAllowedAlterDocument(void) const } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("TaskDialogPython::isAllowedAlterDocument: %s\n", e.what()); + e.ReportException(); } return TaskDialog::isAllowedAlterDocument(); @@ -460,7 +460,7 @@ bool TaskDialogPython::isAllowedAlterView(void) const } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("TaskDialogPython::isAllowedAlterView: %s\n", e.what()); + e.ReportException(); } return TaskDialog::isAllowedAlterView(); @@ -479,7 +479,7 @@ bool TaskDialogPython::isAllowedAlterSelection(void) const } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("TaskDialogPython::isAllowedAlterSelection: %s\n", e.what()); + e.ReportException(); } return TaskDialog::isAllowedAlterSelection(); @@ -498,7 +498,7 @@ bool TaskDialogPython::needsFullSpace() const } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("TaskDialogPython::needsFullSpace: %s\n", e.what()); + e.ReportException(); } return TaskDialog::needsFullSpace(); diff --git a/src/Gui/ViewProviderPythonFeature.cpp b/src/Gui/ViewProviderPythonFeature.cpp index 059131215..af668ed6a 100644 --- a/src/Gui/ViewProviderPythonFeature.cpp +++ b/src/Gui/ViewProviderPythonFeature.cpp @@ -264,7 +264,7 @@ QIcon ViewProviderPythonFeatureImp::getIcon() const } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("ViewProviderPythonFeature::getIcon: %s\n", e.what()); + e.ReportException(); } return QIcon(); @@ -297,7 +297,7 @@ std::vector ViewProviderPythonFeatureImp::claimChildren(co } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - Base::Console().Error("ViewProviderPythonFeature::claimChildren: %s\n", e.what()); + e.ReportException(); } return children; @@ -342,8 +342,7 @@ bool ViewProviderPythonFeatureImp::setEdit(int ModNum) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - const char* name = object->getObject()->Label.getValue(); - Base::Console().Error("ViewProviderPythonFeature::setEdit (%s): %s\n", name, e.what()); + e.ReportException(); } return false; @@ -378,8 +377,7 @@ bool ViewProviderPythonFeatureImp::unsetEdit(int ModNum) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - const char* name = object->getObject()->Label.getValue(); - Base::Console().Error("ViewProviderPythonFeature::unsetEdit (%s): %s\n", name, e.what()); + e.ReportException(); } return false; @@ -414,8 +412,7 @@ void ViewProviderPythonFeatureImp::attach(App::DocumentObject *pcObject) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - const char* name = object->getObject()->Label.getValue(); - Base::Console().Error("ViewProviderPythonFeature::attach (%s): %s\n", name, e.what()); + e.ReportException(); } } @@ -452,8 +449,7 @@ void ViewProviderPythonFeatureImp::updateData(const App::Property* prop) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - const char* name = object->getObject()->Label.getValue(); - Base::Console().Error("ViewProviderPythonFeature::updateData (%s): %s\n", name, e.what()); + e.ReportException(); } } @@ -486,8 +482,7 @@ void ViewProviderPythonFeatureImp::onChanged(const App::Property* prop) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - const char* name = object->getObject()->Label.getValue(); - Base::Console().Error("ViewProviderPythonFeature::onChanged (%s): %s\n", name, e.what()); + e.ReportException(); } } @@ -529,8 +524,7 @@ const char* ViewProviderPythonFeatureImp::getDefaultDisplayMode() const } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - const char* name = object->getObject()->Label.getValue(); - Base::Console().Error("ViewProviderPythonFeature::getDefaultDisplayMode (%s): %s\n", name, e.what()); + e.ReportException(); } return 0; @@ -570,8 +564,7 @@ std::vector ViewProviderPythonFeatureImp::getDisplayModes(void) con } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - const char* name = object->getObject()->Label.getValue(); - Base::Console().Error("ViewProviderPythonFeature::getDisplayModes (%s): %s\n", name, e.what()); + e.ReportException(); } return modes; @@ -596,8 +589,7 @@ std::string ViewProviderPythonFeatureImp::setDisplayMode(const char* ModeName) } catch (Py::Exception&) { Base::PyException e; // extract the Python error text - const char* name = object->getObject()->Label.getValue(); - Base::Console().Error("ViewProviderPythonFeature::setDisplayMode (%s): %s\n", name, e.what()); + e.ReportException(); } return ModeName; From cb03da1d5c58f3d8a2ad7ea023b9cf7d247411bb Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 4 May 2013 18:05:39 +0200 Subject: [PATCH 012/160] Improve UUID handling of documents --- src/App/Application.cpp | 17 ----------- src/App/Document.cpp | 67 +++++++++++++++++++++++------------------ src/Base/FileInfo.cpp | 1 - 3 files changed, 37 insertions(+), 48 deletions(-) diff --git a/src/App/Application.cpp b/src/App/Application.cpp index 518c11c4e..f5d1c2e3a 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -421,23 +421,6 @@ Document* Application::openDocument(const char * FileName) // read the document newDoc->restore(); - // make sure that the uuid is unique - //FIXME: See Document::saveAs() -#if 0 - std::string uuid = newDoc->Uid.getValueStr(); - for (std::map::iterator it = DocMap.begin(); it != DocMap.end(); ++it) { - if (newDoc != it->second) { - if (uuid == it->second->Uid.getValueStr()) { - Base::Uuid id; - newDoc->Uid.setValue(id); - Base::Console().Warning("Document with the UUID '%s' already exists, change to '%s'\n", - uuid.c_str(), id.getValue().c_str()); - break; - } - } - } -#endif - return newDoc; } diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 2d09b27fe..2a5dc33a4 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -436,8 +436,39 @@ unsigned int Document::getMaxUndoStackSize(void)const void Document::onChanged(const Property* prop) { // the Name property is a label for display purposes - if (prop == &Label) + if (prop == &Label) { App::GetApplication().signalRelabelDocument(*this); + } + else if (prop == &Uid) { + std::string new_dir = getTransientDirectoryName(this->Uid.getValueStr(),this->FileName.getStrValue()); + std::string old_dir = this->TransientDir.getStrValue(); + Base::FileInfo TransDirNew(new_dir); + Base::FileInfo TransDirOld(old_dir); + // this directory should not exist + if (!TransDirNew.exists()) { + if (TransDirOld.exists()) { + if (!TransDirOld.renameFile(new_dir.c_str())) + Base::Console().Warning("Failed to rename '%s' to '%s'\n", old_dir.c_str(), new_dir.c_str()); + else + this->TransientDir.setValue(new_dir); + } + else { + if (!TransDirNew.createDirectory()) + Base::Console().Warning("Failed to create '%s'\n", new_dir.c_str()); + else + this->TransientDir.setValue(new_dir); + } + } + // make sure that the uuid is unique + else { + std::string uuid = this->Uid.getValueStr(); + Base::Uuid id; + Base::Console().Warning("Document with the UUID '%s' already exists, change to '%s'\n", + uuid.c_str(), id.getValue().c_str()); + // recursive call of onChanged() + this->Uid.setValue(id); + } + } } void Document::onBeforeChangeProperty(const DocumentObject *Who, const Property *What) @@ -546,12 +577,10 @@ Document::Document(void) ADD_PROPERTY_TYPE(License,("CC-BY 3.0"),0,Prop_None,"License string of the Item"); ADD_PROPERTY_TYPE(LicenseURL,("http://creativecommons.org/licenses/by/3.0/"),0,Prop_None,"URL to the license text/contract"); - // create transient directory - Base::FileInfo TransDir(getTransientDirectoryName(id.getValue(),FileName.getStrValue())); - if (!TransDir.exists()) - TransDir.createDirectory(); - ADD_PROPERTY_TYPE(TransientDir,(TransDir.filePath().c_str()),0,PropertyType(Prop_Transient|Prop_ReadOnly), + // this creates and sets 'TransientDir' in onChanged() + ADD_PROPERTY_TYPE(TransientDir,(""),0,PropertyType(Prop_Transient|Prop_ReadOnly), "Transient directory, where the files live while the document is open"); + Uid.touch(); } Document::~Document() @@ -638,12 +667,7 @@ void Document::Restore(Base::XMLReader &reader) std::string FilePath = FileName.getValue(); std::string DocLabel = Label.getValue(); - // remove previous Transient directory - Base::FileInfo TransDir(TransientDir.getValue()); - TransDir.deleteDirectoryRecursive(); - - - // read the Document Properties + // read the Document Properties, when reading in Uid the transient directory gets renamed automatically PropertyContainer::Restore(reader); // We must restore the correct 'FileName' property again because the stored @@ -651,13 +675,6 @@ void Document::Restore(Base::XMLReader &reader) FileName.setValue(FilePath.c_str()); Label.setValue(DocLabel.c_str()); - // create new transient directory - Base::FileInfo TransDirNew(getTransientDirectoryName(Uid.getValueStr(),FileName.getStrValue())); - if (!TransDirNew.exists()) - TransDirNew.createDirectory(); - TransientDir.setValue(TransDirNew.filePath()); - - // SchemeVersion "2" if ( scheme == 2 ) { // read the feature types @@ -880,19 +897,9 @@ bool Document::saveAs(const char* file) //FIXME: At the moment PropertyFileIncluded doesn't work when renaming this directory. // PropertyFileIncluded shouldn't store the transient path - //FIXME: Application::openDocument() may assign a new UUID. In order to change the directoy - // name handle this in onChanged() #if 0 Base::Uuid id; - Base::FileInfo TransDirNew(getTransientDirectoryName(id.getValue(),this->FileName.getStrValue())); - Base::FileInfo TransDirOld(this->TransientDir.getStrValue()); - // this directory should not exist - if (!TransDirNew.exists()) { - if (TransDirOld.renameFile(TransDirNew.filePath().c_str())) { - this->Uid.setValue(id); - this->TransientDir.setValue(TransDirNew.filePath()); - } - } + this->Uid.setValue(id); #endif } diff --git a/src/Base/FileInfo.cpp b/src/Base/FileInfo.cpp index 0309cda32..d90043d8c 100644 --- a/src/Base/FileInfo.cpp +++ b/src/Base/FileInfo.cpp @@ -428,7 +428,6 @@ bool FileInfo::renameFile(const char* NewName) #else # error "FileInfo::renameFile() not implemented for this platform!" #endif - setFile(NewName); return res; } From b198248535f53be74886e4cb8c51f5a4b9ce5eec Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 5 May 2013 01:24:28 +0200 Subject: [PATCH 013/160] Fix XML reading in property class --- src/App/PropertyStandard.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App/PropertyStandard.cpp b/src/App/PropertyStandard.cpp index 73b0df99a..4ec89060d 100644 --- a/src/App/PropertyStandard.cpp +++ b/src/App/PropertyStandard.cpp @@ -845,7 +845,7 @@ void PropertyIntegerSet::Restore(Base::XMLReader &reader) values.insert(reader.getAttributeAsInteger("v")); } - reader.readEndElement("IntegerList"); + reader.readEndElement("IntegerSet"); //assignment setValues(values); From 1aff25a62d2e94bdc39bad85e422988f79a5282a Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 6 May 2013 08:27:25 +0200 Subject: [PATCH 014/160] Fix data loss in PropertyFileIncluded --- src/App/Document.cpp | 7 -- src/App/Property.h | 2 +- src/App/PropertyFile.cpp | 151 ++++++++++++++++++++++++++------------- src/App/PropertyFile.h | 13 ++-- src/Base/FileInfo.cpp | 20 ++---- src/Mod/Test/Document.py | 37 ++++++---- 6 files changed, 140 insertions(+), 90 deletions(-) diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 2a5dc33a4..6af947de5 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -894,13 +894,6 @@ bool Document::saveAs(const char* file) if (this->FileName.getStrValue() != file) { this->FileName.setValue(file); this->Label.setValue(fi.fileNamePure()); - - //FIXME: At the moment PropertyFileIncluded doesn't work when renaming this directory. - // PropertyFileIncluded shouldn't store the transient path -#if 0 - Base::Uuid id; - this->Uid.setValue(id); -#endif } return save(); diff --git a/src/App/Property.h b/src/App/Property.h index b1046aa34..13f79d8fd 100644 --- a/src/App/Property.h +++ b/src/App/Property.h @@ -61,7 +61,7 @@ public: */ virtual unsigned int getMemSize (void) const { // you have to implement this method in all property classes! - return Base::Persistence::getMemSize() + sizeof(father) + sizeof(StatusBits); + return sizeof(father) + sizeof(StatusBits); } /// get the name of this property in the belonging container diff --git a/src/App/PropertyFile.cpp b/src/App/PropertyFile.cpp index 934023272..d2168498e 100644 --- a/src/App/PropertyFile.cpp +++ b/src/App/PropertyFile.cpp @@ -24,6 +24,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include # include #endif @@ -35,6 +36,7 @@ #include #include #include +#include #include "PropertyFile.h" #include "Document.h" @@ -53,6 +55,7 @@ using namespace std; TYPESYSTEM_SOURCE(App::PropertyFileIncluded , App::Property); + PropertyFileIncluded::PropertyFileIncluded() { @@ -69,11 +72,24 @@ PropertyFileIncluded::~PropertyFileIncluded() std::string PropertyFileIncluded::getDocTransientPath(void) const { + std::string path; PropertyContainer *co = getContainer(); - if (co->isDerivedFrom(DocumentObject::getClassTypeId())) - return dynamic_cast(co)->getDocument()->TransientDir.getValue(); + if (co->isDerivedFrom(DocumentObject::getClassTypeId())) { + path = dynamic_cast(co)->getDocument()->TransientDir.getValue(); + std::replace(path.begin(), path.end(), '\\', '/'); + } + return path; +} - return std::string(); +std::string PropertyFileIncluded::getUniqueFileName(const std::string& path, const std::string& filename) const +{ + Base::Uuid uuid; + Base::FileInfo fi(path + "/" + filename); + while (fi.exists()) { + fi.setFile(path + "/" + filename + "." + uuid.getValue()); + } + + return fi.filePath(); } std::string PropertyFileIncluded::getExchangeTempFile(void) const @@ -97,7 +113,7 @@ void PropertyFileIncluded::setValue(const char* sFile, const char* sName) throw Base::Exception(str.str()); } - aboutToSetValue(); // undo redo by move the file away with temp name + aboutToSetValue(); // undo/redo by moving the file away with temp name // remove old file (if not moved by undo) Base::FileInfo value(_cValue); @@ -133,10 +149,9 @@ void PropertyFileIncluded::setValue(const char* sFile, const char* sName) _BaseFileName = file.fileName(); } - // if the files is already in transient dir of the document, just use it + // if the file is already in transient dir of the document, just use it if (path == pathTrans) { bool done = file.renameFile(_cValue.c_str()); - //assert(done); if (!done) { std::stringstream str; str << "Cannot rename file " << file.filePath() << " to " << _cValue; @@ -160,7 +175,6 @@ void PropertyFileIncluded::setValue(const char* sFile, const char* sName) } bool done = file.copyTo(_cValue.c_str()); - //assert(done); if (!done) { std::stringstream str; str << "Cannot copy file from " << file.filePath() << " to " << _cValue; @@ -180,7 +194,7 @@ const char* PropertyFileIncluded::getValue(void) const PyObject *PropertyFileIncluded::getPyObject(void) { PyObject *p = PyUnicode_DecodeUTF8(_cValue.c_str(),_cValue.size(),0); - if (!p) throw Base::Exception("UTF8 conversion failure at PropertyString::getPyObject()"); + if (!p) throw Base::Exception("PropertyFileIncluded: UTF-8 conversion failure"); return p; } @@ -201,7 +215,7 @@ void PropertyFileIncluded::setPyObject(PyObject *value) } else if (PyTuple_Check(value)) { if (PyTuple_Size(value) != 2) - throw Py::TypeError("Tuple need size of (filePath,newFileName)"); + throw Py::TypeError("Tuple needs size of (filePath,newFileName)"); PyObject* file = PyTuple_GetItem(value,0); PyObject* name = PyTuple_GetItem(value,1); @@ -220,7 +234,7 @@ void PropertyFileIncluded::setPyObject(PyObject *value) fileStr = PyString_AsString(FileName); } else { - std::string error = std::string("first in tuple must be a file or string"); + std::string error = std::string("First item in tuple must be a file or string"); error += value->ob_type->tp_name; throw Py::TypeError(error); } @@ -235,7 +249,7 @@ void PropertyFileIncluded::setPyObject(PyObject *value) nameStr = PyString_AsString(FileName); } else { - std::string error = std::string("second in tuple must be a string"); + std::string error = std::string("Second item in tuple must be a string"); error += value->ob_type->tp_name; throw Py::TypeError(error); } @@ -245,7 +259,7 @@ void PropertyFileIncluded::setPyObject(PyObject *value) } else { - std::string error = std::string("type must be str or file"); + std::string error = std::string("Type must be string or file"); error += value->ob_type->tp_name; throw Py::TypeError(error); } @@ -256,29 +270,40 @@ void PropertyFileIncluded::setPyObject(PyObject *value) void PropertyFileIncluded::Save (Base::Writer &writer) const { +#if 0 + // when saving a document under a new file name the transient directory + // name changes and thus the stored file name doesn't work any more. + if (!_cValue.empty() && !Base::FileInfo(_cValue).exists()) { + Base::FileInfo fi(getDocTransientPath() + "/" + _BaseFileName); + if (fi.exists()) + _cValue = fi.filePath(); + } +#endif if (writer.isForceXML()) { if (!_cValue.empty()) { Base::FileInfo file(_cValue.c_str()); - writer.Stream() << writer.ind() << "" << std::endl; + writer.Stream() << writer.ind() << "" << std::endl; // write the file in the XML stream writer.incInd(); writer.insertBinFile(_cValue.c_str()); writer.decInd(); writer.Stream() << writer.ind() <<"" << endl; } - else + else { writer.Stream() << writer.ind() << "" << std::endl; + } } else { // instead initiate an extra file if (!_cValue.empty()) { Base::FileInfo file(_cValue.c_str()); - writer.Stream() << writer.ind() << "" << std::endl; + writer.Stream() << writer.ind() << "" << std::endl; } - else + else { writer.Stream() << writer.ind() << "" << std::endl; + } } } @@ -315,9 +340,12 @@ void PropertyFileIncluded::Restore(Base::XMLReader &reader) void PropertyFileIncluded::SaveDocFile (Base::Writer &writer) const { Base::ifstream from(Base::FileInfo(_cValue.c_str())); - if (!from) - throw Base::Exception("PropertyFileIncluded::SaveDocFile() " - "File in document transient dir deleted"); + if (!from) { + std::stringstream str; + str << "PropertyFileIncluded::SaveDocFile(): " + << "File '" << _cValue << "' in transient directory doesn't exist."; + throw Base::Exception(str.str()); + } // copy plain data unsigned char c; @@ -330,9 +358,12 @@ void PropertyFileIncluded::SaveDocFile (Base::Writer &writer) const void PropertyFileIncluded::RestoreDocFile(Base::Reader &reader) { Base::ofstream to(Base::FileInfo(_cValue.c_str())); - if (!to) - throw Base::Exception("PropertyFileIncluded::RestoreDocFile() " - "File in document transient dir deleted"); + if (!to) { + std::stringstream str; + str << "PropertyFileIncluded::RestoreDocFile(): " + << "File '" << _cValue << "' in transient directory doesn't exist."; + throw Base::Exception(str.str()); + } // copy plain data aboutToSetValue(); @@ -351,18 +382,23 @@ Property *PropertyFileIncluded::Copy(void) const // remember the base name prop->_BaseFileName = _BaseFileName; - if (!_cValue.empty()) { - Base::FileInfo file(_cValue); - + Base::FileInfo file(_cValue); + if (file.exists()) { // create a new name in the document transient directory - Base::FileInfo NewName(Base::FileInfo::getTempFileName(file.fileName().c_str(),file.dirPath().c_str())); - NewName.deleteFile(); - // move the file - bool done = file.renameFile(NewName.filePath().c_str()); - assert(done); + Base::FileInfo newName(getUniqueFileName(file.dirPath(), file.fileName())); + // copy the file + bool done = file.copyTo(newName.filePath().c_str()); + if (!done) { + std::stringstream str; + str << "PropertyFileIncluded::Copy(): " + << "Copying the file '" << file.filePath() << "' to '" + << newName.filePath() << "' failed."; + throw Base::Exception(str.str()); + } + // remember the new name for the Undo - Base::Console().Log("Copy this=%p Before=%s After=%s\n",prop,prop->_cValue.c_str(),NewName.filePath().c_str()); - prop->_cValue = NewName.filePath().c_str(); + Base::Console().Log("Copy '%s' to '%s'\n",_cValue.c_str(),newName.filePath().c_str()); + prop->_cValue = newName.filePath().c_str(); } return prop; @@ -371,26 +407,45 @@ Property *PropertyFileIncluded::Copy(void) const void PropertyFileIncluded::Paste(const Property &from) { aboutToSetValue(); - Base::FileInfo file(_cValue); - // delete old file (if still there) - file.deleteFile(); - const PropertyFileIncluded &fileInc = dynamic_cast(from); + const PropertyFileIncluded &prop = dynamic_cast(from); + // make sure that source and destination file are different + if (_cValue != prop._cValue) { + // delete old file (if still there) + Base::FileInfo(_cValue).deleteFile(); - // set the base name - _BaseFileName = fileInc._BaseFileName; + // get path to destination which can be the transient directory + // of another document + std::string path = getDocTransientPath(); + Base::FileInfo fiSrc(prop._cValue); + Base::FileInfo fiDst(path + "/" + prop._BaseFileName); + if (fiSrc.exists()) { + fiDst.setFile(getUniqueFileName(fiDst.dirPath(), fiDst.fileName())); + if (!fiSrc.copyTo(fiDst.filePath().c_str())) { + std::stringstream str; + str << "PropertyFileIncluded::Paste(): " + << "Copying the file '" << fiSrc.filePath() << "' to '" + << fiDst.filePath() << "' failed."; + throw Base::Exception(str.str()); + } + _cValue = fiDst.filePath(); + } + else { + _cValue.clear(); + } - if (!fileInc._cValue.empty()) { - // move the saved files back in place - Base::FileInfo NewFile(fileInc._cValue); - _cValue = NewFile.dirPath() + "/" + fileInc._BaseFileName; - bool done = NewFile.renameFile(_cValue.c_str()); - assert(done); + // set the base name + _BaseFileName = prop._BaseFileName; } - else - _cValue.clear(); hasSetValue(); } +unsigned int PropertyFileIncluded::getMemSize (void) const +{ + unsigned int mem = Property::getMemSize(); + mem += _cValue.size(); + mem += _BaseFileName.size(); + return mem; +} //************************************************************************** // PropertyFile diff --git a/src/App/PropertyFile.h b/src/App/PropertyFile.h index 270fe35c9..9aff9b258 100644 --- a/src/App/PropertyFile.h +++ b/src/App/PropertyFile.h @@ -95,9 +95,7 @@ public: virtual Property *Copy(void) const; virtual void Paste(const Property &from); - - // get the transient path if the property is in a DocumentObject - std::string getDocTransientPath(void) const; + virtual unsigned int getMemSize (void) const; /** get a temp file name in the transient path of the document. * Using this file for new Version of the file and set @@ -107,8 +105,13 @@ public: std::string getExchangeTempFile(void) const; protected: - std::string _cValue; - std::string _BaseFileName; + // get the transient path if the property is in a DocumentObject + std::string getDocTransientPath(void) const; + std::string getUniqueFileName(const std::string&, const std::string&) const; + +protected: + mutable std::string _cValue; + mutable std::string _BaseFileName; }; diff --git a/src/Base/FileInfo.cpp b/src/Base/FileInfo.cpp index d90043d8c..9577cd05f 100644 --- a/src/Base/FileInfo.cpp +++ b/src/Base/FileInfo.cpp @@ -26,6 +26,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include # include # include # include @@ -188,22 +189,13 @@ std::string FileInfo::getTempFileName(const char* FileName, const char* Path) void FileInfo::setFile(const char* name) { - std::string result; - const char *It=name; - - while(*It != '\0') { - switch(*It) - { - case '\\': - result += "/"; - break; - default: - result += *It; - } - It++; + if (!name) { + FileName.clear(); + return; } - FileName = result; + FileName = name; + std::replace(FileName.begin(), FileName.end(), '\\', '/'); } std::string FileInfo::filePath () const diff --git a/src/Mod/Test/Document.py b/src/Mod/Test/Document.py index 981149fb4..914433f82 100644 --- a/src/Mod/Test/Document.py +++ b/src/Mod/Test/Document.py @@ -180,7 +180,6 @@ class DocumentSaveRestoreCases(unittest.TestCase): def testSaveAndRestore(self): # saving and restoring SaveName = self.TempPath + os.sep + "SaveRestoreTests.FCStd" - self.Doc.FileName = SaveName self.failUnless(self.Doc.Label_1.TypeTransient == 4711) self.Doc.Label_1.TypeTransient = 4712 # setup Linking @@ -189,7 +188,7 @@ class DocumentSaveRestoreCases(unittest.TestCase): self.Doc.Label_1.LinkSub = (self.Doc.Label_2,["Sub1","Sub2"]) self.Doc.Label_2.LinkSub = (self.Doc.Label_1,["Sub3","Sub4"]) # save the document - self.Doc.save() + self.Doc.saveAs(SaveName) FreeCAD.closeDocument("SaveRestoreTests") self.Doc = FreeCAD.open(SaveName) self.failUnless(self.Doc.Label_1.Integer == 4711) @@ -207,8 +206,8 @@ class DocumentSaveRestoreCases(unittest.TestCase): Doc = FreeCAD.newDocument("RestoreTests") Doc.addObject("App::FeatureTest","Label_1") # saving and restoring - Doc.FileName = self.TempPath + os.sep + "Test2.FCStd" - Doc.save() + FileName = self.TempPath + os.sep + "Test2.FCStd" + Doc.saveAs(FileName) # restore must first clear the current content Doc.restore() self.failUnless(len(Doc.Objects) == 1) @@ -563,13 +562,12 @@ class DocumentPlatformCases(unittest.TestCase): self.Doc.addObject("App::FeatureTest", "Test") self.TempPath = tempfile.gettempdir() self.DocName = self.TempPath + os.sep + "PlatformTests.FCStd" - self.Doc.FileName = self.DocName def testFloatList(self): self.Doc.Test.FloatList = [-0.05, 2.5, 5.2] # saving and restoring - self.Doc.save() + self.Doc.saveAs(self.DocName) FreeCAD.closeDocument("PlatformTests") self.Doc = FreeCAD.open(self.DocName) @@ -581,7 +579,7 @@ class DocumentPlatformCases(unittest.TestCase): self.Doc.Test.ColourList = [(1.0,0.5,0.0),(0.0,0.5,1.0)] # saving and restoring - self.Doc.save() + self.Doc.saveAs(self.DocName) FreeCAD.closeDocument("PlatformTests") self.Doc = FreeCAD.open(self.DocName) @@ -598,7 +596,7 @@ class DocumentPlatformCases(unittest.TestCase): self.Doc.Test.VectorList = [(-0.05, 2.5, 5.2),(-0.05, 2.5, 5.2)] # saving and restoring - self.Doc.save() + self.Doc.saveAs(self.DocName) FreeCAD.closeDocument("PlatformTests") self.Doc = FreeCAD.open(self.DocName) @@ -609,7 +607,7 @@ class DocumentPlatformCases(unittest.TestCase): self.Doc.addObject("Points::Feature", "Points") # saving and restoring - self.Doc.save() + self.Doc.saveAs(self.DocName) FreeCAD.closeDocument("PlatformTests") self.Doc = FreeCAD.open(self.DocName) @@ -679,10 +677,10 @@ class DocumentFileIncludeCases(unittest.TestCase): self.failUnless(file.read()=="test No2") file.close() # Save restore test - self.Doc.FileName = self.TempPath+"/FileIncludeTest.fcstd" - self.Doc.save() + FileName = self.TempPath+"/FileIncludeTests.fcstd" + self.Doc.saveAs(FileName) FreeCAD.closeDocument("FileIncludeTests") - self.Doc = FreeCAD.open(self.TempPath+"/FileIncludeTest.fcstd") + self.Doc = FreeCAD.open(self.TempPath+"/FileIncludeTests.fcstd") # check if the file is still there self.L1 = self.Doc.getObject("FileObject1") file = open(self.L1.File,"r") @@ -715,10 +713,20 @@ class DocumentFileIncludeCases(unittest.TestCase): self.failUnless(file.read()=="test No2") file.close() + # create a second document, copy a file and close the document + # the test is about to put the file to the correct transient dir + doc2 = FreeCAD.newDocument("Doc2") + L4 = doc2.addObject("App::DocumentObjectFileIncluded","FileObject") + L4.File = (L3.File,"Test.txt") + FreeCAD.closeDocument("FileIncludeTests") + self.Doc = FreeCAD.open(self.TempPath+"/FileIncludeTests.fcstd") + self.failUnless(os.path.exists(L4.File)) + FreeCAD.closeDocument("Doc2") + def tearDown(self): #closing doc - FreeCAD.closeDocument("FileIncludeTest") + FreeCAD.closeDocument("FileIncludeTests") class DocumentPropertyCases(unittest.TestCase): @@ -733,8 +741,7 @@ class DocumentPropertyCases(unittest.TestCase): self.Obj.addProperty(i,i) tempPath = tempfile.gettempdir() tempFile = tempPath + os.sep + "PropertyTests.FCStd" - self.Doc.FileName = tempFile - self.Doc.save() + self.Doc.saveAs(tempFile) FreeCAD.closeDocument("PropertyTests") self.Doc = FreeCAD.open(tempFile) From 95b2a1cd2b87ae44da7bb5310509aa1c0242b644 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 6 May 2013 10:51:25 +0200 Subject: [PATCH 015/160] Fix another data loss issue in PropertyFileIncluded --- src/App/PropertyFile.cpp | 47 +++++++++++++++++++++++++--------------- src/Mod/Test/Document.py | 7 ++++++ 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/App/PropertyFile.cpp b/src/App/PropertyFile.cpp index d2168498e..77f5953ba 100644 --- a/src/App/PropertyFile.cpp +++ b/src/App/PropertyFile.cpp @@ -123,24 +123,28 @@ void PropertyFileIncluded::setValue(const char* sFile, const char* sName) // if a special name given, use this instead if (sName) { - Base::FileInfo ExtraName(path + "/" + sName); - if (ExtraName.exists() ) { + Base::FileInfo fi(pathTrans + "/" + sName); + if (fi.exists()) { // if a file with this name already exists search for a new one + std::string dir = pathTrans; + std::string fnp = fi.fileNamePure(); + std::string ext = fi.extension(false); int i=0; - do { i++; std::stringstream str; - str << path << "/" << sName << i; - ExtraName.setFile(str.str()); + str << dir << "/" << fnp << i; + if (!ext.empty()) + str << "." << ext; + fi.setFile(str.str()); } - while (ExtraName.exists()); - _cValue = ExtraName.filePath(); - _BaseFileName = ExtraName.fileName(); + while (fi.exists()); + _cValue = fi.filePath(); + _BaseFileName = fi.fileName(); } else { - _cValue = path + "/" + sName; + _cValue = pathTrans + "/" + sName; _BaseFileName = sName; } } @@ -163,15 +167,23 @@ void PropertyFileIncluded::setValue(const char* sFile, const char* sName) // if file already exists in transient dir make a new unique name Base::FileInfo fi(_cValue); if (fi.exists()) { - Base::FileInfo fi2(Base::FileInfo::getTempFileName()); - std::stringstream str; - str << fi.dirPath() << "/" << fi2.fileNamePure(); + // if a file with this name already exists search for a new one + std::string dir = fi.dirPath(); + std::string fnp = fi.fileNamePure(); std::string ext = fi.extension(false); - if (!ext.empty()) - str << "." << ext; - Base::FileInfo fi3(str.str()); - _cValue = fi3.filePath(); - _BaseFileName = fi3.fileName(); + int i=0; + do { + i++; + std::stringstream str; + str << dir << "/" << fnp << i; + if (!ext.empty()) + str << "." << ext; + fi.setFile(str.str()); + } + while (fi.exists()); + + _cValue = fi.filePath(); + _BaseFileName = fi.fileName(); } bool done = file.copyTo(_cValue.c_str()); @@ -256,7 +268,6 @@ void PropertyFileIncluded::setPyObject(PyObject *value) setValue(fileStr.c_str(),nameStr.c_str()); return; - } else { std::string error = std::string("Type must be string or file"); diff --git a/src/Mod/Test/Document.py b/src/Mod/Test/Document.py index 914433f82..9618f5c96 100644 --- a/src/Mod/Test/Document.py +++ b/src/Mod/Test/Document.py @@ -717,10 +717,17 @@ class DocumentFileIncludeCases(unittest.TestCase): # the test is about to put the file to the correct transient dir doc2 = FreeCAD.newDocument("Doc2") L4 = doc2.addObject("App::DocumentObjectFileIncluded","FileObject") + L5 = doc2.addObject("App::DocumentObjectFileIncluded","FileObject") + L6 = doc2.addObject("App::DocumentObjectFileIncluded","FileObject") L4.File = (L3.File,"Test.txt") + L5.File = L3.File + L6.File = L3.File FreeCAD.closeDocument("FileIncludeTests") self.Doc = FreeCAD.open(self.TempPath+"/FileIncludeTests.fcstd") self.failUnless(os.path.exists(L4.File)) + self.failUnless(os.path.exists(L5.File)) + self.failUnless(os.path.exists(L6.File)) + self.failUnless(L5.File != L6.File) FreeCAD.closeDocument("Doc2") From 62710779a70af65236662146bfd5a8a73da1c26f Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 6 May 2013 11:28:13 +0200 Subject: [PATCH 016/160] Rename transient directory when saving document under new file --- src/App/Document.cpp | 7 +++++-- src/App/PropertyFile.cpp | 3 +-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 6af947de5..fb9f28a37 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -459,8 +459,10 @@ void Document::onChanged(const Property* prop) this->TransientDir.setValue(new_dir); } } - // make sure that the uuid is unique - else { + // when reloading an existing document the transient directory doesn't change + // so we must avoid to generate a new uuid + else if (TransDirNew.filePath() != TransDirOld.filePath()) { + // make sure that the uuid is unique std::string uuid = this->Uid.getValueStr(); Base::Uuid id; Base::Console().Warning("Document with the UUID '%s' already exists, change to '%s'\n", @@ -894,6 +896,7 @@ bool Document::saveAs(const char* file) if (this->FileName.getStrValue() != file) { this->FileName.setValue(file); this->Label.setValue(fi.fileNamePure()); + this->Uid.touch(); // this forces a rename of the transient directory } return save(); diff --git a/src/App/PropertyFile.cpp b/src/App/PropertyFile.cpp index 77f5953ba..ba2488765 100644 --- a/src/App/PropertyFile.cpp +++ b/src/App/PropertyFile.cpp @@ -281,7 +281,6 @@ void PropertyFileIncluded::setPyObject(PyObject *value) void PropertyFileIncluded::Save (Base::Writer &writer) const { -#if 0 // when saving a document under a new file name the transient directory // name changes and thus the stored file name doesn't work any more. if (!_cValue.empty() && !Base::FileInfo(_cValue).exists()) { @@ -289,7 +288,7 @@ void PropertyFileIncluded::Save (Base::Writer &writer) const if (fi.exists()) _cValue = fi.filePath(); } -#endif + if (writer.isForceXML()) { if (!_cValue.empty()) { Base::FileInfo file(_cValue.c_str()); From 50559c4b173a96dd87370202135c070d4399c1fe Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 6 May 2013 12:27:25 +0200 Subject: [PATCH 017/160] One more fix to avoid loss of data --- src/App/PropertyFile.cpp | 10 +++++++++- src/Mod/Test/Document.py | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/App/PropertyFile.cpp b/src/App/PropertyFile.cpp index ba2488765..65fbca44c 100644 --- a/src/App/PropertyFile.cpp +++ b/src/App/PropertyFile.cpp @@ -153,6 +153,12 @@ void PropertyFileIncluded::setValue(const char* sFile, const char* sName) _BaseFileName = file.fileName(); } + // That's wrong and can lead to loss of data!!! + // Just consider the example that two objects with this property + // exist in the same document and as an initial step the data are + // copied from one object to the other. A rename will cause the one + // object to loose its data. +#if 0 // if the file is already in transient dir of the document, just use it if (path == pathTrans) { bool done = file.renameFile(_cValue.c_str()); @@ -163,7 +169,9 @@ void PropertyFileIncluded::setValue(const char* sFile, const char* sName) } } // otherwise copy from origin location - else { + else +#endif + { // if file already exists in transient dir make a new unique name Base::FileInfo fi(_cValue); if (fi.exists()) { diff --git a/src/Mod/Test/Document.py b/src/Mod/Test/Document.py index 9618f5c96..2662adf42 100644 --- a/src/Mod/Test/Document.py +++ b/src/Mod/Test/Document.py @@ -728,6 +728,10 @@ class DocumentFileIncludeCases(unittest.TestCase): self.failUnless(os.path.exists(L5.File)) self.failUnless(os.path.exists(L6.File)) self.failUnless(L5.File != L6.File) + # copy file from L5 which is in the same directory + L7 = doc2.addObject("App::DocumentObjectFileIncluded","FileObject3") + L7.File = (L5.File,"Copy.txt") + self.failUnless(os.path.exists(L5.File)) FreeCAD.closeDocument("Doc2") From 8cf9dba3bafacca6fd3170f3de31d111b8e52e39 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 6 May 2013 12:50:31 +0200 Subject: [PATCH 018/160] Add python example of how to use splines --- src/Mod/TemplatePyMod/SplineSurface.py | 43 ++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/Mod/TemplatePyMod/SplineSurface.py diff --git a/src/Mod/TemplatePyMod/SplineSurface.py b/src/Mod/TemplatePyMod/SplineSurface.py new file mode 100644 index 000000000..d69708bfb --- /dev/null +++ b/src/Mod/TemplatePyMod/SplineSurface.py @@ -0,0 +1,43 @@ + +# http://de.wikipedia.org/wiki/Non-Uniform_Rational_B-Spline +# len(knot_u) := nNodes_u + degree_u + 1 +# len(knot_v) := nNodes_v + degree_v + 1 + +degree_u=2 +degree_v=2 +nNodes_u=5 +nNodes_v=5 + +#knot_u=[0,0,0,0.3333,0.6666,1,1,1] +#knot_v=[0,0,0,0.3333,0.6666,1,1,1] +knot_u=[0,0,0,0.2,0.7,1,1,1] +knot_v=[0,0,0,0.2,0.7,1,1,1] +#knot_u=[0,0,0.2,0.4,0.6,0.8,1,1] +#knot_v=[0,0,0.2,0.4,0.6,0.8,1,1] +coor=[[0,0,1],[1,0,2],[2,0,0],[3,0,1],[4,0,2],\ + [0,1,2],[1,1,0],[2,1,0],[3,1,0],[4,1,0],\ + [0,2,0],[1,2,0],[2,2,0],[3,2,0],[4,2,0],\ + [0,3,1],[1,3,0],[2,3,0],[3,3,3],[4,3,0],\ + [0,4,2],[1,4,0],[2,4,0],[3,4,0],[4,4,0]] + +bs=Part.BSplineSurface() +bs.increaseDegree(degree_u,degree_v) + +id=1 +for i in range(0,len(knot_u)-1): + if knot_u[i+1] > knot_u[i]: + bs.insertUKnot(knot_u[i],id,0.0000001) + +id=1 +for i in range(0,len(knot_v)-1): + if knot_v[i+1] > knot_v[i]: + bs.insertVKnot(knot_v[i],id,0.0000001) + +i=0 +for jj in range(0,nNodes_v): + for ii in range(0,nNodes_u): + bs.setPole(ii+1,jj+1,FreeCAD.Vector((coor[i][0],coor[i][1],coor[i][2])),1); + i=i+1; + +s=bs.toShape() +Part.show(s) From 9971dca73c20bc2012392665665aac1ec0439889 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 6 May 2013 12:51:47 +0200 Subject: [PATCH 019/160] Add copyright notice --- src/Mod/TemplatePyMod/SplineSurface.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mod/TemplatePyMod/SplineSurface.py b/src/Mod/TemplatePyMod/SplineSurface.py index d69708bfb..b946b1293 100644 --- a/src/Mod/TemplatePyMod/SplineSurface.py +++ b/src/Mod/TemplatePyMod/SplineSurface.py @@ -1,3 +1,5 @@ +# FreeCAD TemplatePyMod module +# (c) 2013 Werner Mayer LGPL # http://de.wikipedia.org/wiki/Non-Uniform_Rational_B-Spline # len(knot_u) := nNodes_u + degree_u + 1 From 7c5ff7cec9d85d10e1702ec4552a6202571dfa78 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 6 May 2013 15:34:56 +0200 Subject: [PATCH 020/160] Do not allow to drag and drop child items of non-group objects in tree view --- src/Gui/Tree.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index c2b328445..a10cf015b 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -340,6 +340,15 @@ QMimeData * TreeWidget::mimeData (const QList items) const doc = obj->getDocument(); else if (doc != obj->getDocument()) return 0; + // Now check for object with a parent that is an ObjectType, too. + // If this object is *not* a group we are not allowed to remove + // its child (e.g. the sketch of a pad). + QTreeWidgetItem* parent = (*it)->parent(); + if (parent && parent->type() == TreeWidget::ObjectType) { + App::DocumentObject* par = static_cast(parent)->object()->getObject(); + if (!par->getTypeId().isDerivedFrom(App::DocumentObjectGroup::getClassTypeId())) + return 0; + } } return QTreeWidget::mimeData(items); } From ab8a8cd37184753af60e7ee3b76eb074d83fe97b Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 7 May 2013 15:35:51 +0200 Subject: [PATCH 021/160] Remove unneeded code --- src/Mod/Mesh/Gui/RemoveComponents.cpp | 207 +------------------------- src/Mod/Mesh/Gui/RemoveComponents.h | 47 ------ 2 files changed, 3 insertions(+), 251 deletions(-) diff --git a/src/Mod/Mesh/Gui/RemoveComponents.cpp b/src/Mod/Mesh/Gui/RemoveComponents.cpp index a66e3f500..a9d869e69 100644 --- a/src/Mod/Mesh/Gui/RemoveComponents.cpp +++ b/src/Mod/Mesh/Gui/RemoveComponents.cpp @@ -23,46 +23,14 @@ #include "PreCompiled.h" -#ifndef _PreComp_ -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include +#ifndef _PreComp_ +# include #endif #include "RemoveComponents.h" #include "ui_RemoveComponents.h" -#include "ViewProvider.h" -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include using namespace MeshGui; @@ -186,175 +154,6 @@ void RemoveComponents::reject() // deselect all meshes meshSel.clearSelection(); } - -void RemoveComponents::paintSelection() -{ -#if 0 - SoAnnotation* hudRoot = new SoAnnotation; - hudRoot->ref(); - - SoOrthographicCamera* hudCam = new SoOrthographicCamera(); - hudCam->viewportMapping = SoCamera::LEAVE_ALONE; - // Set the position in the window. - // [0, 0] is in the center of the screen. - // - SoTranslation* hudTrans = new SoTranslation; - hudTrans->translation.setValue(-1.0f, -1.0f, 0.0f); - - QImage image(100,100,QImage::Format_ARGB32_Premultiplied); - image.fill(0x00000000); - SoSFImage sfimage; - Gui::BitmapFactory().convert(image, sfimage); - SoImage* hudImage = new SoImage(); - hudImage->image = sfimage; - - // Assemble the parts... - // - hudRoot->addChild(hudCam); - hudRoot->addChild(hudTrans); - hudRoot->addChild(hudImage); - - Gui::View3DInventorViewer* viewer = this->getViewer(); - static_cast(viewer->getSceneGraph())->addChild(hudRoot); - - QWidget* gl = viewer->getGLWidget(); - DrawingPlane pln(hudImage->image, viewer, gl); - gl->installEventFilter(&pln); - QEventLoop loop; - QObject::connect(&pln, SIGNAL(emitSelection()), &loop, SLOT(quit())); - loop.exec(); - static_cast(viewer->getSceneGraph())->removeChild(hudRoot); -#endif -} - -// --------------------------------------- - -DrawingPlane::DrawingPlane(SoSFImage& data, SoQtViewer* s, QWidget* view) - : QObject(), data(data), glView(view), soqt(s), image(view->size(), QImage::Format_ARGB32) -{ - image.fill(qRgba(255, 255, 255, 0)); - - myPenWidth = 50; - - QRgb p = qRgba(255,255,0,0); - int q = ((p << 16) & 0xff0000) | ((p >> 16) & 0xff) | (p & 0xff00ff00); - int r = qRed(q); - int g = qGreen(q); - int b = qBlue(q); - myPenColor = qRgb(r,g,b);//Qt::yellow; - myRadius = 5.0f; -} - -DrawingPlane::~DrawingPlane() -{ -} - -void DrawingPlane::changeRadius(double radius) -{ - this->myRadius = (double)radius; -} - -void DrawingPlane::mousePressEvent(QMouseEvent *event) -{ - // Calculate the given radius from mm into px - const SbViewportRegion& vp = soqt->getViewportRegion(); - float fRatio = vp.getViewportAspectRatio(); - const SbVec2s& sp = vp.getViewportSizePixels(); - float dX, dY; vp.getViewportSize().getValue(dX, dY); - SbViewVolume vv = soqt->getCamera()->getViewVolume(fRatio); - - SbVec3f p1(0,0,0); - SbVec3f p2(0,this->myRadius,0); - vv.projectToScreen(p1, p1); - vv.projectToScreen(p2, p2); - - if (fRatio > 1.0f) { - p1[0] = (p1[0] - 0.5f*dX) / fRatio + 0.5f*dX; - p2[0] = (p2[0] - 0.5f*dX) / fRatio + 0.5f*dX; - } - else if (fRatio < 1.0f) { - p1[1] = (p1[1] - 0.5f*dY) * fRatio + 0.5f*dY; - p2[1] = (p2[1] - 0.5f*dY) * fRatio + 0.5f*dY; - } - - int x1 = p1[0] * sp[0]; - int y1 = p1[1] * sp[1]; - int x2 = p2[0] * sp[0]; - int y2 = p2[1] * sp[1]; - - //myPenWidth = 2*abs(y1-y2); - - if (event->button() == Qt::LeftButton) { - lastPoint = event->pos(); - scribbling = true; - } -} - -void DrawingPlane::mouseMoveEvent(QMouseEvent *event) -{ - if ((event->buttons() & Qt::LeftButton) && scribbling) { - const QPoint& pos = event->pos(); - drawLineTo(pos); - - // filter out some points - if (selection.isEmpty()) { - selection << pos; - } - else { - const QPoint& top = selection.last(); - if (abs(top.x()-pos.x()) > 20 || - abs(top.y()-pos.y()) > 20) - selection << pos; - } - } -} - -void DrawingPlane::mouseReleaseEvent(QMouseEvent *event) -{ - if (event->button() == Qt::LeftButton && scribbling) { - drawLineTo(event->pos()); - scribbling = false; - /*emit*/ emitSelection(); - } -} - -bool DrawingPlane::eventFilter(QObject* o, QEvent* e) -{ - if (o == glView) { - if (e->type() == QEvent::Resize) - resizeEvent(static_cast(e)); - else if (e->type() == QEvent::MouseButtonPress) - mousePressEvent(static_cast(e)); - else if (e->type() == QEvent::MouseButtonRelease) - mouseReleaseEvent(static_cast(e)); - else if (e->type() == QEvent::MouseMove) - mouseMoveEvent(static_cast(e)); - } - - return false; -} - -void DrawingPlane::resizeEvent(QResizeEvent *event) -{ - QImage img(event->size(), QImage::Format_ARGB32); - img.fill(qRgba(255, 255, 255, 0)); - image = img; -} - -void DrawingPlane::drawLineTo(const QPoint &endPoint) -{ - QPainter painter(&image); - painter.setPen(QPen(myPenColor, myPenWidth, Qt::SolidLine, Qt::RoundCap, - Qt::RoundJoin)); - painter.setOpacity(0.5); - painter.drawLine(lastPoint.x(), image.height()-lastPoint.y(), endPoint.x(), image.height()-endPoint.y()); - - QImage img = image;//QGLWidget::convertToGLFormat(image); - int nc = img.numBytes() / ( img.width() * img.height() ); - data.setValue(SbVec2s(img.width(), img.height()), nc, img.bits()); - soqt->scheduleRedraw(); - lastPoint = endPoint; -} // ------------------------------------------------- diff --git a/src/Mod/Mesh/Gui/RemoveComponents.h b/src/Mod/Mesh/Gui/RemoveComponents.h index 96f25a131..57801811a 100644 --- a/src/Mod/Mesh/Gui/RemoveComponents.h +++ b/src/Mod/Mesh/Gui/RemoveComponents.h @@ -29,55 +29,9 @@ #include #include "MeshSelection.h" -// forward declarations -class SoNode; -class SoQtViewer; -class SoSFImage; -namespace App { class DocumentObject; } -namespace Gui { class View3DInventorViewer; } -namespace Gui { class Document; } -namespace Mesh { class Feature; } - namespace MeshGui { -class ViewProviderMesh; class Ui_RemoveComponents; -class DrawingPlane : public QObject -{ - Q_OBJECT - -public: - DrawingPlane(SoSFImage&, SoQtViewer*, QWidget* view); - virtual ~DrawingPlane(); - -protected: - void mousePressEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - void resizeEvent(QResizeEvent *event); - bool eventFilter(QObject* o, QEvent* e); - -protected Q_SLOTS: - void changeRadius(double); - -Q_SIGNALS: - void emitSelection(); - -private: - void drawLineTo(const QPoint &endPoint); - - bool scribbling; - int myPenWidth; - float myRadius; - QColor myPenColor; - QPoint lastPoint; - QList selection; - QImage image; - SoSFImage& data; - SoQtViewer* soqt; - QWidget* glView; -}; - /** * Non-modal dialog to de/select components, regions, the complete or single faces * of a mesh and delete them. @@ -110,7 +64,6 @@ public Q_SLOTS: protected: void changeEvent(QEvent *e); - void paintSelection(); private: Ui_RemoveComponents* ui; From 9a9510d9e34c507a7d9a24f9cc9a111659d2b151 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 7 May 2013 22:42:58 +0200 Subject: [PATCH 022/160] Make file read-only once assigned to a PropertyFileIncluded instance --- src/App/Document.cpp | 2 +- src/App/PropertyFile.cpp | 128 ++++++++++++++++++++++++++++++--------- src/App/PropertyFile.h | 1 + src/Base/FileInfo.cpp | 57 +++++++++++++---- src/Base/FileInfo.h | 10 ++- 5 files changed, 155 insertions(+), 43 deletions(-) diff --git a/src/App/Document.cpp b/src/App/Document.cpp index fb9f28a37..3707e5193 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -607,7 +607,7 @@ Document::~Document() // Remark: The API of Py::Object has been changed to set whether the wrapper owns the passed // Python object or not. In the constructor we forced the wrapper to own the object so we need // not to dec'ref the Python object any more. - // But we must still invalidate the Python object because it need not to be + // But we must still invalidate the Python object because it doesn't need to be // destructed right now because the interpreter can own several references to it. Base::PyObjectBase* doc = (Base::PyObjectBase*)DocumentPythonObject.ptr(); // Call before decrementing the reference counter, otherwise a heap error can occur diff --git a/src/App/PropertyFile.cpp b/src/App/PropertyFile.cpp index 65fbca44c..221ad82c3 100644 --- a/src/App/PropertyFile.cpp +++ b/src/App/PropertyFile.cpp @@ -42,7 +42,7 @@ #include "Document.h" #include "PropertyContainer.h" #include "DocumentObject.h" -#define new DEBUG_CLIENTBLOCK + using namespace App; using namespace Base; using namespace std; @@ -66,10 +66,25 @@ PropertyFileIncluded::~PropertyFileIncluded() // clean up if (!_cValue.empty()) { Base::FileInfo file(_cValue.c_str()); + file.setPermissions(Base::FileInfo::ReadWrite); file.deleteFile(); } } +void PropertyFileIncluded::aboutToSetValue(void) +{ + // This is a trick to check in Copy() if it is called + // directly from outside or by the Undo/Redo mechanism. + // In the latter case it is sufficient to rename the file + // because another file will be assigned afterwards. + // If Copy() is directly called (e.g. to copy the file to + // another document) a copy of the file needs to be created. + // This copy will be deleted again in the class destructor. + this->StatusBits.set(10); + Property::aboutToSetValue(); + this->StatusBits.reset(10); +} + std::string PropertyFileIncluded::getDocTransientPath(void) const { std::string path; @@ -118,8 +133,10 @@ void PropertyFileIncluded::setValue(const char* sFile, const char* sName) // remove old file (if not moved by undo) Base::FileInfo value(_cValue); std::string pathAct = value.dirPath(); - if (value.exists()) + if (value.exists()) { + value.setPermissions(Base::FileInfo::ReadWrite); value.deleteFile(); + } // if a special name given, use this instead if (sName) { @@ -153,25 +170,29 @@ void PropertyFileIncluded::setValue(const char* sFile, const char* sName) _BaseFileName = file.fileName(); } - // That's wrong and can lead to loss of data!!! - // Just consider the example that two objects with this property - // exist in the same document and as an initial step the data are - // copied from one object to the other. A rename will cause the one - // object to loose its data. -#if 0 + // The following applies only on files that are inside the transient + // directory: + // When a file is read-only it is supposed to be assigned to a + // PropertyFileIncluded instance. In this case we must copy the + // file because otherwise the above instance looses its data. + // If the file is writable it is supposed to be of free use and + // it can be simply renamed. + // if the file is already in transient dir of the document, just use it - if (path == pathTrans) { + if (path == pathTrans && file.isWritable()) { bool done = file.renameFile(_cValue.c_str()); if (!done) { std::stringstream str; str << "Cannot rename file " << file.filePath() << " to " << _cValue; throw Base::Exception(str.str()); } + + // make the file read-only + Base::FileInfo dst(_cValue); + dst.setPermissions(Base::FileInfo::ReadOnly); } // otherwise copy from origin location - else -#endif - { + else { // if file already exists in transient dir make a new unique name Base::FileInfo fi(_cValue); if (fi.exists()) { @@ -200,6 +221,10 @@ void PropertyFileIncluded::setValue(const char* sFile, const char* sName) str << "Cannot copy file from " << file.filePath() << " to " << _cValue; throw Base::Exception(str.str()); } + + // make the file read-only + Base::FileInfo dst(_cValue); + dst.setPermissions(Base::FileInfo::ReadOnly); } hasSetValue(); @@ -350,6 +375,9 @@ void PropertyFileIncluded::Restore(Base::XMLReader &reader) reader.readBinFile(_cValue.c_str()); reader.readEndElement("FileIncluded"); _BaseFileName = file; + // set read-only after restoring the file + Base::FileInfo fi(_cValue.c_str()); + fi.setPermissions(Base::FileInfo::ReadOnly); hasSetValue(); } } @@ -375,7 +403,8 @@ void PropertyFileIncluded::SaveDocFile (Base::Writer &writer) const void PropertyFileIncluded::RestoreDocFile(Base::Reader &reader) { - Base::ofstream to(Base::FileInfo(_cValue.c_str())); + Base::FileInfo fi(_cValue.c_str()); + Base::ofstream to(fi); if (!to) { std::stringstream str; str << "PropertyFileIncluded::RestoreDocFile(): " @@ -390,6 +419,9 @@ void PropertyFileIncluded::RestoreDocFile(Base::Reader &reader) to.put((const char)c); } to.close(); + + // set read-only after restoring the file + fi.setPermissions(Base::FileInfo::ReadOnly); hasSetValue(); } @@ -404,19 +436,35 @@ Property *PropertyFileIncluded::Copy(void) const if (file.exists()) { // create a new name in the document transient directory Base::FileInfo newName(getUniqueFileName(file.dirPath(), file.fileName())); - // copy the file - bool done = file.copyTo(newName.filePath().c_str()); - if (!done) { - std::stringstream str; - str << "PropertyFileIncluded::Copy(): " - << "Copying the file '" << file.filePath() << "' to '" - << newName.filePath() << "' failed."; - throw Base::Exception(str.str()); + if (this->StatusBits.test(10)) { + // rename the file + bool done = file.renameFile(newName.filePath().c_str()); + if (!done) { + std::stringstream str; + str << "PropertyFileIncluded::Copy(): " + << "Renaming the file '" << file.filePath() << "' to '" + << newName.filePath() << "' failed."; + throw Base::Exception(str.str()); + } + } + else { + // copy the file + bool done = file.copyTo(newName.filePath().c_str()); + if (!done) { + std::stringstream str; + str << "PropertyFileIncluded::Copy(): " + << "Copying the file '" << file.filePath() << "' to '" + << newName.filePath() << "' failed."; + throw Base::Exception(str.str()); + } } // remember the new name for the Undo Base::Console().Log("Copy '%s' to '%s'\n",_cValue.c_str(),newName.filePath().c_str()); prop->_cValue = newName.filePath().c_str(); + + // make backup files writable to avoid copying them again on undo/redo + newName.setPermissions(Base::FileInfo::ReadWrite); } return prop; @@ -429,22 +477,42 @@ void PropertyFileIncluded::Paste(const Property &from) // make sure that source and destination file are different if (_cValue != prop._cValue) { // delete old file (if still there) - Base::FileInfo(_cValue).deleteFile(); + Base::FileInfo fi(_cValue); + fi.setPermissions(Base::FileInfo::ReadWrite); + fi.deleteFile(); // get path to destination which can be the transient directory // of another document - std::string path = getDocTransientPath(); + std::string pathTrans = getDocTransientPath(); Base::FileInfo fiSrc(prop._cValue); - Base::FileInfo fiDst(path + "/" + prop._BaseFileName); + Base::FileInfo fiDst(pathTrans + "/" + prop._BaseFileName); + std::string path = fiSrc.dirPath(); + if (fiSrc.exists()) { fiDst.setFile(getUniqueFileName(fiDst.dirPath(), fiDst.fileName())); - if (!fiSrc.copyTo(fiDst.filePath().c_str())) { - std::stringstream str; - str << "PropertyFileIncluded::Paste(): " - << "Copying the file '" << fiSrc.filePath() << "' to '" - << fiDst.filePath() << "' failed."; - throw Base::Exception(str.str()); + + // if the file is already in transient dir of the document, just use it + if (path == pathTrans) { + if (!fiSrc.renameFile(fiDst.filePath().c_str())) { + std::stringstream str; + str << "PropertyFileIncluded::Paste(): " + << "Renaming the file '" << fiSrc.filePath() << "' to '" + << fiDst.filePath() << "' failed."; + throw Base::Exception(str.str()); + } } + else { + if (!fiSrc.copyTo(fiDst.filePath().c_str())) { + std::stringstream str; + str << "PropertyFileIncluded::Paste(): " + << "Copying the file '" << fiSrc.filePath() << "' to '" + << fiDst.filePath() << "' failed."; + throw Base::Exception(str.str()); + } + } + + // set the file again read-only + fiDst.setPermissions(Base::FileInfo::ReadOnly); _cValue = fiDst.filePath(); } else { diff --git a/src/App/PropertyFile.h b/src/App/PropertyFile.h index 9aff9b258..d69f93148 100644 --- a/src/App/PropertyFile.h +++ b/src/App/PropertyFile.h @@ -108,6 +108,7 @@ protected: // get the transient path if the property is in a DocumentObject std::string getDocTransientPath(void) const; std::string getUniqueFileName(const std::string&, const std::string&) const; + void aboutToSetValue(void); protected: mutable std::string _cValue; diff --git a/src/Base/FileInfo.cpp b/src/Base/FileInfo.cpp index 9577cd05f..6e8119f0c 100644 --- a/src/Base/FileInfo.cpp +++ b/src/Base/FileInfo.cpp @@ -52,10 +52,20 @@ #include #include -#define new DEBUG_CLIENTBLOCK - using namespace Base; +#ifndef R_OK +#define R_OK 4 /* Test for read permission */ +#endif +#ifndef W_OK +#define W_OK 2 /* Test for write permission */ +#endif +#ifndef X_OK +#define X_OK 1 /* Test for execute permission */ +#endif +#ifndef F_OK +#define F_OK 0 /* Test for existence */ +#endif //********************************************************************************** // helper @@ -263,9 +273,9 @@ bool FileInfo::exists () const { #if defined (FC_OS_WIN32) std::wstring wstr = toStdWString(); - return _waccess(wstr.c_str(),0) == 0; + return _waccess(wstr.c_str(),F_OK) == 0; #elif defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD) - return access(FileName.c_str(),0) == 0; + return access(FileName.c_str(),F_OK) == 0; #endif } @@ -273,9 +283,9 @@ bool FileInfo::isReadable () const { #if defined (FC_OS_WIN32) std::wstring wstr = toStdWString(); - return _waccess(wstr.c_str(),4) == 0; + return _waccess(wstr.c_str(),R_OK) == 0; #elif defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD) - return access(FileName.c_str(),4) == 0; + return access(FileName.c_str(),R_OK) == 0; #endif } @@ -283,9 +293,29 @@ bool FileInfo::isWritable () const { #if defined (FC_OS_WIN32) std::wstring wstr = toStdWString(); - return _waccess(wstr.c_str(),2) == 0; + return _waccess(wstr.c_str(),W_OK) == 0; #elif defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD) - return access(FileName.c_str(),2) == 0; + return access(FileName.c_str(),W_OK) == 0; +#endif +} + +bool FileInfo::setPermissions (Permissions perms) +{ + bool ret = false; + int mode = 0; + + if (perms & FileInfo::ReadOnly) + mode |= S_IREAD; + if (perms & FileInfo::WriteOnly) + mode |= S_IWRITE; + + if (mode == 0) // bad argument + return false; +#if defined (FC_OS_WIN32) + std::wstring wstr = toStdWString(); + return _wchmod(wstr.c_str(),mode) == 0; +#elif defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD) + return chmod(FileName.c_str(),mode) == 0; #endif } @@ -473,12 +503,17 @@ bool FileInfo::deleteDirectoryRecursive(void) const std::vector List = getDirectoryContent(); for (std::vector::iterator It = List.begin();It!=List.end();++It) { - if (It->isDir()) + if (It->isDir()) { + It->setPermissions(FileInfo::ReadWrite); It->deleteDirectoryRecursive(); - else if(It->isFile()) + } + else if (It->isFile()) { + It->setPermissions(FileInfo::ReadWrite); It->deleteFile(); - else + } + else { Base::Exception("FileInfo::deleteDirectoryRecursive(): Unknown object Type in directory!"); + } } return deleteDirectory(); } diff --git a/src/Base/FileInfo.h b/src/Base/FileInfo.h index f541dc216..52fd77548 100644 --- a/src/Base/FileInfo.h +++ b/src/Base/FileInfo.h @@ -42,6 +42,12 @@ namespace Base class BaseExport FileInfo { public: + enum Permissions { + WriteOnly = 0x01, + ReadOnly = 0x02, + ReadWrite = 0x03, + }; + /// Constrction FileInfo (const char* _FileName=""); FileInfo (const std::string &_FileName); @@ -89,6 +95,8 @@ public: bool isReadable () const; /// Checks if the file exist and is writable bool isWritable () const; + /// Tries to set the file permisson + bool setPermissions (Permissions); /// Checks if it is a file (not a direrctory) bool isFile () const; /// Checks if it is a directory (not a file) @@ -109,7 +117,7 @@ public: std::vector getDirectoryContent(void) const; /// Delete an empty directory bool deleteDirectory(void) const; - /// Delete a directory and all its content + /// Delete a directory and all its content. bool deleteDirectoryRecursive(void) const; //@} From d58f317bc5a9e1c38f0626ddec6a8d64ea233485 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 7 May 2013 23:30:17 +0200 Subject: [PATCH 023/160] Reimplement 'Duplicate' command to do the same as Copy/Paste --- src/Gui/CommandDoc.cpp | 77 +++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 50 deletions(-) diff --git a/src/Gui/CommandDoc.cpp b/src/Gui/CommandDoc.cpp index 86d7c2abc..1c14ba62f 100644 --- a/src/Gui/CommandDoc.cpp +++ b/src/Gui/CommandDoc.cpp @@ -910,59 +910,36 @@ StdCmdDuplicateSelection::StdCmdDuplicateSelection() void StdCmdDuplicateSelection::activated(int iMsg) { - App::Document* act = App::GetApplication().getActiveDocument(); - if (!act) - return; // no active document found - Gui::Document* doc = Gui::Application::Instance->getDocument(act); - std::vector sel = Gui::Selection().getCompleteSelection(); + std::vector sel = Selection().getCompleteSelection(); + std::vector obj; + obj.reserve(sel.size()); for (std::vector::iterator it = sel.begin(); it != sel.end(); ++it) { - if (!it->pObject) - continue; // should actually not happen - // create a copy of the object - App::DocumentObject* copy = act->copyObject(it->pObject, false); - if (!copy) // continue if no copy could be created - continue; - // mark all properties of the copy as "touched" which are touched in the original object - std::map props; - it->pObject->getPropertyMap(props); - std::map copy_props; - copy->getPropertyMap(copy_props); - for (std::map::iterator jt = props.begin(); jt != props.end(); ++jt) { - if (jt->second->isTouched()) { - std::map::iterator kt; - kt = copy_props.find(jt->first); - if (kt != copy_props.end()) { - kt->second->touch(); - } - } - } - - Gui::Document* parent = Gui::Application::Instance->getDocument(it->pObject->getDocument()); - if (!parent || !doc) - continue; // should not happen - // copy the properties of the associated view providers - Gui::ViewProvider* view = parent->getViewProvider(it->pObject); - Gui::ViewProvider* copy_view = doc->getViewProvider(copy); - copy_view->addDynamicProperties(view); - if (!view || !copy_view) - continue; // should not happen - - // get the properties of the view provider - props.clear(); - view->getPropertyMap(props); - copy_props.clear(); - copy_view->getPropertyMap(copy_props); - for (std::map::iterator jt = props.begin(); jt != props.end(); ++jt) { - std::map::iterator kt; - kt = copy_props.find(jt->first); - if (kt != copy_props.end()) { - std::auto_ptr data(jt->second->Copy()); - if (data.get()) { - kt->second->Paste(*data); - } - } + if (it->pObject) { + obj.push_back(it->pObject); } } + + if (obj.empty()) + return; + + Base::FileInfo fi(Base::FileInfo::getTempFileName()); + { + // save stuff to file + Base::ofstream str(fi, std::ios::out | std::ios::binary); + App::Document* doc = obj.front()->getDocument(); + MergeDocuments mimeView(doc); + doc->exportObjects(obj, str); + str.close(); + } + App::Document* doc = App::GetApplication().getActiveDocument(); + if (doc) { + // restore objects from file and add to active document + Base::ifstream str(fi, std::ios::in | std::ios::binary); + MergeDocuments mimeView(doc); + mimeView.importObjects(str); + str.close(); + } + fi.deleteFile(); } bool StdCmdDuplicateSelection::isActive(void) From 33fbb0ed8d266dbe2d039c7d731794a3f9e62a73 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 8 May 2013 14:45:52 +0200 Subject: [PATCH 024/160] Ask user what to do if objects with unselected dependency get copied --- src/App/Document.cpp | 68 ++++++++++++++++++++++++++++++++---------- src/App/Document.h | 4 +++ src/Gui/CommandDoc.cpp | 33 +++++++++++++++----- src/Gui/MainWindow.cpp | 51 ++++++++++++++++++++++--------- 4 files changed, 119 insertions(+), 37 deletions(-) diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 3707e5193..8454df3ea 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -64,6 +64,7 @@ recompute path. Also enables more complicated dependencies beyond trees. #include #include #include +#include #include #include @@ -1135,6 +1136,58 @@ std::vector Document::getInList(const DocumentObject* me) return result; } +std::vector +Document::getDependencyList(const std::vector& objs) const +{ + DependencyList DepList; + std::map ObjectMap; + std::map VertexMap; + + // Filling up the adjacency List + for (std::map::const_iterator It = d->objectMap.begin(); It != d->objectMap.end();++It) { + // add the object as Vertex and remember the index + Vertex v = add_vertex(DepList); + ObjectMap[It->second] = v; + VertexMap[v] = It->second; + } + // add the edges + for (std::map::const_iterator It = d->objectMap.begin(); It != d->objectMap.end();++It) { + std::vector OutList = It->second->getOutList(); + for (std::vector::const_iterator It2=OutList.begin();It2!=OutList.end();++It2) { + if (*It2) + add_edge(ObjectMap[It->second],ObjectMap[*It2],DepList); + } + } + + std::list make_order; + DependencyList::out_edge_iterator j, jend; + + try { + // this sort gives the execute + boost::topological_sort(DepList, std::front_inserter(make_order)); + } + catch (const std::exception&) { + return std::vector(); + } + + //std::vector out; + boost::unordered_set out; + for (std::vector::const_iterator it = objs.begin(); it != objs.end(); ++it) { + std::map::iterator jt = ObjectMap.find(*it); + // ok, object is part of this graph + if (jt != ObjectMap.end()) { + for (boost::tie(j, jend) = boost::out_edges(jt->second, DepList); j != jend; ++j) { + out.insert(VertexMap[boost::target(*j, DepList)]); + } + out.insert(*it); + } + } + + std::vector ary; + ary.insert(ary.end(), out.begin(), out.end()); + return ary; +} + void Document::_rebuildDependencyList(void) { d->VertexObjectList.clear(); @@ -1164,21 +1217,6 @@ void Document::recompute() // updates the dependency graph _rebuildDependencyList(); - //DependencyList DepList; - //std::map VertexObjectList; - - //// Filling up the adjacency List - //for (std::map::const_iterator It = d->objectMap.begin(); It != d->objectMap.end();++It) - // // add the object as Vertex and remember the index - // VertexObjectList[It->second] = add_vertex(DepList); - //// add the edges - //for (std::map::const_iterator It = d->objectMap.begin(); It != d->objectMap.end();++It) { - // std::vector OutList = It->second->getOutList(); - // for (std::vector::const_iterator It2=OutList.begin();It2!=OutList.end();++It2) - // if (*It2) - // add_edge(VertexObjectList[It->second],VertexObjectList[*It2],DepList); - //} - std::list make_order; DependencyList::out_edge_iterator j, jend; diff --git a/src/App/Document.h b/src/App/Document.h index 06a7fbdcb..3ab0cb639 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -265,6 +265,10 @@ public: bool checkOnCycle(void); /// get a list of all objects linking to the given object std::vector getInList(const DocumentObject* me) const; + /// Get a complete list of all objects the given objects depend on. The list + /// also contains the given objects! + std::vector getDependencyList + (const std::vector&) const; // set Changed //void setChanged(DocumentObject* change); //@} diff --git a/src/Gui/CommandDoc.cpp b/src/Gui/CommandDoc.cpp index 1c14ba62f..212f89f07 100644 --- a/src/Gui/CommandDoc.cpp +++ b/src/Gui/CommandDoc.cpp @@ -841,7 +841,6 @@ void StdCmdCopy::activated(int iMsg) { bool done = getGuiApplication()->sendMsgToActiveView("Copy"); if (!done) { - WaitCursor wc; QMimeData * mimeData = getMainWindow()->createMimeDataFromSelection(); QClipboard* cb = QApplication::clipboard(); cb->setMimeData(mimeData); @@ -911,24 +910,42 @@ StdCmdDuplicateSelection::StdCmdDuplicateSelection() void StdCmdDuplicateSelection::activated(int iMsg) { std::vector sel = Selection().getCompleteSelection(); - std::vector obj; - obj.reserve(sel.size()); + std::map< App::Document*, std::vector > objs; for (std::vector::iterator it = sel.begin(); it != sel.end(); ++it) { - if (it->pObject) { - obj.push_back(it->pObject); + if (it->pObject && it->pObject->getDocument()) { + objs[it->pObject->getDocument()].push_back(it->pObject); } } - if (obj.empty()) + if (objs.empty()) return; Base::FileInfo fi(Base::FileInfo::getTempFileName()); { + std::vector sel; // selected + std::vector all; // object sub-graph + for (std::map< App::Document*, std::vector >::iterator it = objs.begin(); it != objs.end(); ++it) { + std::vector dep = it->first->getDependencyList(it->second); + sel.insert(sel.end(), it->second.begin(), it->second.end()); + all.insert(all.end(), dep.begin(), dep.end()); + } + + if (all.size() > sel.size()) { + int ret = QMessageBox::question(getMainWindow(), + qApp->translate("Std_DuplicateSelection","Object dependencies"), + qApp->translate("Std_DuplicateSelection","The selected objects have a dependency to unselected objects.\n" + "Do you want to duplicate them, too?"), + QMessageBox::Yes,QMessageBox::No); + if (ret == QMessageBox::Yes) { + sel = all; + } + } + // save stuff to file Base::ofstream str(fi, std::ios::out | std::ios::binary); - App::Document* doc = obj.front()->getDocument(); + App::Document* doc = sel.front()->getDocument(); MergeDocuments mimeView(doc); - doc->exportObjects(obj, str); + doc->exportObjects(sel, str); str.close(); } App::Document* doc = App::GetApplication().getActiveDocument(); diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index e1cc361a1..6c91f19ed 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -23,6 +23,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include # include # include # include @@ -63,6 +64,7 @@ #include "MainWindow.h" #include "Application.h" #include "Assistant.h" +#include "WaitCursor.h" #include "Action.h" #include "Command.h" @@ -1403,21 +1405,39 @@ void MainWindow::dragEnterEvent (QDragEnterEvent * e) QMimeData * MainWindow::createMimeDataFromSelection () const { - std::vector sel = Selection().getCompleteSelection(); - unsigned int memsize=1000; // ~ for the meta-information - std::vector obj; - obj.reserve(sel.size()); - for (std::vector::iterator it = sel.begin(); it != sel.end(); ++it) { - if (it->pObject) { - obj.push_back(it->pObject); - memsize += it->pObject->getMemSize(); + std::vector selobj = Selection().getCompleteSelection(); + std::map< App::Document*, std::vector > objs; + for (std::vector::iterator it = selobj.begin(); it != selobj.end(); ++it) { + if (it->pObject && it->pObject->getDocument()) { + objs[it->pObject->getDocument()].push_back(it->pObject); } } - // get a pointer to a document - if (obj.empty()) return 0; - App::Document* doc = obj.front()->getDocument(); - if (!doc) return 0; + if (objs.empty()) + return 0; + + std::vector sel; // selected + std::vector all; // object sub-graph + for (std::map< App::Document*, std::vector >::iterator it = objs.begin(); it != objs.end(); ++it) { + std::vector dep = it->first->getDependencyList(it->second); + sel.insert(sel.end(), it->second.begin(), it->second.end()); + all.insert(all.end(), dep.begin(), dep.end()); + } + + if (all.size() > sel.size()) { + int ret = QMessageBox::question(getMainWindow(), + tr("Object dependencies"), + tr("The selected objects have a dependency to unselected objects.\n" + "Do you want to copy them, too?"), + QMessageBox::Yes,QMessageBox::No); + if (ret == QMessageBox::Yes) { + sel = all; + } + } + + unsigned int memsize=1000; // ~ for the meta-information + for (std::vector::iterator it = sel.begin(); it != sel.end(); ++it) + memsize += (*it)->getMemSize(); // if less than ~10 MB bool use_buffer=(memsize < 0xA00000); @@ -1429,22 +1449,25 @@ QMimeData * MainWindow::createMimeDataFromSelection () const use_buffer = false; } + WaitCursor wc; QString mime; if (use_buffer) { mime = QLatin1String("application/x-documentobject"); Base::ByteArrayOStreambuf buf(res); std::ostream str(&buf); // need this instance to call MergeDocuments::Save() + App::Document* doc = sel.front()->getDocument(); MergeDocuments mimeView(doc); - doc->exportObjects(obj, str); + doc->exportObjects(sel, str); } else { mime = QLatin1String("application/x-documentobject-file"); static Base::FileInfo fi(Base::FileInfo::getTempFileName()); Base::ofstream str(fi, std::ios::out | std::ios::binary); // need this instance to call MergeDocuments::Save() + App::Document* doc = sel.front()->getDocument(); MergeDocuments mimeView(doc); - doc->exportObjects(obj, str); + doc->exportObjects(sel, str); str.close(); res = fi.filePath().c_str(); } From 738e8c3d1510f5fecb7a4084d7a654a96630054e Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 8 May 2013 14:47:20 +0200 Subject: [PATCH 025/160] Prepare tree view to show for multiple referenced objects more tree items --- src/Gui/Tree.cpp | 27 +++++++++++++++++++++++++-- src/Gui/Tree.h | 2 ++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index a10cf015b..63e57a34a 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -305,6 +305,30 @@ Qt::DropActions TreeWidget::supportedDropActions () const return QTreeWidget::supportedDropActions(); } +bool TreeWidget::event(QEvent *e) +{ +#if 0 + if (e->type() == QEvent::ShortcutOverride) { + QKeyEvent* ke = static_cast(e); + switch (ke->key()) { + case Qt::Key_Delete: + ke->accept(); + } + } +#endif + return QTreeWidget::event(e); +} + +void TreeWidget::keyPressEvent(QKeyEvent *event) +{ +#if 0 + if (event && event->matches(QKeySequence::Delete)) { + event->ignore(); + } +#endif + QTreeWidget::keyPressEvent(event); +} + void TreeWidget::mouseDoubleClickEvent (QMouseEvent * event) { QTreeWidgetItem* item = itemAt(event->pos()); @@ -942,8 +966,7 @@ void DocumentItem::slotHighlightObject (const Gui::ViewProviderDocumentObject& o jt->second->setData(0, Qt::BackgroundColorRole,QVariant()); break; default: - // not defined enum - assert(0); + break; } jt->second->setFont(0,f); diff --git a/src/Gui/Tree.h b/src/Gui/Tree.h index b0e6b1287..f6ce2da66 100644 --- a/src/Gui/Tree.h +++ b/src/Gui/Tree.h @@ -84,6 +84,8 @@ protected: QMimeData * mimeData (const QList items) const; void dragMoveEvent(QDragMoveEvent *event); void dropEvent(QDropEvent *event); + bool event(QEvent *e); + void keyPressEvent(QKeyEvent *event); void mouseDoubleClickEvent(QMouseEvent * event); protected Q_SLOTS: From fa3bbd093adfbd3a0870f8b65760ae1101930917 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 8 May 2013 15:07:46 +0200 Subject: [PATCH 026/160] Save position of last edited property item and restore it when selection changes --- src/Gui/propertyeditor/PropertyEditor.cpp | 6 ++++-- src/Gui/propertyeditor/PropertyEditor.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Gui/propertyeditor/PropertyEditor.cpp b/src/Gui/propertyeditor/PropertyEditor.cpp index 239d2399c..92180f7ca 100644 --- a/src/Gui/propertyeditor/PropertyEditor.cpp +++ b/src/Gui/propertyeditor/PropertyEditor.cpp @@ -136,9 +136,11 @@ void PropertyEditor::buildUp(const std::mapcurrentIndex(); QStringList propertyPath = propertyModel->propertyPathFromIndex(index); + if (!propertyPath.isEmpty()) + this->selectedProperty = propertyPath; propertyModel->buildUp(props); - if (!propertyPath.isEmpty()) { - QModelIndex index = propertyModel->propertyIndexFromPath(propertyPath); + if (!this->selectedProperty.isEmpty()) { + QModelIndex index = propertyModel->propertyIndexFromPath(this->selectedProperty); this->setCurrentIndex(index); } } diff --git a/src/Gui/propertyeditor/PropertyEditor.h b/src/Gui/propertyeditor/PropertyEditor.h index 6e59d9631..aa9c89587 100644 --- a/src/Gui/propertyeditor/PropertyEditor.h +++ b/src/Gui/propertyeditor/PropertyEditor.h @@ -63,6 +63,7 @@ protected: private: PropertyModel* propertyModel; + QStringList selectedProperty; bool autoupdate; bool committing; bool delaybuild; From cec94bdb6afb984f8ff2e62852a8d9dc61f12978 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 8 May 2013 18:40:20 +0200 Subject: [PATCH 027/160] Fix for highlighting of edges --- src/Gui/View3DInventorViewer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index 47289e22e..b3dfa6047 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -1072,7 +1072,9 @@ void View3DInventorViewer::renderScene(void) for (std::list::iterator it = this->graphicsItems.begin(); it != this->graphicsItems.end(); ++it) (*it)->paintGL(); +#if 0 // this breaks highlighting of edges glEnable(GL_LIGHTING); +#endif glEnable(GL_DEPTH_TEST); } From 1e2aface5a710b9fe885a7188fb931e49f0b1cf6 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 8 May 2013 18:56:55 +0200 Subject: [PATCH 028/160] Fix for highlighting of edges --- src/Gui/View3DInventorViewer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index b3dfa6047..1d37bd310 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -1064,8 +1064,10 @@ void View3DInventorViewer::renderScene(void) // Immediately reschedule to get continous spin animation. if (this->isAnimating()) { this->scheduleRedraw(); } +#if 0 // this breaks highlighting of edges glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); +#endif printDimension(); navigation->redraw(); @@ -1074,8 +1076,8 @@ void View3DInventorViewer::renderScene(void) #if 0 // this breaks highlighting of edges glEnable(GL_LIGHTING); -#endif glEnable(GL_DEPTH_TEST); +#endif } void View3DInventorViewer::setSeekMode(SbBool on) From 83a447f43f4699a665d21096061734acf9593cec Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 11 May 2013 22:16:02 +0200 Subject: [PATCH 029/160] MVC for tree view --- src/Gui/DocumentModel.cpp | 278 ++++++++++++++++++++---------- src/Gui/DocumentModel.h | 4 +- src/Mod/Sandbox/Gui/Workbench.cpp | 30 ++++ src/Mod/Sandbox/Gui/Workbench.h | 1 + 4 files changed, 222 insertions(+), 91 deletions(-) diff --git a/src/Gui/DocumentModel.cpp b/src/Gui/DocumentModel.cpp index f65a58965..856200b99 100644 --- a/src/Gui/DocumentModel.cpp +++ b/src/Gui/DocumentModel.cpp @@ -30,6 +30,8 @@ # include #endif +#include + #include "DocumentModel.h" #include "Application.h" #include "BitmapFactory.h" @@ -54,8 +56,6 @@ namespace Gui { virtual ~DocumentModelIndex() { qDeleteAll(childItems); } - void reset() - { qDeleteAll(childItems); childItems.clear(); } void setParent(DocumentModelIndex* parent) { parentItem = parent; } DocumentModelIndex *parent() const @@ -64,7 +64,12 @@ namespace Gui { { childItems.append(child); child->setParent(this); } void removeChild(int row) { childItems.removeAt(row); } - + QList removeAll() + { + QList list = childItems; + childItems.clear(); + return list; + } DocumentModelIndex *child(int row) { return childItems.value(row); } int row() const @@ -91,11 +96,18 @@ namespace Gui { return Qt::ItemIsSelectable|Qt::ItemIsEnabled; } + protected: + void reset() + { qDeleteAll(childItems); childItems.clear(); } + protected: DocumentModelIndex() : parentItem(0) {} DocumentModelIndex *parentItem; QList childItems; }; + + // ------------------------------------------------------------------------ + // Root node class ApplicationIndex : public DocumentModelIndex { @@ -104,24 +116,22 @@ namespace Gui { public: ApplicationIndex(){} int findChild(const Gui::Document& d) const; - Qt::ItemFlags flags() const - { return Qt::ItemIsEnabled; } - QVariant data(int role) const - { - if (role == Qt::DecorationRole) { - return qApp->windowIcon(); - } - else if (role == Qt::DisplayRole) { - return DocumentModel::tr("Application"); - } - return QVariant(); - } + Qt::ItemFlags flags() const; + QVariant data(int role) const; }; + + // ------------------------------------------------------------------------ + // Document nodes class DocumentIndex : public DocumentModelIndex { + friend class ViewProviderIndex; TYPESYSTEM_HEADER(); static QIcon* documentIcon; + typedef boost::unordered_set IndexSet; + std::map vp_nodes; + void addToDocument(ViewProviderIndex*); + void removeFromDocument(ViewProviderIndex*); public: const Gui::Document& d; @@ -130,30 +140,18 @@ namespace Gui { if (!documentIcon) documentIcon = new QIcon(Gui::BitmapFactory().pixmap("Document")); } - int findViewProvider(const ViewProvider&) const; - void findViewProviders(const ViewProvider&, QList&) const; - QVariant data(int role) const + ~DocumentIndex() { - if (role == Qt::DecorationRole) { - return *documentIcon; - } - else if (role == Qt::DisplayRole) { - App::Document* doc = d.getDocument(); - return QString::fromUtf8(doc->Label.getValue()); - } - else if (role == Qt::FontRole) { - Document* doc = Application::Instance->activeDocument(); - QFont font; - font.setBold(doc==&d); - QVariant variant; - variant.setValue(font); - return variant; - } - - return QVariant(); + qDeleteAll(childItems); childItems.clear(); } + ViewProviderIndex* cloneViewProvider(const ViewProviderDocumentObject&) const; + int rowOfViewProvider(const ViewProviderDocumentObject&) const; + void findViewProviders(const ViewProviderDocumentObject&, QList&) const; + QVariant data(int role) const; }; + // ------------------------------------------------------------------------ + // Object nodes class ViewProviderIndex : public DocumentModelIndex { @@ -161,31 +159,18 @@ namespace Gui { public: const Gui::ViewProviderDocumentObject& v; - ViewProviderIndex(const Gui::ViewProviderDocumentObject& v) : v(v){} - void findViewProviders(const ViewProvider&, QList&) const; - QVariant data(int role) const - { - if (role == Qt::DecorationRole) { - return v.getIcon(); - } - else if (role == Qt::DisplayRole) { - App::DocumentObject* obj = v.getObject(); - return QString::fromUtf8(obj->Label.getValue()); - } - else if (role == Qt::FontRole) { - App::DocumentObject* obj = v.getObject(); - App::DocumentObject* act = obj->getDocument()->getActiveObject(); - QFont font; - font.setBold(obj==act); - QVariant variant; - variant.setValue(font); - return variant; - } + ViewProviderIndex(const Gui::ViewProviderDocumentObject& v, DocumentIndex* d); + ~ViewProviderIndex(); + ViewProviderIndex* clone() const; + void findViewProviders(const ViewProviderDocumentObject&, QList&) const; + QVariant data(int role) const; - return QVariant(); - } + private: + DocumentIndex* d; }; + // ------------------------------------------------------------------------ + int ApplicationIndex::findChild(const Gui::Document& d) const { int child=0; @@ -199,9 +184,50 @@ namespace Gui { return -1; } + Qt::ItemFlags ApplicationIndex::flags() const + { + return Qt::ItemIsEnabled; + } + + QVariant ApplicationIndex::data(int role) const + { + if (role == Qt::DecorationRole) { + return qApp->windowIcon(); + } + else if (role == Qt::DisplayRole) { + return DocumentModel::tr("Application"); + } + return QVariant(); + } + + // ------------------------------------------------------------------------ + QIcon* DocumentIndex::documentIcon = 0; - void DocumentIndex::findViewProviders(const ViewProvider& vp, + void DocumentIndex::addToDocument(ViewProviderIndex* vp) + { + vp_nodes[&vp->v].insert(vp); + } + + void DocumentIndex::removeFromDocument(ViewProviderIndex* vp) + { + vp_nodes[&vp->v].erase(vp); + } + + ViewProviderIndex* + DocumentIndex::cloneViewProvider(const ViewProviderDocumentObject& vp) const + { + std::map >::const_iterator it; + it = vp_nodes.find(&vp); + if (it != vp_nodes.end()) { + boost::unordered_set::const_iterator v; + v = it->second.begin(); + return (*v)->clone(); + } + return new ViewProviderIndex(vp, const_cast(this)); + } + + void DocumentIndex::findViewProviders(const ViewProviderDocumentObject& vp, QList& index) const { QList::const_iterator it; @@ -211,7 +237,7 @@ namespace Gui { } } - int DocumentIndex::findViewProvider(const ViewProvider& vp) const + int DocumentIndex::rowOfViewProvider(const ViewProviderDocumentObject& vp) const { QList::const_iterator it; int index=0; @@ -224,8 +250,52 @@ namespace Gui { return -1; } - void ViewProviderIndex::findViewProviders(const ViewProvider& vp, - QList& index) const + QVariant DocumentIndex::data(int role) const + { + if (role == Qt::DecorationRole) { + return *documentIcon; + } + else if (role == Qt::DisplayRole) { + App::Document* doc = d.getDocument(); + return QString::fromUtf8(doc->Label.getValue()); + } + else if (role == Qt::FontRole) { + Document* doc = Application::Instance->activeDocument(); + QFont font; + font.setBold(doc==&d); + QVariant variant; + variant.setValue(font); + return variant; + } + + return QVariant(); + } + + // ------------------------------------------------------------------------ + + ViewProviderIndex::ViewProviderIndex(const Gui::ViewProviderDocumentObject& v, DocumentIndex* d) + : v(v),d(d) + { + if (d) d->addToDocument(this); + } + + ViewProviderIndex::~ViewProviderIndex() + { + if (d) d->removeFromDocument(this); + } + + ViewProviderIndex* ViewProviderIndex::clone() const + { + ViewProviderIndex* copy = new ViewProviderIndex(this->v, this->d); + for (QList::const_iterator it = childItems.begin(); it != childItems.end(); ++it) { + ViewProviderIndex* c = static_cast(*it)->clone(); + copy->appendChild(c); + } + return copy; + } + + void ViewProviderIndex::findViewProviders(const ViewProviderDocumentObject& vp, + QList& index) const { if (&this->v == &vp) index.push_back(const_cast(this)); @@ -236,6 +306,30 @@ namespace Gui { } } + QVariant ViewProviderIndex::data(int role) const + { + if (role == Qt::DecorationRole) { + return v.getIcon(); + } + else if (role == Qt::DisplayRole) { + App::DocumentObject* obj = v.getObject(); + return QString::fromUtf8(obj->Label.getValue()); + } + else if (role == Qt::FontRole) { + App::DocumentObject* obj = v.getObject(); + App::DocumentObject* act = obj->getDocument()->getActiveObject(); + QFont font; + font.setBold(obj==act); + QVariant variant; + variant.setValue(font); + return variant; + } + + return QVariant(); + } + + // ------------------------------------------------------------------------ + TYPESYSTEM_SOURCE_ABSTRACT(Gui::DocumentModelIndex, Base::BaseClass); TYPESYSTEM_SOURCE_ABSTRACT(Gui::ApplicationIndex,Gui::DocumentModelIndex); TYPESYSTEM_SOURCE_ABSTRACT(Gui::DocumentIndex, Gui::DocumentModelIndex); @@ -350,7 +444,7 @@ void DocumentModel::slotNewObject(const Gui::ViewProviderDocumentObject& obj) QModelIndex parent = createIndex(index->row(),0,index); int count_obj = index->childCount(); beginInsertRows(parent, count_obj, count_obj); - index->appendChild(new ViewProviderIndex(obj)); + index->appendChild(new ViewProviderIndex(obj, index)); endInsertRows(); } } @@ -399,35 +493,47 @@ void DocumentModel::slotChangeObject(const Gui::ViewProviderDocumentObject& obj, else if (isPropertyLink(Prop)) { App::Document* doc = fea->getDocument(); Gui::Document* gdc = Application::Instance->getDocument(doc); - std::vector views = getLinkedObjects(*gdc, Prop); + std::vector views = claimChildren(*gdc, obj); int row = d->rootItem->findChild(*gdc); if (row > -1) { + QList del_items; DocumentIndex* doc_index = static_cast(d->rootItem->child(row)); - QList obj_index; - doc_index->findViewProviders(obj, obj_index); - - // remove from top level in document for (std::vector::iterator vp = views.begin(); vp != views.end(); ++vp) { - int row = doc_index->findViewProvider(**vp); + int row = doc_index->rowOfViewProvider(**vp); + // is it a top-level child in the document if (row >= 0) { DocumentModelIndex* child = doc_index->child(row); + del_items.push_back(child); QModelIndex parent = createIndex(doc_index->row(), 0, doc_index); beginRemoveRows(parent, row, row); doc_index->removeChild(row); - delete child; endRemoveRows(); } } + // get all occurrences of the view provider in the tree structure + QList obj_index; + doc_index->findViewProviders(obj, obj_index); for (QList::iterator it = obj_index.begin(); it != obj_index.end(); ++it) { QModelIndex parent = createIndex((*it)->row(),0,*it); int count_obj = (*it)->childCount(); - beginInsertRows(parent, count_obj, count_obj + (int)views.size()); - for (std::vector::iterator jt = views.begin(); jt != views.end(); ++jt) - (*it)->appendChild(new ViewProviderIndex(**jt)); + beginRemoveRows(parent, 0, count_obj); + // remove all children but do not yet delete them + QList items = (*it)->removeAll(); + endRemoveRows(); + + beginInsertRows(parent, 0, (int)views.size()); + for (std::vector::iterator vp = views.begin(); vp != views.end(); ++vp) { + ViewProviderIndex* clone = doc_index->cloneViewProvider(**vp); + (*it)->appendChild(clone); + } endInsertRows(); + + del_items.append(items); } + + qDeleteAll(del_items); } } } @@ -461,33 +567,27 @@ bool DocumentModel::isPropertyLink(const App::Property& prop) const { if (prop.isDerivedFrom(App::PropertyLink::getClassTypeId())) return true; + if (prop.isDerivedFrom(App::PropertyLinkSub::getClassTypeId())) + return true; if (prop.isDerivedFrom(App::PropertyLinkList::getClassTypeId())) return true; + if (prop.isDerivedFrom(App::PropertyLinkSubList::getClassTypeId())) + return true; return false; } std::vector -DocumentModel::getLinkedObjects(const Gui::Document& doc, const App::Property& prop) const +DocumentModel::claimChildren(const Gui::Document& doc, const ViewProviderDocumentObject& obj) const { - std::vector links; - if (prop.isDerivedFrom(App::PropertyLink::getClassTypeId())) { - App::DocumentObject* obj; - obj = static_cast(prop).getValue(); - ViewProvider* view = doc.getViewProvider(obj); + std::vector views; + std::vector childs = obj.claimChildren(); + for (std::vector::iterator it = childs.begin(); it != childs.end(); ++it) { + ViewProvider* view = doc.getViewProvider(*it); if (view && view->getTypeId().isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) - links.push_back(static_cast(view)); - } - else if (prop.isDerivedFrom(App::PropertyLinkList::getClassTypeId())) { - const std::vector& refs = static_cast - (prop).getValues(); - for (std::vector::const_iterator it = refs.begin();it != refs.end(); ++it) { - ViewProvider* view = doc.getViewProvider(*it); - if (view && view->getTypeId().isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) - links.push_back(static_cast(view)); - } + views.push_back(static_cast(view)); } - return links; + return views; } int DocumentModel::columnCount (const QModelIndex & /*parent*/) const diff --git a/src/Gui/DocumentModel.h b/src/Gui/DocumentModel.h index aaaa89ef0..fafe3587b 100644 --- a/src/Gui/DocumentModel.h +++ b/src/Gui/DocumentModel.h @@ -67,8 +67,8 @@ private: const Document* getDocument(const QModelIndex&) const; bool isPropertyLink(const App::Property&) const; - std::vector getLinkedObjects - (const Gui::Document&, const App::Property&) const; + std::vector claimChildren + (const Document&, const ViewProviderDocumentObject&) const; private: struct DocumentModelP *d; diff --git a/src/Mod/Sandbox/Gui/Workbench.cpp b/src/Mod/Sandbox/Gui/Workbench.cpp index c87385295..de5753616 100644 --- a/src/Mod/Sandbox/Gui/Workbench.cpp +++ b/src/Mod/Sandbox/Gui/Workbench.cpp @@ -36,6 +36,10 @@ #include "Workbench.h" #include #include +#include +#include +#include +#include using namespace SandboxGui; @@ -44,6 +48,24 @@ TYPESYSTEM_SOURCE(SandboxGui::Workbench, Gui::StdWorkbench) Workbench::Workbench() { + // Tree view + Gui::DockWindow* tree = new Gui::DockWindow(0, Gui::getMainWindow()); + tree->setWindowTitle(QString::fromAscii("Tree view")); + Gui::TreeView* treeWidget = new Gui::TreeView(tree); + treeWidget->setRootIsDecorated(false); + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/TreeView"); + treeWidget->setIndentation(hGrp->GetInt("Indentation", treeWidget->indentation())); + + QGridLayout* pLayout = new QGridLayout(tree); + pLayout->setSpacing(0); + pLayout->setMargin (0); + pLayout->addWidget(treeWidget, 0, 0); + + tree->setObjectName + (QString::fromAscii(QT_TRANSLATE_NOOP("QDockWidget","Tree view (MVC)"))); + tree->setMinimumWidth(210); + Gui::DockWindowManager* pDockMgr = Gui::DockWindowManager::instance(); + pDockMgr->registerDockWindow("Std_TreeViewMVC", tree); } Workbench::~Workbench() @@ -109,6 +131,14 @@ Gui::ToolBarItem* Workbench::setupCommandBars() const return 0; } +Gui::DockWindowItems* Workbench::setupDockWindows() const +{ + Gui::DockWindowItems* root = Gui::StdWorkbench::setupDockWindows(); + root->setVisibility(false); // hide all dock windows by default + root->addDockWidget("Std_TreeViewMVC", Qt::RightDockWidgetArea, true, true); + return root; +} + // ---------------------------------------------------- diff --git a/src/Mod/Sandbox/Gui/Workbench.h b/src/Mod/Sandbox/Gui/Workbench.h index f923c433a..cdc20d370 100644 --- a/src/Mod/Sandbox/Gui/Workbench.h +++ b/src/Mod/Sandbox/Gui/Workbench.h @@ -43,6 +43,7 @@ protected: Gui::MenuItem* setupMenuBar() const; Gui::ToolBarItem* setupToolBars() const; Gui::ToolBarItem* setupCommandBars() const; + Gui::DockWindowItems* setupDockWindows() const; }; class SoWidgetShape : public SoShape { From e1222202dd1f980cc541e81f297b82360c9c2b51 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 12 May 2013 17:41:59 +0200 Subject: [PATCH 030/160] 0001097: CMake stops with error: Circular ... <- ... dependency dropped. --- CMakeLists.txt | 6 ++++++ data/examples/CMakeLists.txt | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 104dffe66..17cda74bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -439,8 +439,14 @@ IF(APPLE) SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so") ENDIF(APPLE) +# force build directory to be different to source directory +#if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) +#MESSAGE(SEND_ERROR "The build directory (${CMAKE_BINARY_DIR}) must be different to the source directory " +# "(${CMAKE_SOURCE_DIR}). Please choose another build directory!") +#elseif() add_subdirectory(src) add_subdirectory(data) +#endif() # ================================================================================ # == Packaging =================================================================== diff --git a/data/examples/CMakeLists.txt b/data/examples/CMakeLists.txt index eb0e2f991..4c92d776b 100644 --- a/data/examples/CMakeLists.txt +++ b/data/examples/CMakeLists.txt @@ -12,7 +12,10 @@ ADD_CUSTOM_TARGET(Example_data ALL SOURCES ${Examples_Files} ) -fc_copy_sources(Examples "${CMAKE_BINARY_DIR}/data/examples" ${Examples_Files}) +# 0001097: CMake stops with error "Circular ... <- ... dependency dropped." +if(NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") + fc_copy_sources(Examples "${CMAKE_BINARY_DIR}/data/examples" ${Examples_Files}) +endif() INSTALL( FILES From bb650315946660c6cf7861233eddb38d3120f055 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 13 May 2013 15:25:31 +0200 Subject: [PATCH 031/160] Method to get SelectionObject from string --- src/Gui/Selection.cpp | 37 +++++++++++++++++++++++++++++++++++++ src/Gui/Selection.h | 1 + 2 files changed, 38 insertions(+) diff --git a/src/Gui/Selection.cpp b/src/Gui/Selection.cpp index d9ba9ca99..cffd9f60a 100644 --- a/src/Gui/Selection.cpp +++ b/src/Gui/Selection.cpp @@ -979,6 +979,8 @@ PyMethodDef SelectionSingleton::Methods[] = { "document is given the selection of the active document is returned.\n" "The SelectionObjects contain a variety of information about the selection,\n" "e.g. sub-element names."}, + {"getSelectionObject", (PyCFunction) SelectionSingleton::sGetSelectionObject, 1, + "getSelectionObject(doc,obj,sub,(x,y,z)) -- Return a SelectionObject"}, {"addObserver", (PyCFunction) SelectionSingleton::sAddSelObserver, 1, "addObserver(Object) -- Install an observer\n"}, {"removeObserver", (PyCFunction) SelectionSingleton::sRemSelObserver, 1, @@ -1114,6 +1116,41 @@ PyObject *SelectionSingleton::sGetSelectionEx(PyObject * /*self*/, PyObject *arg } } +PyObject *SelectionSingleton::sGetSelectionObject(PyObject * /*self*/, PyObject *args, PyObject * /*kwd*/) +{ + char *docName, *objName, *subName; + PyObject* tuple=0; + if (!PyArg_ParseTuple(args, "sss|O!", &docName, &objName, &subName, + &PyTuple_Type, &tuple)) + return NULL; + + try { + SelectionObject selObj; + selObj.DocName = docName; + selObj.FeatName = objName; + std::string sub = subName; + if (!sub.empty()) { + selObj.SubNames.push_back(sub); + if (tuple) { + Py::Tuple t(tuple); + double x = (double)Py::Float(t.getItem(0)); + double y = (double)Py::Float(t.getItem(1)); + double z = (double)Py::Float(t.getItem(2)); + selObj.SelPoses.push_back(Base::Vector3d(x,y,z)); + } + } + + return selObj.getPyObject(); + } + catch (const Py::Exception&) { + return 0; + } + catch (const Base::Exception& e) { + PyErr_SetString(PyExc_Exception, e.what()); + return 0; + } +} + PyObject *SelectionSingleton::sAddSelObserver(PyObject * /*self*/, PyObject *args, PyObject * /*kwd*/) { PyObject* o; diff --git a/src/Gui/Selection.h b/src/Gui/Selection.h index a8e38eb8a..7aa665615 100644 --- a/src/Gui/Selection.h +++ b/src/Gui/Selection.h @@ -309,6 +309,7 @@ protected: static PyObject *sCountObjectsOfType (PyObject *self,PyObject *args,PyObject *kwd); static PyObject *sGetSelection (PyObject *self,PyObject *args,PyObject *kwd); static PyObject *sGetSelectionEx (PyObject *self,PyObject *args,PyObject *kwd); + static PyObject *sGetSelectionObject (PyObject *self,PyObject *args,PyObject *kwd); static PyObject *sAddSelObserver (PyObject *self,PyObject *args,PyObject *kwd); static PyObject *sRemSelObserver (PyObject *self,PyObject *args,PyObject *kwd); static PyObject *sAddSelectionGate (PyObject *self,PyObject *args,PyObject *kwd); From f23a3cf5c45af756cdcb66157beb0cf6300a2287 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 13 May 2013 15:34:21 +0200 Subject: [PATCH 032/160] 0001120: Windows installer long standing issues [easy fix] --- src/WindowsInstaller/BuildInstaller.bat | 2 +- src/WindowsInstaller/LibPack.wxs | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/WindowsInstaller/BuildInstaller.bat b/src/WindowsInstaller/BuildInstaller.bat index 2ca4e2475..04fc554c7 100644 --- a/src/WindowsInstaller/BuildInstaller.bat +++ b/src/WindowsInstaller/BuildInstaller.bat @@ -24,7 +24,7 @@ SET /P M=Reebuild and press enter rem making of the bin zip file -c:\Programme\7-Zip\7z.exe a -t7z FreeCAD.7z "-xr!*.idb" "-xr!*.pdb" "-xr!*.ilk" "-xr!*.pyc" "-xr!?.git\*" "-xr!*.am" "-xr!CMakeFiles" "..\..\bin" "..\..\Mod" "..\..\Doc" "..\..\data" +"%PROGRAMFILES%\7-Zip\7z.exe" a -t7z FreeCAD.7z "-xr!*.idb" "-xr!*.pdb" "-xr!*.ilk" "-xr!*.pyc" "-xr!?.git\*" "-xr!*.am" "-xr!CMakeFiles" "..\..\bin" "..\..\Mod" "..\..\Doc" "..\..\data" call CopyRelease.bat diff --git a/src/WindowsInstaller/LibPack.wxs b/src/WindowsInstaller/LibPack.wxs index d49cc4ca6..007f69a33 100644 --- a/src/WindowsInstaller/LibPack.wxs +++ b/src/WindowsInstaller/LibPack.wxs @@ -59,16 +59,16 @@ - - - - - - - - - - + + + + + + + + + + From 04401b46f58aac31cc402ed40b077b0607c1746b Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 13 May 2013 15:36:53 +0200 Subject: [PATCH 033/160] Set version number to 0.14 --- src/Build/Version.h.in | 2 +- src/WindowsInstaller/CopyRelease.bat.in | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Build/Version.h.in b/src/Build/Version.h.in index d76718751..954f3dcef 100644 --- a/src/Build/Version.h.in +++ b/src/Build/Version.h.in @@ -1,7 +1,7 @@ // Version Number #define FCVersionMajor "0" -#define FCVersionMinor "13" +#define FCVersionMinor "14" #define FCVersionName "Vulcan" // test: $Format:Hash (%H), Date: %ci$ #define FCRevision "$WCREV$" //Highest committed revision number diff --git a/src/WindowsInstaller/CopyRelease.bat.in b/src/WindowsInstaller/CopyRelease.bat.in index 6c7dbbb68..91d6e2330 100644 --- a/src/WindowsInstaller/CopyRelease.bat.in +++ b/src/WindowsInstaller/CopyRelease.bat.in @@ -1,4 +1,4 @@ -copy FreeCAD.msi FreeCAD_0.13.$WCREV$_x86_RC_setup.msi -copy FreeCAD.7z FreeCAD_0.13.$WCREV$_x86_RC_bin.7z \ No newline at end of file +copy FreeCAD.msi FreeCAD_0.14.$WCREV$_x86_RC_setup.msi +copy FreeCAD.7z FreeCAD_0.14.$WCREV$_x86_RC_bin.7z \ No newline at end of file From 5639f22f8e6a6e1bb4578d93d7bf8e9da5e94825 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 13 May 2013 16:25:30 +0200 Subject: [PATCH 034/160] 0001111: Deleting sketch after padding was done crashes the program --- src/Gui/CommandDoc.cpp | 43 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/src/Gui/CommandDoc.cpp b/src/Gui/CommandDoc.cpp index 212f89f07..3588e77d0 100644 --- a/src/Gui/CommandDoc.cpp +++ b/src/Gui/CommandDoc.cpp @@ -1026,17 +1026,44 @@ void StdCmdDelete::activated(int iMsg) Gui::Document* pGuiDoc = Gui::Application::Instance->getDocument(*it); std::vector sel = rSel.getSelectionEx((*it)->getName()); if (!sel.empty()) { - (*it)->openTransaction("Delete"); + bool doDeletion = true; + // check if we can delete the object for (std::vector::iterator ft = sel.begin(); ft != sel.end(); ++ft) { - Gui::ViewProvider* vp = pGuiDoc->getViewProvider(ft->getObject()); - if (vp) { - // ask the ViewProvider if its want to do some clean up - if (vp->onDelete(ft->getSubNames())) - doCommand(Doc,"App.getDocument(\"%s\").removeObject(\"%s\")" - ,(*it)->getName(), ft->getFeatName()); + App::DocumentObject* obj = ft->getObject(); + std::vector links = obj->getInList(); + if (!links.empty()) { + // check if the referenced objects are groups or are selected too + for (std::vector::iterator lt = links.begin(); lt != links.end(); ++lt) { + if (!(*lt)->getTypeId().isDerivedFrom(App::DocumentObjectGroup::getClassTypeId()) && !rSel.isSelected(*lt)) { + doDeletion = false; + break; + } + } + + if (!doDeletion) { + break; + } } } - (*it)->commitTransaction(); + + if (doDeletion) { + (*it)->openTransaction("Delete"); + for (std::vector::iterator ft = sel.begin(); ft != sel.end(); ++ft) { + Gui::ViewProvider* vp = pGuiDoc->getViewProvider(ft->getObject()); + if (vp) { + // ask the ViewProvider if it wants to do some clean up + if (vp->onDelete(ft->getSubNames())) + doCommand(Doc,"App.getDocument(\"%s\").removeObject(\"%s\")" + ,(*it)->getName(), ft->getFeatName()); + } + } + (*it)->commitTransaction(); + } + else { + QMessageBox::warning(Gui::getMainWindow(), + qApp->translate("Std_Delete", "Object dependencies"), + qApp->translate("Std_Delete", "This object is referenced by other objects and thus cannot be deleted.")); + } } } } From 941dcbf6fcd805daf9c3920cab3084d73a7a57b3 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 14 May 2013 14:53:13 +0200 Subject: [PATCH 035/160] Implement drag-at-cursor --- src/Gui/NavigationStyle.cpp | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/Gui/NavigationStyle.cpp b/src/Gui/NavigationStyle.cpp index 836b6f7bf..b7380aaad 100644 --- a/src/Gui/NavigationStyle.cpp +++ b/src/Gui/NavigationStyle.cpp @@ -52,6 +52,9 @@ struct NavigationStyleP { int animationsteps; int animationdelta; SbVec3f focal1, focal2; + SbVec3f startDragPoint; + SbBool dragPointFound; + SbBool dragAtCursor; SbRotation endRotation; SoTimerSensor * animsensor; float sensitivity; @@ -62,6 +65,8 @@ struct NavigationStyleP { this->animationsteps = 0; this->sensitivity = 2.0f; this->resetcursorpos = FALSE; + this->dragPointFound = FALSE; + this->dragAtCursor = FALSE; } static void viewAnimationCB(void * data, SoSensor * sensor); }; @@ -323,6 +328,7 @@ void NavigationStyle::lookAtPoint(const SbVec3f& pos) { SoCamera* cam = viewer->getCamera(); if (cam == 0) return; + PRIVATE(this)->dragPointFound = FALSE; // Find global coordinates of focal point. SbVec3f direction; @@ -643,6 +649,7 @@ void NavigationStyle::panToCenter(const SbPlane & pplane, const SbVec2f & currpo const SbViewportRegion & vp = viewer->getViewportRegion(); float ratio = vp.getViewportAspectRatio(); panCamera(viewer->getCamera(), ratio, pplane, SbVec2f(0.5,0.5), currpos); + PRIVATE(this)->dragPointFound = FALSE; } /** Dependent on the camera type this will either shrink or expand the @@ -781,6 +788,15 @@ void NavigationStyle::spin(const SbVec2f & pointerpos) lastpos[0] = float(this->log.position[1][0]) / float(SoQtMax((int)(glsize[0]-1), 1)); lastpos[1] = float(this->log.position[1][1]) / float(SoQtMax((int)(glsize[1]-1), 1)); + if (PRIVATE(this)->dragAtCursor && PRIVATE(this)->dragPointFound) { + SbVec3f hitpoint = PRIVATE(this)->startDragPoint; + + // set to the given position + SbVec3f direction; + viewer->getCamera()->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction); + viewer->getCamera()->position = hitpoint - viewer->getCamera()->focalDistance.getValue() * direction; + } + // 0000333: Turntable camera rotation SbMatrix mat; viewer->getCamera()->orientation.getValue().getValue(mat); @@ -800,6 +816,16 @@ void NavigationStyle::spin(const SbVec2f & pointerpos) r.invert(); this->reorientCamera(viewer->getCamera(), r); + if (PRIVATE(this)->dragAtCursor && PRIVATE(this)->dragPointFound) { + float ratio = vp.getViewportAspectRatio(); + SbViewVolume vv = viewer->getCamera()->getViewVolume(vp.getViewportAspectRatio()); + SbPlane panplane = vv.getPlane(viewer->getCamera()->focalDistance.getValue()); + SbVec2f posn; + posn[0] = float(this->localPos[0]) / float(SoQtMax((int)(glsize[0]-1), 1)); + posn[1] = float(this->localPos[1]) / float(SoQtMax((int)(glsize[1]-1), 1)); + panCamera(viewer->getCamera(), ratio, panplane, posn, SbVec2f(0.5,0.5)); + } + // Calculate an average angle magnitude value to make the transition // to a possible spin animation mode appear smooth. @@ -855,6 +881,20 @@ void NavigationStyle::saveCursorPosition(const SoEvent * const ev) { this->globalPos.setValue(QCursor::pos().x(), QCursor::pos().y()); this->localPos = ev->getPosition(); + + // get the 3d point to the screen position, if possible + if (PRIVATE(this)->dragAtCursor) { + SoRayPickAction rpaction(viewer->getViewportRegion()); + rpaction.setPoint(this->localPos); + rpaction.setRadius(2); + rpaction.apply(viewer->getSceneManager()->getSceneGraph()); + + SoPickedPoint * picked = rpaction.getPickedPoint(); + if (picked) { + PRIVATE(this)->dragPointFound = TRUE; + PRIVATE(this)->startDragPoint = picked->getPoint(); + } + } } void NavigationStyle::moveCursorPosition() From 81045486fd6b9090be0ec31166c7ad5474272f24 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 14 May 2013 15:20:00 +0200 Subject: [PATCH 036/160] 0000826: reading from the python console for using pdb -- code cleanup --- src/Gui/PythonConsole.cpp | 66 ------------------------------------- src/Gui/PythonConsole.h | 23 ------------- src/Gui/PythonConsolePy.cpp | 8 ----- src/Gui/PythonConsolePy.h | 3 -- 4 files changed, 100 deletions(-) diff --git a/src/Gui/PythonConsole.cpp b/src/Gui/PythonConsole.cpp index 8783922fa..a8306d693 100644 --- a/src/Gui/PythonConsole.cpp +++ b/src/Gui/PythonConsole.cpp @@ -1417,70 +1417,4 @@ void ConsoleHistory::doScratch( void ) // ----------------------------------------------------- -/* TRANSLATOR Gui::PythonInputField */ - -PythonInputField::PythonInputField(QWidget* parent) - : QWidget(parent) -{ - QGridLayout* gridLayout = new QGridLayout(this); - gridLayout->setSpacing(6); - gridLayout->setMargin(9); - - editField = new PythonEditor(this); - gridLayout->addWidget(editField, 0, 0, 1, 1); - setFocusProxy(editField); - - QHBoxLayout* hboxLayout = new QHBoxLayout(); - hboxLayout->setSpacing(6); - hboxLayout->setMargin(0); - - QSpacerItem* spacerItem = new QSpacerItem(131, 31, QSizePolicy::Expanding, QSizePolicy::Minimum); - hboxLayout->addItem(spacerItem); - - okButton = new QPushButton(this); - hboxLayout->addWidget(okButton); - clearButton = new QPushButton(this); - hboxLayout->addWidget(clearButton); - gridLayout->addLayout(hboxLayout, 1, 0, 1, 1); - - - this->setWindowTitle(Gui::PythonConsole::tr("Python Input Dialog")); - okButton->setText(tr("OK")); - clearButton->setText(tr("Clear")); - - QObject::connect(okButton, SIGNAL(clicked()), this, SIGNAL(textEntered())); - QObject::connect(clearButton, SIGNAL(clicked()), editField, SLOT(clear())); -} - -PythonInputField::~PythonInputField() -{ -} - -QString PythonInputField::getText() const -{ - return editField->toPlainText(); -} - -void PythonInputField::clear() -{ - return editField->clear(); -} - -void PythonInputField::changeEvent(QEvent *e) -{ - if (e->type() == QEvent::LanguageChange) { - this->setWindowTitle(Gui::PythonConsole::tr("Python Input Dialog")); - okButton->setText(tr("OK")); - clearButton->setText(tr("Clear")); - } - else { - QWidget::changeEvent(e); - } -} - -void PythonInputField::showEvent(QShowEvent* e) -{ - editField->setFocus(); -} - #include "moc_PythonConsole.cpp" diff --git a/src/Gui/PythonConsole.h b/src/Gui/PythonConsole.h index b949894d9..13efa1f45 100644 --- a/src/Gui/PythonConsole.h +++ b/src/Gui/PythonConsole.h @@ -181,29 +181,6 @@ protected: void colorChanged(const QString& type, const QColor& col); }; -class GuiExport PythonInputField : public QWidget -{ - Q_OBJECT - -public: - PythonInputField(QWidget* parent=0); - ~PythonInputField(); - QString getText() const; - void clear(); - -protected: - void changeEvent(QEvent *e); - void showEvent(QShowEvent* e); - -Q_SIGNALS: - void textEntered(); - -private: - QPushButton* okButton; - QPushButton* clearButton; - QPlainTextEdit* editField; -}; - } // namespace Gui #endif // GUI_PYTHONCONSOLE_H diff --git a/src/Gui/PythonConsolePy.cpp b/src/Gui/PythonConsolePy.cpp index b9fe2a5f0..fe28a0c6f 100644 --- a/src/Gui/PythonConsolePy.cpp +++ b/src/Gui/PythonConsolePy.cpp @@ -292,19 +292,11 @@ void PythonStdin::init_type() PythonStdin::PythonStdin(PythonConsole *pc) : pyConsole(pc) { - editField = new PythonInputField(/*getMainWindow()*/); - timer = new QTimer(); - timer->setInterval(250); - QObject::connect(timer, SIGNAL(timeout()), - editField, SLOT(hide())); console = getMainWindow()->findChild(); } PythonStdin::~PythonStdin() { - // call deleteLater() because deleting immediately causes problems - editField->deleteLater(); - timer->deleteLater(); } Py::Object PythonStdin::repr() diff --git a/src/Gui/PythonConsolePy.h b/src/Gui/PythonConsolePy.h index 63cc34284..b1ad4fcfa 100644 --- a/src/Gui/PythonConsolePy.h +++ b/src/Gui/PythonConsolePy.h @@ -30,7 +30,6 @@ class QTimer; namespace Gui { class PythonConsole; -class PythonInputField; /** * Python class for redirection of stdout to FreeCAD's Python @@ -141,9 +140,7 @@ public: Py::Object readline(const Py::Tuple&); private: - PythonInputField* editField; PythonConsole* console; - QTimer* timer; }; } // namespace Gui From 672e4d0feba8bb6e73ee20b8573abc17741763af Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 14 May 2013 16:26:44 +0200 Subject: [PATCH 037/160] 0000965: Tooltips should include shortcuts keys in parentheses --- src/Gui/Command.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Gui/Command.cpp b/src/Gui/Command.cpp index 2fc6f8748..f1c4439d2 100644 --- a/src/Gui/Command.cpp +++ b/src/Gui/Command.cpp @@ -581,6 +581,12 @@ void Command::applyCommandData(Action* action) action->setWhatsThis(QCoreApplication::translate( this->className(), sToolTipText, 0, QCoreApplication::UnicodeUTF8)); + QString accel = action->shortcut().toString(); + if (!accel.isEmpty()) { + QString tip = QString::fromAscii("(%1)\t%2") + .arg(accel).arg(action->statusTip()); + action->setStatusTip(tip); + } } const char* Command::keySequenceToAccel(int sk) const From ea943e0d7c01325f3adb459bdbad881f80f46217 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 14 May 2013 17:28:44 +0200 Subject: [PATCH 038/160] 0001121: IndentationError in Python Console --- src/Gui/PythonConsole.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Gui/PythonConsole.cpp b/src/Gui/PythonConsole.cpp index a8306d693..28586eb4c 100644 --- a/src/Gui/PythonConsole.cpp +++ b/src/Gui/PythonConsole.cpp @@ -786,8 +786,10 @@ bool PythonConsole::isComment(const QString& source) const QChar ch = source.at(i++); if (ch.isSpace()) continue; - if (ch == QLatin1Char('#')) + else if (ch == QLatin1Char('#')) return true; + else + return false; } return false; From 1939e61c57f91658587c04c2c4a3edcec0baa65e Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 16 May 2013 12:32:33 +0200 Subject: [PATCH 039/160] Check for decimal and group separator on startup (Windows) --- src/Gui/Application.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index da74a7e5f..0ae0513cf 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -335,6 +335,18 @@ Application::Application(bool GUIenabled) ("User parameter:BaseApp/Preferences/Units"); Base::UnitsApi::setDecimals(hUnits->GetInt("Decimals", Base::UnitsApi::getDecimals())); + // Check for the symbols for group separator and deciaml point. They must be different otherwise + // Qt doesn't work properly. +#if defined(Q_OS_WIN32) + if (QLocale::system().groupSeparator() == QLocale::system().decimalPoint()) { + QMessageBox::critical(0, QLatin1String("Invalid system settings"), + QLatin1String("Your system uses the same symbol for decimal point and group separator.\n\n" + "This causes serious problems and makes the application fail to work properly.\n" + "Go to the system configuration panel of the OS and fix this issue, please.")); + throw Base::Exception("Invalid system settings"); + } +#endif + // setting up Python binding Base::PyGILStateLocker lock; PyObject* module = Py_InitModule3("FreeCADGui", Application::Methods, From 37d1696e16a23700443dea33eed0294d54f2532c Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 17 May 2013 13:29:11 +0200 Subject: [PATCH 040/160] 0000175: Auto save function (first step) --- src/Gui/Application.cpp | 79 +++++++++++++++++++++++++++++++++++++++++ src/Gui/Application.h | 1 + src/Gui/MainWindow.cpp | 2 ++ 3 files changed, 82 insertions(+) diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index 0ae0513cf..915de9b8d 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -41,8 +41,11 @@ # include #endif # include +# include #endif +#include + // FreeCAD Base header #include @@ -1748,9 +1751,24 @@ void Application::runApplication(void) Base::Console().Log("Init: Entering event loop\n"); try { + std::stringstream s; + s << Base::FileInfo::getTempPath() << App::GetApplication().getExecutableName() + << "_" << QCoreApplication::applicationPid() << ".lock"; + // open a lock file with the PID + Base::FileInfo fi(s.str()); + Base::ofstream lock(fi); + boost::interprocess::file_lock flock(s.str().c_str()); + flock.lock(); + int ret = mainApp.exec(); if (ret == systemExit) throw Base::SystemExitException(); + + // close the lock file, in case of a crash we can see the existing lock file + // on the next restart and try to repair the documents, if needed. + flock.unlock(); + lock.close(); + fi.deleteFile(); } catch (const Base::SystemExitException&) { Base::Console().Message("System exit\n"); @@ -1765,3 +1783,64 @@ void Application::runApplication(void) Base::Console().Log("Finish: Event loop left\n"); } + +void Application::checkForPreviousCrashes() +{ + QDir tmp = QDir::temp(); + tmp.setNameFilters(QStringList() << QString::fromAscii("*.lock")); + tmp.setFilter(QDir::Files); + + QList restoreDocFiles; + QString exeName = QString::fromAscii(App::GetApplication().getExecutableName()); + QList locks = tmp.entryInfoList(); + for (QList::iterator it = locks.begin(); it != locks.end(); ++it) { + QString bn = it->baseName(); + if (bn.startsWith(exeName)) { + QString fn = it->absoluteFilePath(); + boost::interprocess::file_lock flock((const char*)fn.toLocal8Bit()); + if (flock.try_lock()) { + // OK, this file is a leftover from a previous crash + QString crashed_pid = bn.mid(exeName.length()+1); + // search for transient directories with this PID + QString filter; + QTextStream str(&filter); + str << exeName << "_Doc_*_" << crashed_pid; + tmp.setNameFilters(QStringList() << filter); + tmp.setFilter(QDir::Dirs); + QList dirs = tmp.entryInfoList(); + if (dirs.isEmpty()) { + // delete the lock file immediately if not transient directories are related + tmp.remove(fn); + } + else { + int countDeletedDocs = 0; + for (QList::iterator it = dirs.begin(); it != dirs.end(); ++it) { + QDir doc_dir(it->absoluteFilePath()); + doc_dir.setFilter(QDir::NoDotAndDotDot|QDir::AllEntries); + uint entries = doc_dir.entryList().count(); + if (entries == 0) { + // in this case we can delete the transient directory because + // we cannot do anything + if (tmp.rmdir(it->filePath())) + countDeletedDocs++; + } + else { + // store the transient directory in case it's not empty + restoreDocFiles << *it; + } + } + + // all directories corresponding to the lock file have been deleted + // so delete the lock file, too + if (countDeletedDocs == dirs.size()) { + tmp.remove(fn); + } + } + } + } + } + + if (!restoreDocFiles.isEmpty()) { + //TODO: + } +} diff --git a/src/Gui/Application.h b/src/Gui/Application.h index 1901c3694..42e739254 100644 --- a/src/Gui/Application.h +++ b/src/Gui/Application.h @@ -157,6 +157,7 @@ public: /// true when the application shuting down bool isClosing(void); + void checkForPreviousCrashes(); /** @name workbench handling */ //@{ diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index 6c91f19ed..e9b621430 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -1174,6 +1174,8 @@ void MainWindow::delayedStartup() if (hGrp->GetBool("CreateNewDoc", false)) { App::GetApplication().newDocument(); } + + Application::Instance->checkForPreviousCrashes(); } void MainWindow::appendRecentFile(const QString& filename) From 0a930d4c1a47cede65ad8d0cce813e73f89c4841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Luis=20Cerc=C3=B3s=20Pita?= Date: Mon, 20 May 2013 09:08:43 -0400 Subject: [PATCH 041/160] Regenerated branch --- src/Mod/Ship/CMakeLists.txt | 28 +- src/Mod/Ship/Makefile.am | 16 +- src/Mod/Ship/SimInstance.py | 139 ++- src/Mod/Ship/resources/opencl/jacobi.cl | 79 ++ src/Mod/Ship/resources/opencl/lsqr.cl | 186 ++++ src/Mod/Ship/resources/opencl/matrixGen.cl | 326 +++++++ src/Mod/Ship/resources/opencl/minres.cl | 94 ++ src/Mod/Ship/simCreate/TaskPanel.py | 66 +- src/Mod/Ship/simCreate/TaskPanel.ui | 147 ++- src/Mod/Ship/simRun/Sim/BEMsolver.py | 55 ++ src/Mod/Ship/simRun/Sim/__init__.py | 4 +- src/Mod/Ship/simRun/Sim/evolution.py | 304 ++++++ src/Mod/Ship/simRun/Sim/initialization.py | 418 ++++++-- src/Mod/Ship/simRun/Sim/matrixGen.py | 274 ++++-- src/Mod/Ship/simRun/Simulation.py | 137 ++- src/Mod/Ship/simRun/TaskPanel.py | 16 +- src/Mod/Ship/simRun/clSim/BEMsolver.py | 61 ++ src/Mod/Ship/simRun/clSim/__init__.py | 5 +- src/Mod/Ship/simRun/clSim/bem_jacobi_cl.py | 155 +++ src/Mod/Ship/simRun/clSim/bem_lsqr_cl.py | 229 +++++ src/Mod/Ship/simRun/clSim/bem_minres_cl.py | 157 +++ src/Mod/Ship/simRun/clSim/clUtils.py | 58 ++ src/Mod/Ship/simRun/clSim/evolution.py | 258 +++++ src/Mod/Ship/simRun/clSim/initialization.py | 322 +++++-- src/Mod/Ship/simRun/clSim/matrixGen.py | 184 ++++ src/Mod/Ship/simRun/theory/abstract.tex | 56 ++ src/Mod/Ship/simRun/theory/bib.bib | 91 ++ src/Mod/Ship/simRun/theory/deep_water.wxmx | Bin 0 -> 73355 bytes .../Ship/simRun/theory/images/CC_88x31.png | Bin 0 -> 5281 bytes .../Ship/simRun/theory/images/Integral.png | Bin 0 -> 32720 bytes .../Ship/simRun/theory/images/Integral.svg | 911 ++++++++++++++++++ src/Mod/Ship/simRun/theory/images/Omega.png | Bin 0 -> 28285 bytes src/Mod/Ship/simRun/theory/images/Omega.svg | 206 ++++ src/Mod/Ship/simRun/theory/images/Omega2.png | Bin 0 -> 43277 bytes src/Mod/Ship/simRun/theory/images/Omega2.svg | 222 +++++ .../Ship/simRun/theory/images/test_bem.png | Bin 0 -> 49139 bytes .../Ship/simRun/theory/images/test_direct.png | Bin 0 -> 48587 bytes .../Ship/simRun/theory/images/test_wave.png | Bin 0 -> 66196 bytes src/Mod/Ship/simRun/theory/laplace2D.tex | 196 ++++ src/Mod/Ship/simRun/theory/laplace3D.tex | 642 ++++++++++++ src/Mod/Ship/simRun/theory/main.aux | 125 +++ src/Mod/Ship/simRun/theory/main.bbl | 24 + src/Mod/Ship/simRun/theory/main.blg | 48 + src/Mod/Ship/simRun/theory/main.log | 827 ++++++++++++++++ src/Mod/Ship/simRun/theory/main.out | 22 + src/Mod/Ship/simRun/theory/main.pdf | Bin 0 -> 322361 bytes src/Mod/Ship/simRun/theory/main.tex | 90 ++ src/Mod/Ship/simRun/theory/main.toc | 22 + src/Mod/Ship/simRun/theory/test/green.py | 127 +++ src/Mod/Ship/simRun/theory/test/main.py | 285 ++++++ src/Mod/Ship/simRun/theory/test/waves.py | 94 ++ 51 files changed, 7305 insertions(+), 401 deletions(-) create mode 100644 src/Mod/Ship/resources/opencl/jacobi.cl create mode 100644 src/Mod/Ship/resources/opencl/lsqr.cl create mode 100644 src/Mod/Ship/resources/opencl/matrixGen.cl create mode 100644 src/Mod/Ship/resources/opencl/minres.cl create mode 100644 src/Mod/Ship/simRun/Sim/BEMsolver.py create mode 100644 src/Mod/Ship/simRun/Sim/evolution.py create mode 100644 src/Mod/Ship/simRun/clSim/BEMsolver.py create mode 100644 src/Mod/Ship/simRun/clSim/bem_jacobi_cl.py create mode 100644 src/Mod/Ship/simRun/clSim/bem_lsqr_cl.py create mode 100644 src/Mod/Ship/simRun/clSim/bem_minres_cl.py create mode 100644 src/Mod/Ship/simRun/clSim/clUtils.py create mode 100644 src/Mod/Ship/simRun/clSim/evolution.py create mode 100644 src/Mod/Ship/simRun/clSim/matrixGen.py create mode 100644 src/Mod/Ship/simRun/theory/abstract.tex create mode 100644 src/Mod/Ship/simRun/theory/bib.bib create mode 100644 src/Mod/Ship/simRun/theory/deep_water.wxmx create mode 100644 src/Mod/Ship/simRun/theory/images/CC_88x31.png create mode 100644 src/Mod/Ship/simRun/theory/images/Integral.png create mode 100644 src/Mod/Ship/simRun/theory/images/Integral.svg create mode 100644 src/Mod/Ship/simRun/theory/images/Omega.png create mode 100644 src/Mod/Ship/simRun/theory/images/Omega.svg create mode 100644 src/Mod/Ship/simRun/theory/images/Omega2.png create mode 100644 src/Mod/Ship/simRun/theory/images/Omega2.svg create mode 100644 src/Mod/Ship/simRun/theory/images/test_bem.png create mode 100644 src/Mod/Ship/simRun/theory/images/test_direct.png create mode 100644 src/Mod/Ship/simRun/theory/images/test_wave.png create mode 100644 src/Mod/Ship/simRun/theory/laplace2D.tex create mode 100644 src/Mod/Ship/simRun/theory/laplace3D.tex create mode 100644 src/Mod/Ship/simRun/theory/main.aux create mode 100644 src/Mod/Ship/simRun/theory/main.bbl create mode 100644 src/Mod/Ship/simRun/theory/main.blg create mode 100644 src/Mod/Ship/simRun/theory/main.log create mode 100644 src/Mod/Ship/simRun/theory/main.out create mode 100644 src/Mod/Ship/simRun/theory/main.pdf create mode 100644 src/Mod/Ship/simRun/theory/main.tex create mode 100644 src/Mod/Ship/simRun/theory/main.toc create mode 100644 src/Mod/Ship/simRun/theory/test/green.py create mode 100644 src/Mod/Ship/simRun/theory/test/main.py create mode 100644 src/Mod/Ship/simRun/theory/test/waves.py diff --git a/src/Mod/Ship/CMakeLists.txt b/src/Mod/Ship/CMakeLists.txt index 8137d225d..aa87360bd 100644 --- a/src/Mod/Ship/CMakeLists.txt +++ b/src/Mod/Ship/CMakeLists.txt @@ -21,6 +21,14 @@ SET(ShipExamples_SRCS ) SOURCE_GROUP("shipexamples" FILES ${ShipExamples_SRCS}) +SET(ShipOpenCL_SRCS + resources/opencl/matrixGen.cl + resources/opencl/jacobi.cl + resources/opencl/minres.cl + resources/opencl/lsqr.cl +) +SOURCE_GROUP("shipopencl" FILES ${ShipOpenCL_SRCS}) + SET(ShipLoadExample_SRCS shipLoadExample/__init__.py shipLoadExample/TaskPanel.py @@ -107,12 +115,18 @@ SET(SimRun_SRCS simRun/TaskPanel.ui simRun/clSim/__init__.py simRun/clSim/initialization.py - simRun/clSim/Utils.py + simRun/clSim/matrixGen.py + simRun/clSim/BEMsolver.py + simRun/clSim/evolution.py + simRun/clSim/clUtils.py + simRun/clSim/bem_jacobi_cl.py + simRun/clSim/bem_minres_cl.py + simRun/clSim/bem_lsqr_cl.py simRun/Sim/__init__.py simRun/Sim/initialization.py simRun/Sim/matrixGen.py - simRun/Sim/computeSources.py - simRun/Sim/fsEvolution.py + simRun/Sim/BEMsolver.py + simRun/Sim/evolution.py ) SOURCE_GROUP("simrun" FILES ${SimRun_SRCS}) @@ -123,7 +137,7 @@ SET(SimPost_SRCS ) 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}) +SET(all_files ${ShipMain_SRCS} ${ShipIcons_SRCS} ${ShipExamples_SRCS} ${ShipOpenCL_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} @@ -143,6 +157,12 @@ INSTALL( DESTINATION Mod/Ship/resources/examples ) +INSTALL( + FILES + ${ShipOpenCL_SRCS} + DESTINATION + Mod/Ship/resources/opencl +) INSTALL( FILES ${ShipLoadExample_SRCS} diff --git a/src/Mod/Ship/Makefile.am b/src/Mod/Ship/Makefile.am index fd24beac6..c71bc97b5 100644 --- a/src/Mod/Ship/Makefile.am +++ b/src/Mod/Ship/Makefile.am @@ -15,6 +15,10 @@ nobase_data_DATA = \ resources/examples/wigley.fcstd \ resources/examples/wigley_katamaran.fcstd \ resources/icons/Ico.xpm \ + resources/opencl/matrixGen.cl \ + resources/opencl/jacobi.cl \ + resources/opencl/minres.cl \ + resources/opencl/lsqr.cl \ shipLoadExample/__init__.py \ shipLoadExample/TaskPanel.py \ shipLoadExample/TaskPanel.ui \ @@ -60,12 +64,18 @@ nobase_data_DATA = \ simRun/TaskPanel.ui \ simRun/clSim/__init__.py \ simRun/clSim/initialization.py \ - simRun/clSim/Utils.py \ + simRun/clSim/matrixGen.py \ + simRun/clSim/BEMsolver.py \ + simRun/clSim/evolution.py \ + simRun/clSim/clUtils.py \ + simRun/clSim/bem_jacobi_cl.py \ + simRun/clSim/bem_minres_cl.py \ + simRun/clSim/bem_lsqr_cl.py \ simRun/Sim/__init__.py \ simRun/Sim/initialization.py \ simRun/Sim/matrixGen.py \ - simRun/Sim/computeSources.py \ - simRun/Sim/fsEvolution.py \ + simRun/Sim/BEMsolver.py \ + simRun/Sim/evolution.py \ simPost/__init__.py \ simPost/TaskPanel.py \ simPost/TaskPanel.ui diff --git a/src/Mod/Ship/SimInstance.py b/src/Mod/Ship/SimInstance.py index 0e8f6db2a..638c17612 100644 --- a/src/Mod/Ship/SimInstance.py +++ b/src/Mod/Ship/SimInstance.py @@ -62,19 +62,38 @@ class FreeSurfaceFace: self.area = area class ShipSimulation: - def __init__(self, obj, fsMeshData, waves): + def __init__(self, obj, fsMeshData, waves, error): """ Creates a new simulation instance on active document. @param obj Created Part::FeaturePython object. + @param h Sea water level. @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 + @param waves [[A,T,phi,heading],] Waves involved. + @param error Relation between the minimum and the maximum Green's function values. """ # Add uniqueness property to identify Tank instances tooltip = str(QtGui.QApplication.translate("Ship","True if is a valid ship simulation instance", None,QtGui.QApplication.UnicodeUTF8)) obj.addProperty("App::PropertyBool","IsShipSimulation","ShipSimulation", tooltip).IsShipSimulation=True + # Store general data + tooltip = str(QtGui.QApplication.translate("Ship","Free surface length in the x direction", + None,QtGui.QApplication.UnicodeUTF8)) + obj.addProperty("App::PropertyFloat","L","ShipSimulation", tooltip).L=fsMeshData[0] + tooltip = str(QtGui.QApplication.translate("Ship","Free surface length in the y direction", + None,QtGui.QApplication.UnicodeUTF8)) + obj.addProperty("App::PropertyFloat","B","ShipSimulation", tooltip).B=fsMeshData[1] + tooltip = str(QtGui.QApplication.translate("Ship","Free surface number of elements at x direction", + None,QtGui.QApplication.UnicodeUTF8)) + obj.addProperty("App::PropertyInteger","FS_Nx","ShipSimulation", tooltip).FS_Nx=fsMeshData[2] + tooltip = str(QtGui.QApplication.translate("Ship","Free surface number of elements at y direction", + None,QtGui.QApplication.UnicodeUTF8)) + obj.addProperty("App::PropertyInteger","FS_Ny","ShipSimulation", tooltip).FS_Ny=fsMeshData[3] + tooltip = str(QtGui.QApplication.translate("Ship","Relative error of the Green's function", + None,QtGui.QApplication.UnicodeUTF8)) + obj.addProperty("App::PropertyFloat","error","ShipSimulation", tooltip).error=error # Compute free surface mesh self.createFSMesh(obj,fsMeshData) + self.createVirtualFS(obj,fsMeshData,error) self.computeWaves(obj,waves) # Store waves tooltip = str(QtGui.QApplication.translate("Ship","Waves (Amplitude,period,phase)", @@ -112,8 +131,8 @@ class ShipSimulation: 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. + @param fsMeshData [L,B,Nx,Ny] Free surface mesh data, with lenght + (x), Breath (y) and desired number of points at each direction. """ # Study input object try: @@ -130,29 +149,17 @@ class ShipSimulation: FreeCAD.Console.PrintError(msg + '\n') return # Get areas and number of elements per direction - L = fsMeshData[0] - B = fsMeshData[1] - N = fsMeshData[2] - A = L*B + L = fsMeshData[0] + B = fsMeshData[1] + nx = fsMeshData[2] + ny = fsMeshData[3] + N = nx*ny + A = L*B area = A/N - l = sqrt(area) - b = sqrt(area) - nx = int(round(L / l)) - ny = int(round(B / b)) + l = L/nx + b = B/ny # Start data fields if not already exist props = obj.PropertiesList - try: - props.index("FS_Nx") - except ValueError: - tooltip = str(QtGui.QApplication.translate("Ship","Free surface number of elements at x direction", - None,QtGui.QApplication.UnicodeUTF8)) - obj.addProperty("App::PropertyInteger","FS_Nx","ShipSimulation", tooltip).FS_Nx=0 - try: - props.index("FS_Ny") - except ValueError: - tooltip = str(QtGui.QApplication.translate("Ship","Free surface number of elements at y direction", - None,QtGui.QApplication.UnicodeUTF8)) - obj.addProperty("App::PropertyInteger","FS_Ny","ShipSimulation", tooltip).FS_Ny=0 try: props.index("FS_Position") except ValueError: @@ -172,6 +179,8 @@ class ShipSimulation: None,QtGui.QApplication.UnicodeUTF8)) obj.addProperty("App::PropertyVectorList","FS_Normal","ShipSimulation", tooltip).FS_Normal=[] # Fill data + obj.L = L + obj.B = B obj.FS_Nx = nx obj.FS_Ny = ny pos = [] @@ -186,6 +195,68 @@ class ShipSimulation: obj.FS_Area = areas[:] obj.FS_Normal = normal[:] + def createVirtualFS(self, obj, fsMeshData, error): + """ Computes the number of required extended free surfaces. + @param obj Created Part::FeaturePython object. + @param fsMeshData [L,B,Nx,Ny] Free surface mesh data, with lenght + (x), Breath (y) and desired number of points at each direction. + @param error Relation between the minimum and the maximum Green's function values. + """ + # Study input object + try: + props = obj.PropertiesList + props.index("IsShipSimulation") + if not obj.IsShipSimulation: + msg = QtGui.QApplication.translate("ship_console", "Object is not a valid ship simulation", + None,QtGui.QApplication.UnicodeUTF8) + FreeCAD.Console.PrintError(msg + '\n') + return + except ValueError: + msg = QtGui.QApplication.translate("ship_console", "Object is not a ship simulation", + None,QtGui.QApplication.UnicodeUTF8) + FreeCAD.Console.PrintError(msg + '\n') + return + # Get dimensions of the elements + L = fsMeshData[0] + B = fsMeshData[1] + nx = fsMeshData[2] + ny = fsMeshData[3] + dx = L / nx + dy = B / ny + # Compute maximum Green's function considering flat free surface + Gmax = dx*asinh(dy/dx) + dy*asinh(dx/dy) + # Locate the distance (number of free surface) to get the minimum required value + Gmin = error*Gmax + x = (L-dx)/2.0 + Nx = 0 + G = Gmin + 1.0 + while(G > Gmin): + x = x + L + Nx = Nx + 1 + G = 1.0 / (4.0*pi * x) + y = (B-dy)/2.0 + Ny = 0 + G = Gmin + 1.0 + while(G > Gmin): + y = y + L + Ny = Ny + 1 + G = 1.0 / (4.0*pi * y) + # Register computed data + try: + props.index("Sea_Nx") + except ValueError: + tooltip = str(QtGui.QApplication.translate("Ship","Number of repetitions of the free surface at x direction", + None,QtGui.QApplication.UnicodeUTF8)) + obj.addProperty("App::PropertyInteger","Sea_Nx","ShipSimulation", tooltip).Sea_Nx=0 + try: + props.index("Sea_Ny") + except ValueError: + tooltip = str(QtGui.QApplication.translate("Ship","Number of repetitions of the free surface at y direction", + None,QtGui.QApplication.UnicodeUTF8)) + obj.addProperty("App::PropertyInteger","Sea_Ny","ShipSimulation", tooltip).Sea_Ny=0 + obj.Sea_Nx = Nx + obj.Sea_Ny = Ny + def computeWaves(self, obj, waves): """ Add waves effect to free surface mesh positions. @param obj Created Part::FeaturePython object. @@ -215,21 +286,14 @@ class ShipSimulation: """ 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) + mesh = FSMesh(obj) + surf = Part.BSplineSurface() + pos = [] for i in range(0,nx): + pos.append([]) 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) + pos[i].append(mesh[i][j].pos) + surf.interpolate(pos) return surf.toShape() class ViewProviderShipSimulation: @@ -694,3 +758,4 @@ def FSMesh(obj, recompute=False): 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/resources/opencl/jacobi.cl b/src/Mod/Ship/resources/opencl/jacobi.cl new file mode 100644 index 000000000..88eadc992 --- /dev/null +++ b/src/Mod/Ship/resources/opencl/jacobi.cl @@ -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 * + */ + +/** Compute residuals of the solution stimator for a linear system. + * @param A Linear system matrix. + * @param B Linear system independent term. + * @param X Solution estimation. + * @param R Residuals. + * @param n Linear system dimension. + */ +__kernel void r(__global float* A, + __global float* B, + __global float* X, + __global float* R, + unsigned int n) +{ + // find position in global arrays + unsigned int i = get_global_id(0); + unsigned int j; + if(i >= n) + return; + // Evaluate the row + R[i] = B[i]; + for(j=0;j= n) + return; + // Evaluate the row + X[i] = B[i]; + for(j=0;j * + * * + * 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 * + */ + +/** Get matrix column. + * @param A Linear system matrix. + * @param v Column vector (output). + * @param col Column index. + * @param n Linear system dimension. + */ +__kernel void column(__global float* A, + __global float* v, + unsigned int col, + unsigned int n) +{ + // find position in global arrays + unsigned int i = get_global_id(0); + if(i >= n) + return; + v[i] = A[i + col*n]; +} + +/** Performs matrix column product by a constant. + * @param A Linear system matrix. + * @param c Constant. + * @param col Column index. + * @param n Linear system dimension. + */ +__kernel void prod_c_column(__global float* A, + float c, + unsigned int col, + unsigned int n) +{ + // find position in global arrays + unsigned int i = get_global_id(0); + if(i >= n) + return; + A[i + col*n] *= c; +} + +/** Compute residuals of the solution stimator for a linear system. + * @param A Linear system matrix. + * @param B Linear system independent term. + * @param X Solution estimation. + * @param R Residuals. + * @param n Linear system dimension. + */ +__kernel void r(__global float* A, + __global float* B, + __global float* X, + __global float* R, + unsigned int n) +{ + // find position in global arrays + unsigned int i = get_global_id(0); + unsigned int j; + if(i >= n) + return; + // Evaluate the row + R[i] = B[i]; + for(j=0;j= n) + return; + // Evaluate the row + Y[i] = 0.f; + for(j=0;j= n) + return; + // Evaluate the row + Y[i] = 0.f; + for(j=0;j= n) + return; + // Evaluate the row + u[i] = - alpha * u0[i]; + for(j=0;j= n) + return; + // Evaluate the row + v[i] = - beta * v0[i]; + for(j=0;j * + * * + * 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 * + */ + +#ifndef M_PI + #define M_PI 3.14159265f +#endif + +#ifndef _NG_ + #define _NG_ 16 +#endif + +/** Compute \$G_{ab}\$ effect: \n + * \$ G_{ab} = \frac{1}{4 \pi \vert \mathbf{r} \vert } \$ + * @param r Union vector \$ \mathbf{r}_{ab} \$ + */ +float G_val(float4 r) +{ + return 1.f / ( 4.f*M_PI * length(r) ); +} + +/** Compute \$H_{ab}\$ effect: \n + * \$ H_{ab} = \frac{\mathbf{r}}{4 \pi \vert \mathbf{r} \vert^3} \cdot n_b \$ + * @param r Union vector \$ \mathbf{r}_{ab} \$ + * @param n Element normal \$ n_b \$ + */ +float H_val(float4 r, + float4 n) +{ + return - dot(r,n) / (4.f*M_PI * pow(dot(r,r),1.5f)); +} + +/** Computes z coordinate due to the waves superposition + * for a desired position. + * @param w Array of waves. + * @param p Point to compute. + * @param t Simulation time. + * @param nW Number of waves. + * @return z coordinate. + */ +float waves_z(__global float4* w, float4 p, float t, unsigned int nW) +{ + /* + return 0.f; + */ + + unsigned int i; + float z = 0.f; + for(i=0;i -0.5*L) && + (P[i*3+j].x < 0.5*L) && + (P[i*3+j].y > -0.5*B) && + (P[i*3+j].y < 0.5*B)) + P[i*3+j].z = positions[(I-1+i)*ny + (J-1+j)].z; + else + P[i*3+j].z = waves_z(w, P[i*3+j], t, nW); + P[i*3+j].w = 0.f; + } + } + // Get SPline surface coeffs + K[0] = P[0].z; // k_{0} + K[1] = 4*P[3].z - P[6].z - 3*P[0].z; // k_{u} + K[2] = 4*P[1].z - P[2].z - 3*P[0].z; // k_{v} + K[3] = P[8].z - 4*P[7].z + 3*P[6].z + + 3*P[2].z - 12*P[1].z + 9*P[0].z + + -4*P[5].z + 16*P[4].z - 12*P[3].z; // k_{uv} + K[4] = 2*P[6].z + 2*P[0].z - 4*P[3].z; // k_{uu} + K[5] = 2*P[2].z + 2*P[0].z - 4*P[1].z; // k_{vv} + K[6] = -2*P[8].z + 8*P[7].z - 6*P[6].z + + -2*P[2].z + 8*P[1].z - 6*P[0].z + + 4*P[5].z - 16*P[4].z + 12*P[3].z; // k_{uuv} + K[7] = -2*P[8].z + 4*P[7].z - 2*P[6].z + + -6*P[2].z + 12*P[1].z - 6*P[0].z + + 8*P[5].z - 16*P[4].z + 8*P[3].z; // k_{uuv} + K[8] = 4*P[8].z - 8*P[7].z + 4*P[6].z + + 4*P[2].z - 8*P[1].z + 4*P[0].z + + -8*P[5].z + 16*P[4].z - 8*P[3].z; // k_{uuvv} + // Loop around the point p collecting the integral + float2 gh; + gh.x = 0.0f; + gh.y = -0.5f; + for(i=0;i<_NG_;i++){ + for(j=0;j<_NG_;j++){ + float4 p_a; + float u,v; + p_a.x = positions[I*ny + J].x - 0.5f*dx + (i+0.5f)*Dx; + p_a.y = positions[I*ny + J].y - 0.5f*dy + (j+0.5f)*Dy; + u = (p_a.x - P[0].x) / (P[6].x - P[0].x); + v = (p_a.y - P[0].y) / (P[2].y - P[0].y); + p_a.z = K[0] + K[1]*u + K[2]*v + K[3]*u*v + + K[4]*u*u + K[5]*v*v + K[6]*u*u*v + + K[7]*u*v*v + K[8]*u*u*v*v; + p_a.w = 1.f; + gh.x += G_val(p_a - p)*Dx*Dy; + // For some reason H is not well integrated + // gh.y += H_val(p_a - p, n)*Dx*Dy; + } + } + return gh; +} + +/** Compute Linear system matrix. Desingularized sources must taken into account. + * @param A Linear system matrix. + * @param B Independent term for velocity potentials. + * @param positions Elements points. + * @param areas Elements area. + * @param normals Elements normals. + * @param p Velocity potentials. + * @param dp Acceleration potentials. + * @param waves Array of waves data (Amplitude,period,phase,heading) + * @param l Free surface length in the x direction. + * @param b Free surface length in the y direction. + * @param dx Distance between element centers in the x direction. + * @param dy Distance between element centers in the x direction. + * @param t Simulation time. + * @param nx Free surface points in the x direction. + * @param ny Free surface points in the y direction. + * @param nFS Number of points in the free surface. + * @param nB Number of points in the body (ignored yet, should be 0). + * @param n Total number of points. + * @param nSeax Number of repetitions of the free surface in the x direction. + * @param nSeay Number of repetitions of the free surface in the y direction. + * @param nW Number of waves. + */ +__kernel void matrixGen(__global float* A, + __global float* B, + __global float4* positions, + __global float* areas, + __global float4* normals, + __global float* p, + __global float* dp, + __global float4* waves, + float l, + float b, + float dx, + float dy, + float t, + unsigned int nx, + unsigned int ny, + unsigned int nFS, + unsigned int nB, + unsigned int n, + int nSeax, + int nSeay, + unsigned int nW) +{ + // find position in global arrays + unsigned int i = get_global_id(0); + unsigned int j; + int I,J; + if(i >= n) + return; + // Get the point where we want to evaluate + float4 p_a = positions[i]; + // Evaluate the row + B[i] = 0.f; + for(j=0;j * + * * + * 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 * + */ + +/** Compute residuals of the solution stimator for a linear system. + * @param A Linear system matrix. + * @param B Linear system independent term. + * @param X Solution estimation. + * @param R Residuals. + * @param n Linear system dimension. + */ +__kernel void r(__global float* A, + __global float* B, + __global float* X, + __global float* R, + unsigned int n) +{ + // find position in global arrays + unsigned int i = get_global_id(0); + unsigned int j; + if(i >= n) + return; + // Evaluate the row + R[i] = B[i]; + for(j=0;j= n) + return; + // Evaluate the row + Y[i] = 0.f; + for(j=0;j= n) + return; + // Evaluate the row + x[i] = x0[i] + Ar_r / Ar_Ar * r[i]; +} + diff --git a/src/Mod/Ship/simCreate/TaskPanel.py b/src/Mod/Ship/simCreate/TaskPanel.py index 7e200532b..1f3592709 100644 --- a/src/Mod/Ship/simCreate/TaskPanel.py +++ b/src/Mod/Ship/simCreate/TaskPanel.py @@ -49,9 +49,10 @@ class TaskPanel: 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) + sim = SimInstance.ShipSimulation(obj, + [form.fsL.value(), form.fsB.value(), form.fsNx.value(), form.fsNy.value()], + w, + form.error.value()) SimInstance.ViewProviderShipSimulation(obj.ViewObject) return True @@ -80,21 +81,25 @@ class TaskPanel: 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") + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.fsL = form.findChild(QtGui.QDoubleSpinBox, "Length") + form.fsB = form.findChild(QtGui.QDoubleSpinBox, "Beam") + form.fsNx = form.findChild(QtGui.QSpinBox, "Nx") + form.fsNy = form.findChild(QtGui.QSpinBox, "Ny") + form.error = form.findChild(QtGui.QDoubleSpinBox, "Error") + 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.fsL, QtCore.SIGNAL("valueChanged(double)"), self.onFS) + QtCore.QObject.connect(form.fsB, QtCore.SIGNAL("valueChanged(double)"), self.onFS) + QtCore.QObject.connect(form.fsNx, QtCore.SIGNAL("valueChanged(int)"), self.onFS) + QtCore.QObject.connect(form.fsNy, QtCore.SIGNAL("valueChanged(int)"), self.onFS) + QtCore.QObject.connect(form.error, QtCore.SIGNAL("valueChanged(double)"), self.onError) QtCore.QObject.connect(form.waves,QtCore.SIGNAL("cellChanged(int,int)"),self.onWaves); def getMainWindow(self): @@ -120,14 +125,12 @@ class TaskPanel: None,QtGui.QApplication.UnicodeUTF8)) self.form.findChild(QtGui.QGroupBox, "FSDataBox").setTitle(QtGui.QApplication.translate("shipsim_create","Free surface", None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "LengthLabel").setText(QtGui.QApplication.translate("shipsim_create","Length", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "BeamLabel").setText(QtGui.QApplication.translate("shipsim_create","Breadth", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "NLabel").setText(QtGui.QApplication.translate("shipsim_create","Number of points", - None,QtGui.QApplication.UnicodeUTF8)) self.form.findChild(QtGui.QGroupBox, "WavesDataBox").setTitle(QtGui.QApplication.translate("shipsim_create","Waves", None,QtGui.QApplication.UnicodeUTF8)) + self.form.findChild(QtGui.QGroupBox, "OtherBox").setTitle(QtGui.QApplication.translate("shipsim_create","Other", + None,QtGui.QApplication.UnicodeUTF8)) + self.form.findChild(QtGui.QLabel, "ErrorLabel").setText(QtGui.QApplication.translate("shipsim_create","Relative error", + None,QtGui.QApplication.UnicodeUTF8)) labels = [] labels.append(QtGui.QApplication.translate("shipsim_create","Amplitude", None,QtGui.QApplication.UnicodeUTF8) + " [m]") @@ -138,6 +141,27 @@ class TaskPanel: labels.append(QtGui.QApplication.translate("shipsim_create","Heading", None,QtGui.QApplication.UnicodeUTF8) + " [deg]") self.form.waves.setHorizontalHeaderLabels(labels) + # Set some tooltips + tooltip = QtGui.QApplication.translate("shipsim_create","Free surface length on x direction", + None,QtGui.QApplication.UnicodeUTF8) + self.form.findChild(QtGui.QLabel, "LengthLabel").setToolTip(tooltip) + self.form.findChild(QtGui.QDoubleSpinBox, "Length").setToolTip(tooltip) + tooltip = QtGui.QApplication.translate("shipsim_create","Free surface length on y direction", + None,QtGui.QApplication.UnicodeUTF8) + self.form.findChild(QtGui.QLabel, "BeamLabel").setToolTip(tooltip) + self.form.findChild(QtGui.QDoubleSpinBox, "Beam").setToolTip(tooltip) + tooltip = QtGui.QApplication.translate("shipsim_create","Number of nodes on x direction. Take into acount the following considerations:\n1.\tNodes must have an aspect ratio as near to 1,0 as possible, so this values must\n\taccomplish approximately that Nx/Ny = L/B\n3.\tThe linear system matrix generated will be of dimensions NxN, where\n\tN = Nx*Ny\n\tSo be mindful with the values selected and computer capabilities.", + None,QtGui.QApplication.UnicodeUTF8) + self.form.findChild(QtGui.QLabel, "NxLabel").setToolTip(tooltip) + self.form.findChild(QtGui.QSpinBox, "Nx").setToolTip(tooltip) + tooltip = QtGui.QApplication.translate("shipsim_create","Number of nodes on y direction. Take into acount the following considerations:\n1.\tNodes must have an aspect ratio as near to 1,0 as possible, so this values must\n\taccomplish approximately that Nx/Ny = L/B\n3.\tThe linear system matrix generated will be of dimensions NxN, where\n\tN = Nx*Ny\n\tSo be mindful with the values selected and computer capabilities.", + None,QtGui.QApplication.UnicodeUTF8) + self.form.findChild(QtGui.QLabel, "NyLabel").setToolTip(tooltip) + self.form.findChild(QtGui.QSpinBox, "Ny").setToolTip(tooltip) + tooltip = QtGui.QApplication.translate("shipsim_create","Relation between the minimum value of the Green's function (fartest point) and the maximum one.\nThis variable set the number of times that the Free surface will be virtually repeated.\nLower values may imply too much repeated free surfaces with a significant cost.", + None,QtGui.QApplication.UnicodeUTF8) + self.form.findChild(QtGui.QLabel, "ErrorLabel").setToolTip(tooltip) + self.form.findChild(QtGui.QDoubleSpinBox, "Error").setToolTip(tooltip) def onFS(self, value): """ Method called when free surface data is changed. @@ -145,6 +169,12 @@ class TaskPanel: """ pass + def onError(self, value): + """ Method called when sea data is changed. + @param value Changed value. + """ + pass + def onWaves(self, row, column): """ Method called when waves data is changed. @param row Affected row. diff --git a/src/Mod/Ship/simCreate/TaskPanel.ui b/src/Mod/Ship/simCreate/TaskPanel.ui index 107d2a16d..6dcc376a5 100644 --- a/src/Mod/Ship/simCreate/TaskPanel.ui +++ b/src/Mod/Ship/simCreate/TaskPanel.ui @@ -6,7 +6,7 @@ 0 0 - 269 + 386 384 @@ -42,7 +42,7 @@ 0 - 128 + 0 @@ -55,11 +55,11 @@ false - - QLayout::SetDefaultConstraint - + + 2 + QLayout::SetMinimumSize @@ -78,15 +78,27 @@ - Length + L + + + 0 + 0 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + 1 + + 1.000000000000000 + 1000000.000000000000000 @@ -98,37 +110,30 @@ - - - - - - QLayout::SetMinimumSize - - - 10 - - - 0 - - - 10 - - - 0 - - Beam + B + + + 0 + 0 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + 1 + + 1.000000000000000 + 1000000.000000000000000 @@ -160,22 +165,60 @@ 0 - + - Number of points + Nx - + + + + 0 + 0 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 3 + + + 10000000 + + + 25 + + + + + + + Ny + + + + + + + + 0 + 0 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + 1 - 1000000000 + 1000000 - 1000 + 25 @@ -260,6 +303,48 @@ + + + + Other + + + + + + + + Relative error + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + 0.000100000000000 + + + 1.000000000000000 + + + 0.001000000000000 + + + 0.001000000000000 + + + + + + + + diff --git a/src/Mod/Ship/simRun/Sim/BEMsolver.py b/src/Mod/Ship/simRun/Sim/BEMsolver.py new file mode 100644 index 000000000..da6932483 --- /dev/null +++ b/src/Mod/Ship/simRun/Sim/BEMsolver.py @@ -0,0 +1,55 @@ +#*************************************************************************** +#* * +#* 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 +import scipy.linalg as la +import FreeCAD + +grav=9.81 + +class simBEMSolver: + 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, bem): + """ Compute potential unknow data (gradients for free surface, and + potentials for the other ones). + @param bem Boundary Element Method instance. + """ + [bem['Ap'], residues, rank, s] = la.lstsq(bem['A'], bem['B']) + if(rank < bem['N']): + FreeCAD.Console.PrintError("\t\t[Sim]: Solving velocity potentials.\n") + FreeCAD.Console.PrintError("\t\t\tEffective rank of linear system matrix is %i (N = %i)\n" % (rank, bem['N'])) + [bem['Adp'], residues, rank, s] = la.lstsq(bem['A'], bem['dB']) + if(rank < bem['N']): + FreeCAD.Console.PrintError("\t\t[Sim]: Solving acceleration potentials.\n") + FreeCAD.Console.PrintError("\t\t\tEffective rank of linear system matrix is %i (N = %i)\n" % (rank, bem['N'])) + diff --git a/src/Mod/Ship/simRun/Sim/__init__.py b/src/Mod/Ship/simRun/Sim/__init__.py index aabf4a621..6a185fde4 100644 --- a/src/Mod/Ship/simRun/Sim/__init__.py +++ b/src/Mod/Ship/simRun/Sim/__init__.py @@ -23,5 +23,5 @@ from initialization import * from matrixGen import * -from computeSources import * -from fsEvolution import * +from BEMsolver import * +from evolution import * diff --git a/src/Mod/Ship/simRun/Sim/evolution.py b/src/Mod/Ship/simRun/Sim/evolution.py new file mode 100644 index 000000000..1108cefe1 --- /dev/null +++ b/src/Mod/Ship/simRun/Sim/evolution.py @@ -0,0 +1,304 @@ +#*************************************************************************** +#* * +#* 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 simEvolution: + 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 executeRK4(self, x, dx, p, dp, pos, vel, phi, dphi, fs, sea, body, waves, dt, t, stage): + """ Compute free surface RK4 stage evolution process (valid for stages 1,2 and 3). + @param x Output free surface z coordinates. + @param dx Output free surface z coordinates variation (dz/dt). + @param p Output potentials. + @param dp Output potentials variation (dphi/dt). + @param pos Input free surface positions. + @param vel Input free surface velocities. + @param phi Input potentials. + @param dphi Input potentials variation (dphi/dt). + @param fs Free surface instance. + @param sea Sea instance. + @param body Body instance. + @param waves Waves instance. + @param dt Time step. + @param t Actual time (without adding dt). + @param stage Runge-Kutta4 stage. + @return Input variables evoluted one time step. + """ + # -------------------------------------------- + # Only free surface + # -------------------------------------------- + h = fs['h'] + nx = fs['Nx'] + ny = fs['Ny'] + nF = nx*ny + factor = 0.5 + if stage > 2: + factor = 1. + for i in range(0,nx): + for j in range(0,ny): + x[i,j] = np.copy(pos[i,j][2]) + dx[i,j] = np.copy(vel[i,j][2]) + x[i,j] = x[i,j] + factor*dt*dx[i,j] + p[i*ny+j] = np.copy(phi[i*ny+j]) + dp[i*ny+j] = np.copy(dphi[i*ny+j]) + p[i*ny+j] = p[i*ny+j] + factor*dt*dp[i*ny+j] + # Impose values at beach (far free surface) + nbx = fs['Beachx'] + nby = fs['Beachy'] + for i in range(0,nx): + for j in range(0,nby) + range(ny-nby,ny): + [x[i,j],dx[i,j],p[i*ny+j],dp[i*ny+j]] = self.beach(pos[i,j], waves, factor*dt, t) + for j in range(0,ny): + for i in range(0,nbx) + range(nx-nbx,nx): + [x[i,j],dx[i,j],p[i*ny+j],dp[i*ny+j]] = self.beach(pos[i,j], waves, factor*dt, t) + # -------------------------------------------- + # Sea boundaries, where potentials are fixed. + # We use the gradient projected over normal, + # see initialization for more details about + # this. + # -------------------------------------------- + ids = ['front','back','left','right','bottom'] + i0 = fs['N'] + for index in ids: + s = sea[index] + nx = s['Nx'] + ny = s['Ny'] + for i in range(0,nx): + for j in range(0,ny): + p[i0 + i*ny+j] = 0. + dp[i0 + i*ny+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 + pos = s['pos'][i,j] + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + normal = s['normal'][i,j] + hfact = np.cosh(k*(pos[2]+h)) / np.cosh(k*h) + factor = np.dot(normal,np.array([np.cos(heading), np.sin(heading), 0.])) + amp = frec*A*np.sin(k*l - frec*(t+factor*dt) + phase)*hfact + p[i0 + i*ny+j] = p[i0 + i*ny+j] + factor*amp + amp = - grav*A*k*np.cos(k*l - frec*(t+factor*dt) + phase)*hfact + dp[i0 + i*ny+j] = dp[i0 + i*ny+j] + factor*amp + i0 = i0 + s['N'] + + def execute(self, dx1, dx2, dx3, dp1, dp2, dp3, fs, sea, body, waves, bem, dt, t): + """ Compute free surface evolution process (execute it on RK4 last stage). + @param dx1 Input free surface positions variation on stage 1. + @param dx2 Input free surface positions variation on stage 2. + @param dx3 Input free surface positions variation on stage 3. + @param dp1 Input free surface potentials variation on stage 1. + @param dp2 Input free surface potentials variation on stage 2. + @param dp3 Input free surface potentials variation on stage 3. + @param fs Free surface instance. + @param sea Sea instance. + @param body Body instance. + @param waves Waves instance. + @param bem Boundary Element Method instance. + @param dt Time step. + @param t Actual time (without adding dt). + @param stage Runge-Kutta4 stage. + @return Input variables evoluted one time step. + """ + h = fs['h'] + nx = fs['Nx'] + ny = fs['Ny'] + nF = nx*ny + for i in range(0,nx): + for j in range(0,ny): + # In this stage dx4 and dp4 are directly known from the previous + # stage. + dx4 = fs['vel'][i,j][2] + dp4 = bem['dp4'][i*ny+j] + # And we only need to apply the integration scheme + fs['pos'][i,j][2] = fs['pos'][i,j][2] + dt/6. * (dx1[i,j] + 2.*dx2[i,j] + 2.*dx3[i,j] + dx4) + bem['p4'][i*ny+j] = bem['p4'][i*ny+j] + dt/6. * (dp1[i*ny+j] + 2.*dp2[i*ny+j] + 2.*dp3[i*ny+j] + dp4) + # In order to can apply the boundary condition at the free surface + # at the end of this RK4 stage, we need to store eta in a variable. + # x1 is safe because will be over written at the start of next + # time step. + fs['x1'][i,j] = fs['pos'][i,j][2] + # Impose values at beach (far free surface) + nbx = fs['Beachx'] + nby = fs['Beachy'] + for i in range(0,nx): + for j in range(0,nby) + range(ny-nby,ny): + [x,dummy,p,dummy] = self.beach(fs['pos'][i,j], waves, dt, t) + fs['pos'][i,j][2] = x + bem['p4'][i*ny+j] = p + fs['x1'][i,j] = fs['pos'][i,j][2] + for j in range(0,ny): + for i in range(0,nbx) + range(nx-nbx,nx): + [x,dummy,p,dummy] = self.beach(fs['pos'][i,j], waves, dt, t) + fs['pos'][i,j][2] = x + bem['p4'][i*ny+j] = p + fs['x1'][i,j] = fs['pos'][i,j][2] + # -------------------------------------------- + # Sea boundaries, where potentials are fixed. + # We use the gradient projected over normal, + # see initialization for more details about + # this. + # -------------------------------------------- + ids = ['front','back','left','right','bottom'] + i0 = fs['N'] + p = bem['p4'] + dp = bem['dp4'] + for index in ids: + s = sea[index] + nx = s['Nx'] + ny = s['Ny'] + for i in range(0,nx): + for j in range(0,ny): + p[i0 + i*ny+j] = 0. + dp[i0 + i*ny+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 + pos = s['pos'][i,j] + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + normal = s['normal'][i,j] + hfact = np.cosh(k*(pos[2]+h)) / np.cosh(k*h) + factor = np.dot(normal,np.array([np.cos(heading), np.sin(heading), 0.])) + amp = frec*A*np.sin(k*l - frec*(t+factor*dt) + phase)*hfact + p[i0 + i*ny+j] = p[i0 + i*ny+j] + factor*amp + amp = - grav*A*k*np.cos(k*l - frec*(t+factor*dt) + phase)*hfact + dp[i0 + i*ny+j] = dp[i0 + i*ny+j] + factor*amp + i0 = i0 + s['N'] + + def executeFSBC(self, x, fs, sea, body, waves, bem, dt, t, stage): + """ Compute free surface boundary conditions in order to get + free surface points velocity and potentials acceleration for + the next RK4 stage. + @param x Free surface z coordinates. + @param fs Free surface instance. + @param sea Sea boundaries instance. + @param body Body instance. + @param waves Waves instance. + @param bem Boundary Element Method instance. + @param dt Time step. + @param t Actual time (without adding dt). + """ + nx = fs['Nx'] + ny = fs['Ny'] + nF = nx*ny + factor = 0.5 + if stage > 2: + factor = 1. + for i in range(0,nx): + for j in range(0,ny): + pos = np.copy(fs['pos'][i,j]) + pos[2] = x[i,j] + gradVal = bem['Ap'][i*ny+j] + normal = fs['normal'][i,j] + # v_z = dphi/dz - grad(phi)*grad(z) - U*dz/dx + dzdt = gradVal*normal[2] + # dphi/dt = - rho*g*z - 0.5*grad(phi)^2 + v_z*dphi/dz - p_0 - U*dphi/dx - dU/dt*x + dphidt = -grav*pos[2] - 0.5*np.dot(gradVal,gradVal) # + dzdt*gradVal*normal[2] + # We need to preserve data on free surface global + # velocity and potential values in order to use as + # input of the next RK4 stage + fs['vel'][i,j][2] = dzdt + bem['dp4'][i*ny+j] = dphidt + # Impose values at beach (far free surface) + nbx = fs['Beachx'] + nby = fs['Beachy'] + for i in range(0,nx): + for j in range(0,nby) + range(ny-nby,ny): + [dummy,dx,dummy,dp] = self.beach(fs['pos'][i,j], waves, factor*dt, t) + fs['vel'][i,j][2] = dx + bem['dp4'][i*ny+j] = dp + for j in range(0,ny): + for i in range(0,nbx) + range(nx-nbx,nx): + [dummy,dx,dummy,dp] = self.beach(fs['pos'][i,j], waves, factor*dt, t) + fs['vel'][i,j][2] = dx + bem['dp4'][i*ny+j] = dp + + def beach(self, pos, waves, dt, t): + """ Compute far free surface where only + incident waves can be taken into account. + @param pos Free surface position. + @param waves Waves instance. + @param dt Time step. + @param t Actual time (without adding dt). + @return Position, velocity, potential and potential acceleration + """ + h = waves['h'] + x = 0. + dx = 0. + p = 0. + dp = 0. + # Since values of the potencial, and this acceleration, + # depends on z, we need to compute first the positions. + 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) + # hfact = np.sinh(k*(pos[2]+h)) / np.cosh(k*h) + hfact = 1.0 + amp = A*np.sin(k*l - frec*(t+dt) + phase)*hfact + x = x + amp + amp = - A*frec*np.cos(k*l - frec*(t+dt) + phase)*hfact + dx = dx + amp + # And now we can compute 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) + hfact = np.cosh(k*(x+h)) / np.cosh(k*h) + amp = - grav/frec*A*np.sin(k*l - frec*(t+dt) + phase)*hfact + p = p + amp + amp = grav*A*np.cos(k*l - frec*(t+dt) + phase)*hfact + dp = dp + amp + return [x,dx,p,dp] + diff --git a/src/Mod/Ship/simRun/Sim/initialization.py b/src/Mod/Ship/simRun/Sim/initialization.py index e89192c14..f7c58ad90 100644 --- a/src/Mod/Ship/simRun/Sim/initialization.py +++ b/src/Mod/Ship/simRun/Sim/initialization.py @@ -1,119 +1,327 @@ #*************************************************************************** -#* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * -#* * +#* * +#* 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 * +#* 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 * -#* * +#* USA * +#* * #*************************************************************************** # numpy import numpy as np +import FreeCAD grav=9.81 class simInitialization: - def __init__(self, FSmesh, waves, context=None, queue=None): - """ 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, - must be None. - @param queue OpenCL command queue. Only for compatibility, - must be None. - """ - self.context = context - 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 __init__(self, h, FSMesh, SeaMesh, waves, context=None, queue=None): + """ Constructor. + @param h Water height. + @param FSMesh Initial free surface mesh. + @param waves Considered simulation waves (A,T,phi,heading). + @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 + self.loadData(h, FSMesh, SeaMesh, 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. - @param FSmesh Initial free surface mesh. - @param waves Considered simulation waves (A,T,phi,heading). - """ - nx = len(FSmesh) - ny = len(FSmesh[0]) - nW = len(waves) - # Mesh data - p = np.ndarray((nx,ny, 3), dtype=np.float32) - n = np.ndarray((nx,ny, 3), 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 - normal = FSmesh[i][j].normal - area = FSmesh[i][j].area - p[i,j,0] = pos.x - p[i,j,1] = pos.y - p[i,j,2] = pos.z - n[i,j,0] = normal.x - n[i,j,1] = normal.y - n[i,j,2] = normal.z - a[i,j] = area - 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): - w[i,0] = waves[i][0] - w[i,1] = waves[i][1] - 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 loadData(self, h, FSMesh, SeaMesh, waves): + """ Convert data to numpy format. + @param FSMesh Initial free surface mesh. + @param waves Considered simulation waves (A,T,phi,heading). + """ + # Data will classified in four groups: + # Free surface: + # Is a key part of the simulation, so is + # separated from the rest of water involved + # elements. + # Sea: + # BEM method required a closed domain, so + # water floor and sides must be append, but + # are not a key objective of the simulation. + # Body: + # Is the main objective of the simulation. + # Waves: + # Data that is append as boundary condition. + # BEM: + # Used to solve the BEM problem and evolution. + + # -------------------------------------------- + # Free surface data + # N, Nx, Ny = Number of points in each + # direction + # pos = Positions + # vel = Velocities + # n = Normals + # area = Areas + # -------------------------------------------- + nx = len(FSMesh) + ny = len(FSMesh[0]) + p = np.ndarray((nx,ny, 3), dtype=np.float32) + V = np.zeros((nx,ny, 3), dtype=np.float32) + n = np.ndarray((nx,ny, 3), dtype=np.float32) + a = np.ndarray((nx,ny), dtype=np.float32) + x1 = np.zeros((nx,ny), dtype=np.float32) + x2 = np.zeros((nx,ny), dtype=np.float32) + x3 = np.zeros((nx,ny), dtype=np.float32) + dx1 = np.zeros((nx,ny), dtype=np.float32) + dx2 = np.zeros((nx,ny), dtype=np.float32) + dx3 = np.zeros((nx,ny), dtype=np.float32) + for i in range(0, nx): + for j in range(0, ny): + pos = FSMesh[i][j].pos + normal = FSMesh[i][j].normal + area = FSMesh[i][j].area + p[i,j,0] = pos.x + p[i,j,1] = pos.y + p[i,j,2] = pos.z + n[i,j,0] = normal.x + n[i,j,1] = normal.y + n[i,j,2] = normal.z + a[i,j] = area + self.fs = {'h': h, 'N':nx*ny, 'Nx':nx, 'Ny':ny, \ + 'pos':p, 'vel':V, 'normal':n, 'area':a, \ + 'x1':x1, 'x2':x2, 'x3':x3,\ + 'dx1':dx1, 'dx2':dx2, 'dx3':dx3} + # -------------------------------------------- + # Sea data (dictionary with components + # ['front','back','left','right','bottom']) + # N, Nx, Ny = Number of points in each + # direction + # pos = Positions + # vel = Velocities + # n = Normals + # area = Areas + # -------------------------------------------- + self.sea = {'ids':['front','back','left','right','bottom']} + N = 0 + for index in self.sea['ids']: + mesh = SeaMesh[index] + nx = len(mesh) + ny = len(mesh[0]) + p = np.ndarray((nx,ny, 3), dtype=np.float32) + V = np.zeros((nx,ny, 3), dtype=np.float32) + n = np.ndarray((nx,ny, 3), dtype=np.float32) + a = np.ndarray((nx,ny), dtype=np.float32) + for i in range(0, nx): + for j in range(0, ny): + pos = mesh[i][j].pos + normal = mesh[i][j].normal + area = mesh[i][j].area + p[i,j,0] = pos.x + p[i,j,1] = pos.y + p[i,j,2] = pos.z + n[i,j,0] = normal.x + n[i,j,1] = normal.y + n[i,j,2] = normal.z + a[i,j] = area + d = {'N':nx*ny, 'Nx':nx, 'Ny':ny, 'pos':p, 'vel':V, 'normal':n, 'area':a} + self.sea[index] = d + N = N + nx*ny + self.sea['N'] = N + self.sea['h'] = h + # -------------------------------------------- + # Body data + # N, Nx, Ny = Number of points in each + # direction + # pos = Positions + # vel = Velocities + # n = Normals + # area = Areas + # -------------------------------------------- + self.b = {'N':0, 'pos':None, 'vel':None, 'normal':None, 'area':None} + # -------------------------------------------- + # Waves data + # N = Number of waves + # data = Waves data + # -------------------------------------------- + nW = len(waves) + w = np.ndarray((nW, 4), dtype=np.float32) + for i in range(0,nW): + w[i,0] = waves[i][0] + w[i,1] = waves[i][1] + w[i,2] = waves[i][2] + w[i,3] = waves[i][3] + self.waves = {'h':h, 'N':nW, 'data':w} + # -------------------------------------------- + # BEM data + # N = nFS + nSea + nB + # A,B,dB = Linear system matrix and vectors + # p1,... = Velocity potentials (phi) for + # each RK4 step. In reallity are + # the independent term of the + # BEM linear system, so is the + # potential for the free surface, + # and the gradient projected over + # the normal along all other terms. + # dp1,... = Acceleration potentials + # (dphi/dt) for each RK4 step. + # In reallity are the + # independent term of the BEM + # linear system, so is the + # potential for the free surface, + # and the gradient projected over + # the normal along all other terms. + # Ap,Adp = BEM solution vectors, that + # contains the potential gradients + # on free surface, and the potential + # along all toher surfaces. + # -------------------------------------------- + nFS = self.fs['N'] + nSea = self.sea['N'] + nB = self.b['N'] + N = nFS + nSea + nB + A = np.zeros((N, N), dtype=np.float32) + B = np.zeros((N), dtype=np.float32) + dB = np.zeros((N), dtype=np.float32) + p1 = np.zeros((N), dtype=np.float32) + p2 = np.zeros((N), dtype=np.float32) + p3 = np.zeros((N), dtype=np.float32) + p4 = np.zeros((N), dtype=np.float32) + Ap = np.zeros((N), dtype=np.float32) + dp1 = np.zeros((N), dtype=np.float32) + dp2 = np.zeros((N), dtype=np.float32) + dp3 = np.zeros((N), dtype=np.float32) + dp4 = np.zeros((N), dtype=np.float32) + Adp = np.zeros((N), dtype=np.float32) + self.bem = {'N':N, 'A':A, 'B':B, 'dB':dB, \ + 'p1':p1, 'p2':p2, 'p3':p3, 'p4':p4, 'Ap':Ap, \ + 'dp1':dp1, 'dp2':dp2, 'dp3':dp3, 'dp4':dp4, 'Adp':Adp } + + def execute(self): + """ Compute initial conditions. """ + # -------------------------------------------- + # Free surface beach nodes. + # Beach nodes are the nodes of the free + # surface where the waves are imposed. All + # the other nodes are computed allowing non + # linear waves due to the ship interaction. + # The beach will have enough dimension to + # control at least half wave length + # -------------------------------------------- + # Get maximum wave length + wl = 0.0 + for w in self.waves['data']: + T = w[1] + wl = max(wl, 0.5 * grav / np.pi * T*T) + # Get nodes dimensions + nx = self.fs['Nx'] + ny = self.fs['Ny'] + lx = self.fs['pos'][nx-1,0][0] - self.fs['pos'][0,0][0] + ly = self.fs['pos'][0,ny-1][1] - self.fs['pos'][0,0][1] + dx = lx / nx + dy = ly / ny + # Get number of nodes involved + wnx = max(1, int(round(0.5*wl / dx))) + wny = max(1, int(round(0.5*wl / dy))) + wnx = min(wnx, nx) + wny = min(wny, ny) + self.fs['Beachx'] = wnx + self.fs['Beachy'] = wny + # -------------------------------------------- + # Free surface initial condition. + # Since RK4 scheme starts on the end of + # previous step, we only write on last + # stage value (p4 and dp4) + # -------------------------------------------- + nx = self.fs['Nx'] + ny = self.fs['Ny'] + h = self.fs['h'] + for i in range(0,nx): + for j in range(0,ny): + # Since initial values of the potencial, and this acceleration, + # depends on z, we need to compute first the positions. + self.fs['pos'][i,j][2] = 0. + for w in self.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 + pos = self.fs['pos'][i,j] + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + # hfact = np.sinh(k*(pos[2]+h)) / np.cosh(k*h) + hfact = 1.0 + amp = A*np.sin(k*l + phase)*hfact + self.fs['pos'][i,j][2] = self.fs['pos'][i,j][2] + amp + amp = - A*frec*np.cos(k*l + phase)*hfact + self.fs['vel'][i,j][2] = self.fs['vel'][i,j][2] + amp + # And now we can compute potentials. + for w in self.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 + pos = self.fs['pos'][i,j] + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + hfact = np.cosh(k*(pos[2]+h)) / np.cosh(k*h) + amp = - grav/frec*A*np.cos(k*l + phase)*hfact + self.bem['p4'][i*ny+j] = self.bem['p4'][i*ny+j] + amp + amp = - grav*A*np.sin(k*l + phase)*hfact + self.bem['dp4'][i*ny+j] = self.bem['dp4'][i*ny+j] + amp + # -------------------------------------------- + # Sea initial condition on sides. + # 1. Since RK4 scheme starts on the end of + # previous step, we only write on last + # stage value (p4 and dp4) + # 2. In the sea boundaries we are + # interested on the gradient of the + # potentials projected over the normal, + # so we really store this value. + # 3. In the floor this value is ever null. + # -------------------------------------------- + ids = ['front','back','left','right','bottom'] + i0 = self.fs['N'] + for index in ids: + sea = self.sea[index] + nx = sea['Nx'] + ny = sea['Ny'] + for i in range(0,nx): + for j in range(0,ny): + for w in self.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 + pos = sea['pos'][i,j] + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + normal = sea['normal'][i,j] + hfact = np.cosh(k*(pos[2]+h)) / np.cosh(k*h) + factor = np.dot(normal,np.array([np.cos(heading), np.sin(heading), 0.])) + amp = frec*A*np.sin(k*l + phase)*hfact + self.bem['p4'][i0 + i*ny+j] = self.bem['p4'][i*ny+j] + factor*amp + amp = - grav*A*k*np.cos(k*l + phase)*hfact + self.bem['dp4'][i0 + i*ny+j] = self.bem['dp4'][i*ny+j] + factor*amp + i0 = i0 + sea['N'] - def execute(self): - """ Compute initial conditions. """ - nx = self.fs['Nx'] - 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] - 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 - pos = self.fs['pos'][i,j] - 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 = - 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 index 4eab537bc..43ea6ed51 100644 --- a/src/Mod/Ship/simRun/Sim/matrixGen.py +++ b/src/Mod/Ship/simRun/Sim/matrixGen.py @@ -1,24 +1,24 @@ #*************************************************************************** -#* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * -#* * +#* * +#* 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 * +#* 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 * -#* * +#* USA * +#* * #*************************************************************************** # numpy @@ -27,53 +27,197 @@ 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 __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 execute(self, x, p, dp, fs, sea, bem, body): + """ Compute system matrix. + @param x Free surface z coordinates. + @param fs Free surface instance. + @param sea Sea boundary instance. + @param bem Boundary Element Method instance. + @param body Body instance. + """ + nFS = fs['N'] + nSea = sea['N'] + nB = body['N'] + n = nFS + nSea + nB + A = bem['A'] + B = bem['B'] + dB = bem['dB'] + # Free surface sources rows + nx = fs['Nx'] + ny = fs['Ny'] + for i in range(0,nx): + for j in range(0,ny): + pos = np.copy(fs['pos'][i,j]) + pos[2] = x[i,j] + # Compute G terms + fsG = self.fsG(x, pos, fs) + seaG = self.seaG(pos, sea) + # Compute H terms + fsH = self.fsH(i*ny+j, x, pos, fs) + seaH = self.seaH(i*ny+j, pos, fs, sea) + # Append terms to linear system matrix + A[i*ny+j,0:nFS] = fsG + A[i*ny+j,nFS:n] = seaH + # Set independent terms + B[i*ny+j] = np.dot(fsH, p[0:nFS]) + np.dot(seaG, p[nFS:nFS+nSea]) + dB[i*ny+j] = np.dot(fsH, dp[0:nFS]) + np.dot(seaG, dp[nFS:nFS+nSea]) + # Append body effect + # ... + # Sea sources rows + ids = ['front','back','left','right','bottom'] + count = 0 + for index in ids: + s = sea[index] + nx = s['Nx'] + ny = s['Ny'] + for i in range(0,nx): + for j in range(0,ny): + pos = np.copy(s['pos'][i,j]) + # Compute G terms + fsG = self.fsG(x, pos, fs) + seaG = self.seaG(pos, sea) + # Compute H terms + fsH = self.fsH(nFS+count, x, pos, fs) + seaH = self.seaH(nFS+count, pos, fs, sea) + # Append terms to linear system matrix + A[nFS+count, 0:nFS] = fsG + A[nFS+count, nFS:n] = seaH + # Set independent terms + B[nFS+count] = np.dot(fsH, p[0:nFS]) + np.dot(seaG, p[nFS:nFS+nSea]) + dB[nFS+count] = np.dot(fsH, dp[0:nFS]) + np.dot(seaG, dp[nFS:nFS+nSea]) + # Append body effect + # ... + count = count + 1 + # Solid sources rows + # ... + + def fsG(self, x, pos, fs): + r""" Compute free surface terms potential effect over desired position. Desingularized + sources must taken into account. + \$ G_{ij} = \sum_{j=0}^{n_{FS}-1} \log(\mathbf{r}_{ij}) \$ + @param x Free surface z coordinates. + @param pos Point to evaluate. + @param fs Free surface instance. + @return Free surface effect row. + """ + nx = fs['Nx'] + ny = 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(fs['pos'][i,j]) + source[2] = x[i,j] + area = fs['area'][i,j] + normal = fs['normal'][i,j] + source = source + np.sqrt(area)*normal + # Get union vector between points + r = pos-source + row[i*ny+j] = area * 0.5*np.log(np.dot(r,r)) + return row + + def fsH(self, index, x, pos, fs): + r""" Compute free surface terms potential gradient effect over desired position. Desingularized + sources must taken into account. + \$ H_{ij} = \sum_{j=0}^{n_{FS}-1} \frac{\mathbf{r}_{ij}}{\vert \mathbf{r}_{ij} \vert^2} \$ + When the point effect over himself is considered, -1/2 must be append. + @param index Potential point index. + @param x Free surface z coordinates. + @param pos Point to evaluate. + @param fs Free surface instance. + @return Free surface effect row. + """ + nx = fs['Nx'] + ny = 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(fs['pos'][i,j]) + source[2] = x[i,j] + area = fs['area'][i,j] + normal = fs['normal'][i,j] + source = source + np.sqrt(area)*normal + # Get union vector between points + r = pos-source + row[i*ny+j] = area * np.dot(r,normal) / np.dot(r,r) + # If effect over himslef is considered, apply the correction + if(index == i*ny+j): + row[i*ny+j] = row[i*ny+j] - 0.5 + return row + + def seaG(self, pos, sea): + r""" Compute sea boundary terms potential effect over desired position. Desingularized + sources must taken into account. + \$ G_{ij} = \sum_{j=0}^{n_{FS}-1} \log(\mathbf{r}_{ij}) \$ + @param pos Point to evaluate. + @param sea Sea boundaries instance. + @return Sea boundaries effect row. + """ + ids = ['front','back','left','right','bottom'] + count = 0 + row = np.ndarray(sea['N'], dtype=np.float32) + for index in ids: + s = sea[index] + nx = s['Nx'] + ny = s['Ny'] + for i in range(0,nx): + for j in range(0,ny): + # Get source position (desingularized) + source = np.copy(s['pos'][i,j]) + area = s['area'][i,j] + normal = s['normal'][i,j] + source = source + np.sqrt(area)*normal + # Get distance between points + r = pos-source + row[count] = area * 0.5*np.log(np.dot(r,r)) + count = count + 1 + return row + + def seaH(self, index, pos, fs, sea): + r""" Compute sea boundary terms potential gradient effect over desired position. Desingularized + sources must taken into account. + \$ H_{ij} = \sum_{j=0}^{n_{FS}-1} \frac{\mathbf{r}_{ij}}{\vert \mathbf{r}_{ij} \vert^2} \$ + When the point effect over himself is considered, -1/2 must be append. + @param index Potential point index. + @param pos Point to evaluate. + @param fs Free surface instance. + @param sea Sea boundaries instance. + @return Sea boundaries effect row. + """ + nF = fs['N'] + ids = ['front','back','left','right','bottom'] + count = 0 + row = np.ndarray(sea['N'], dtype=np.float32) + for index in ids: + s = sea[index] + nx = s['Nx'] + ny = s['Ny'] + for i in range(0,nx): + for j in range(0,ny): + # Get source position (desingularized) + source = np.copy(s['pos'][i,j]) + area = s['area'][i,j] + normal = s['normal'][i,j] + source = source + np.sqrt(area)*normal + # Get distance between points + r = pos-source + row[count] = area * np.dot(r,normal) / np.dot(r,r) + # If effect over himslef is considered, apply the correction + if(index == count+nF): + row[count] = row[count] - 0.5 + count = count + 1 + return row - 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 06773fc4e..713d196d0 100644 --- a/src/Mod/Ship/simRun/Simulation.py +++ b/src/Mod/Ship/simRun/Simulation.py @@ -51,14 +51,17 @@ class Singleton(type): class FreeCADShipSimulation(threading.Thread): __metaclass__ = Singleton - def __init__ (self, device, endTime, output, simInstance, FSmesh, waves): + def __init__ (self, device, endTime, output, simInstance, FSMesh, FSData, waves, Sea_Nx, Sea_Ny): """ 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 FSMesh Free surface mesh faces. + @param FSData Free surface data (Length, Breath, Nx, Ny). @param waves Waves parameters (A,T,phi,heading) + @param Sea_Nx Times that the free surface is virtually repeated in the x direction + @param Sea_Ny Times that the free surface is virtually repeated in the y direction """ threading.Thread.__init__(self) # Setup as stopped @@ -75,9 +78,11 @@ class FreeCADShipSimulation(threading.Thread): self.endTime = endTime self.output = output self.sim = simInstance - self.FSmesh = FSmesh + self.FSMesh = FSMesh + self.FSData = FSData self.waves = waves - + self.Sea = (Sea_Nx, Sea_Ny) + def run(self): """ Runs the simulation. """ @@ -90,36 +95,116 @@ class FreeCADShipSimulation(threading.Thread): msg = QtGui.QApplication.translate("ship_console","Initializating", None,QtGui.QApplication.UnicodeUTF8) FreeCAD.Console.PrintMessage("\t[Sim]: " + msg + "...\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 + if self.device == None: # Can't use OpenCL + init = simInitialization(self.FSMesh,self.FSData,self.waves,self.Sea,self.context,self.queue) + matGen = simMatrixGen(self.context,self.queue) + solver = simBEMSolver(self.context,self.queue) + evol = simEvolution(self.context,self.queue) + else: + init = simInitialization_cl(self.FSMesh,self.FSData,self.waves,self.Sea,self.context,self.queue) + matGen = simMatrixGen_cl(self.context,self.queue) + solver = simBEMSolver_cl(self.context,self.queue) + evol = simEvolution_cl(self.context,self.queue) + FS = init.fs + sea = init.sea + body = init.b + waves = init.waves + BEM = init.bem + dt = init.dt self.t = 0.0 self.FS = FS - nx = FS['Nx'] - ny = FS['Ny'] + nx = FS['Nx'] + ny = FS['Ny'] msg = QtGui.QApplication.translate("ship_console","Iterating", None,QtGui.QApplication.UnicodeUTF8) FreeCAD.Console.PrintMessage("\t[Sim]: " + msg + "...\n") while self.active and self.t < self.endTime: - msg = QtGui.QApplication.translate("ship_console","Generating linear system matrix", - None,QtGui.QApplication.UnicodeUTF8) - FreeCAD.Console.PrintMessage("\t\t[Sim]: " + msg + "...\n") - matGen.execute(FS, A) - msg = QtGui.QApplication.translate("ship_console","Solving linear systems", - None,QtGui.QApplication.UnicodeUTF8) - FreeCAD.Console.PrintMessage("\t\t[Sim]: " + msg + "...\n") - solver.execute(FS, A) - msg = QtGui.QApplication.translate("ship_console","Time integrating", - None,QtGui.QApplication.UnicodeUTF8) - FreeCAD.Console.PrintMessage("\t\t[Sim]: " + msg + "...\n") - fsEvol.execute(FS, waves, dt, self.t) + # Simple Euler method + FreeCAD.Console.PrintMessage("\t\t\t[Sim]: Generating matrix...\n") + matGen.execute(FS, waves, sea, BEM, body, self.t) + FreeCAD.Console.PrintMessage("\t\t\t[Sim]: Solving linear system matrix...\n") + solver.execute(BEM) + FreeCAD.Console.PrintMessage("\t\t\t[Sim]: Integrating...\n") + # evol.execute(FS, BEM, waves, self.t, dt) + + + # -------------------------------------------------------- + # Debugging + # -------------------------------------------------------- + evol.BC(FS, BEM, waves, self.t) + f = open("%.4f.dat" % (self.t), 'w') + for i in range(0,FS['Nx']): + for j in range(0, FS['Ny']): + # Compute analitical solution + z = 0.0 + vz = 0.0 + p = 0.0 + vp = 0.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 + pos = FS['pos'][i,j] + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + amp = A*np.sin(k*l - frec*self.t + phase) + z = z + amp + amp = - A*frec*np.cos(k*l - frec*self.t + phase) + vz = vz + amp + 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 + pos = FS['pos'][i,j] + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + amp = - A*frec/k*np.cos(k*l - frec*self.t + phase)*np.exp(k*z) + p = p + amp + amp = - A*9.81*np.sin(k*l - frec*self.t + phase)*np.exp(k*z) + vp = vp + amp + + """ + z = 0. + vz = 0. + p = 0. + vp = 0. + # We can do phi = Green's function + dx = FS['pos'][i,j][0] + dy = FS['pos'][i,j][1] + dz = 15.0 # An arbitrary value > 0 + p = 1. / (4. * np.pi * np.sqrt(dx*dx + dy*dy + dz*dz)) + vz = - dz / (4. * np.pi * (dx*dx + dy*dy + dz*dz)**(1.5)) + """ + + # write coordinates + f.write("%g %g " % (FS['pos'][i,j,0],FS['pos'][i,j,1])) + # write computed wave and velocity + f.write("%g %g " % (FS['pos'][i,j,2],FS['vel'][i,j,2])) + # write computed potential and time variation rate + # f.write("%g %g " % (BEM['p'][i*FS['Ny']+j],BEM['dpdt'][i*FS['Ny']+j])) + f.write("%g %g " % (BEM['p'][i*FS['Ny']+j],0.)) + # write analytic wave and velocity + f.write("%g %g " % (z,vz)) + # write analytic potential and time variation rate + # f.write("%g %g\n" % (p,vp)) + f.write("%g %g\n" % (p,0.)) + f.write("\n") + f.close() + evol.Integrate(FS, BEM, waves, self.t, dt) + # -------------------------------------------------------- + # Debugging + # -------------------------------------------------------- + + self.t = self.t + dt FreeCAD.Console.PrintMessage('\t[Sim]: 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 628347458..bf9996484 100644 --- a/src/Mod/Ship/simRun/TaskPanel.py +++ b/src/Mod/Ship/simRun/TaskPanel.py @@ -61,18 +61,22 @@ class TaskPanel: device = d count = count + 1 # Get free surfaces data - FSMesh = SimInstance.FSMesh(self.sim) - wData = self.sim.Waves - wDir = self.sim.Waves_Dir - waves = [] + FSMesh = SimInstance.FSMesh(self.sim) + FSData = (self.sim.L,self.sim.B,self.sim.FS_Nx,self.sim.FS_Ny) + wData = self.sim.Waves + wDir = self.sim.Waves_Dir + waves = [] for i in range(0,len(wData)): waves.append([wData[i].x, wData[i].y, wData[i].z, wDir[i]]) + SeaNx = self.sim.Sea_Nx + SeaNy = self.sim.Sea_Ny msg = QtGui.QApplication.translate("ship_console","Launching simulation", None,QtGui.QApplication.UnicodeUTF8) App.Console.PrintMessage(msg + "...\n") # Build simulation thread - simulator = Sim(device, endTime, output, self.sim, FSMesh, waves) - simulator.start() + simulator = Sim(device, endTime, output, self.sim, FSMesh, FSData, waves, SeaNx, SeaNy) + simulator.start() # Activate me for final release + # simulator.run() # Activate me for development (i will show python fails) msg = QtGui.QApplication.translate("ship_console","Done", None,QtGui.QApplication.UnicodeUTF8) App.Console.PrintMessage(msg + "!\n") diff --git a/src/Mod/Ship/simRun/clSim/BEMsolver.py b/src/Mod/Ship/simRun/clSim/BEMsolver.py new file mode 100644 index 000000000..42e54a89a --- /dev/null +++ b/src/Mod/Ship/simRun/clSim/BEMsolver.py @@ -0,0 +1,61 @@ +#*************************************************************************** +#* * +#* 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 +from bem_jacobi_cl import jacobi +from bem_minres_cl import minres +from bem_lsqr_cl import lsqr +import FreeCAD + +grav=9.81 + +class simBEMSolver_cl: + def __init__(self, context=None, queue=None): + """ Constructor. + @param context OpenCL context where apply. + @param queue OpenCL command queue. + """ + self.context = context + self.queue = queue + self.solver = lsqr(context, queue) + + def execute(self, bem): + """ Compute potential unknow data (gradients for free surface, and + potentials for the other ones). + @param bem Boundary Element Method instance. + """ + """ + [bem['gradp'], r, iters] = self.solver.solve(bem['A'], bem['B'], bem['gradp']) + if(iters >= 300): + FreeCAD.Console.PrintError("\t\t[Sim]: Solving velocity potentials.\n") + FreeCAD.Console.PrintError("\t\t\tSolutions seems don't convergs after 300 iterations (%g residual)\n" % (r)) + FreeCAD.Console.PrintMessage((r,iters)) + FreeCAD.Console.PrintMessage("\n") + """ + import scipy.linalg as la + [bem['gradp'], residues, rank, s] = la.lstsq(bem['A'], bem['B']) + if(rank < bem['N']): + FreeCAD.Console.PrintError("\t\t[Sim]: Solving velocity potentials.\n") + FreeCAD.Console.PrintError("\t\t\tEffective rank of linear system matrix is {0} (N = {1})\n".format(rank, bem['N'])) + diff --git a/src/Mod/Ship/simRun/clSim/__init__.py b/src/Mod/Ship/simRun/clSim/__init__.py index 2fcb8e495..6a185fde4 100644 --- a/src/Mod/Ship/simRun/clSim/__init__.py +++ b/src/Mod/Ship/simRun/clSim/__init__.py @@ -21,4 +21,7 @@ #* * #*************************************************************************** -import initialization, Utils \ No newline at end of file +from initialization import * +from matrixGen import * +from BEMsolver import * +from evolution import * diff --git a/src/Mod/Ship/simRun/clSim/bem_jacobi_cl.py b/src/Mod/Ship/simRun/clSim/bem_jacobi_cl.py new file mode 100644 index 000000000..368574f22 --- /dev/null +++ b/src/Mod/Ship/simRun/clSim/bem_jacobi_cl.py @@ -0,0 +1,155 @@ +#*************************************************************************** +#* * +#* 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 + +# pyOpenCL +import pyopencl as cl +from pyopencl.reduction import ReductionKernel +import pyopencl.array as cl_array +import clUtils + +import FreeCAD +grav=9.81 + +class jacobi: + def __init__(self, context, queue): + """ Constructor. + @param context OpenCL context where apply. + @param queue OpenCL command queue. + """ + self.context = context + self.queue = queue + self.program = clUtils.loadProgram(context, clUtils.path() + "/jacobi.cl") + # Create OpenCL objects as null objects, that we will generate + # at the first iteration + self.A = None + self.B = None + self.X0 = None + self.X = None + self.x = None + # Create dot operator + self.dot = ReductionKernel(context, np.float32, neutral="0", + reduce_expr="a+b", map_expr="x[i]*y[i]", + arguments="__global float *x, __global float *y") + + def solve(self, A, B, x0=None, tol=10e-6, iters=300, w=1.0): + r""" Solve linear system of equations by a Jacobi + iterative method. + @param A Linear system matrix. + @param B Linear system independent term. + @param x0 Initial aproximation of the solution. + @param tol Relative error tolerance: \n + \$ \vert\vert B - A \, x \vert \vert_\infty / + \vert\vert B \vert \vert_\infty \$ + @param iters Maximum number of iterations. + @param w Relaxation factor + """ + # Create/set OpenCL buffers + w = np.float32(w) + self.setBuffers(A,B,x0) + # Get dimensions for OpenCL execution + n = np.uint32(len(B)) + gSize = (clUtils.globalSize(n),) + # Get a norm to can compare later for valid result + B_cl = cl_array.to_device(self.context,self.queue,B) + bnorm2 = self.dot(B_cl,B_cl).get() + w = w / bnorm2 + FreeCAD.Console.PrintMessage(bnorm2) + FreeCAD.Console.PrintMessage("\n") + rnorm2 = 0. + # Iterate while the result converges or maximum number + # of iterations is reached. + for i in range(0,iters): + kernelargs = (self.A, + self.B, + self.X0, + self.X, + n) + # Test if the final result has been reached + self.program.r(self.queue, gSize, None, *(kernelargs)) + cl.enqueue_read_buffer(self.queue, self.X, self.x).wait() + x_cl = cl_array.to_device(self.context,self.queue,self.x) + rnorm2 = self.dot(x_cl,x_cl).get() + FreeCAD.Console.PrintMessage("\t") + FreeCAD.Console.PrintMessage(rnorm2) + FreeCAD.Console.PrintMessage("\n") + if np.sqrt(rnorm2 / bnorm2) <= tol: + break + # Iterate + kernelargs = (self.A, + self.B, + self.X0, + self.X, + w, + n) + self.program.jacobi(self.queue, gSize, None, *(kernelargs)) + kernelargs = (self.A, + self.B, + self.X, + self.X0, + w, + n) + self.program.jacobi(self.queue, gSize, None, *(kernelargs)) + # Return result computed + cl.enqueue_read_buffer(self.queue, self.X0, self.x).wait() + return (np.copy(self.x), np.sqrt(rnorm2 / bnorm2), i) + + def setBuffers(self, A,B,x0): + """ Create/set OpenCL required buffers. + @param A Linear system matrix. + @param B Independent linear term. + @param x0 Initial solution estimator. + """ + # Get dimensions + shape = np.shape(A) + if len(shape) != 2: + raise ValueError, 'Matrix A must be 2 dimensional array' + if shape[0] != shape[1]: + raise ValueError, 'Square linear system matrix expected' + if len(B) != shape[0]: + raise ValueError, 'Matrix and independet term dimensions does not match' + n = len(B) + # Set x0 if not provided + if x0 != None: + if len(x0) != n: + raise ValueError, 'Initial solution estimator length does not match with linear system dimensions' + if x0 == None: + x0 = B + # Create OpenCL objects if not already generated + if not self.A: + mf = cl.mem_flags + self.A = cl.Buffer( self.context, mf.READ_ONLY, size = n*n * np.dtype('float32').itemsize ) + self.B = cl.Buffer( self.context, mf.READ_ONLY, size = n * np.dtype('float32').itemsize ) + self.X0 = cl.Buffer( self.context, mf.READ_WRITE, size = n * np.dtype('float32').itemsize ) + self.X = cl.Buffer( self.context, mf.READ_WRITE, size = n * np.dtype('float32').itemsize ) + self.x = np.zeros((n), dtype=np.float32) + # Transfer data to buffers + events = [] + events.append(cl.enqueue_write_buffer(self.queue, self.A, A.reshape((n*n)) )) + events.append(cl.enqueue_write_buffer(self.queue, self.B, B)) + events.append(cl.enqueue_write_buffer(self.queue, self.X0, x0)) + for e in events: + e.wait() + diff --git a/src/Mod/Ship/simRun/clSim/bem_lsqr_cl.py b/src/Mod/Ship/simRun/clSim/bem_lsqr_cl.py new file mode 100644 index 000000000..39811a390 --- /dev/null +++ b/src/Mod/Ship/simRun/clSim/bem_lsqr_cl.py @@ -0,0 +1,229 @@ +#*************************************************************************** +#* * +#* 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 + +# pyOpenCL +import pyopencl as cl +from pyopencl.reduction import ReductionKernel +from pyopencl.elementwise import ElementwiseKernel +import pyopencl.array as cl_array +import clUtils + +import FreeCAD +grav=9.81 + +class lsqr: + def __init__(self, context, queue): + """ Constructor. + @param context OpenCL context where apply. + @param queue OpenCL command queue. + """ + self.context = context + self.queue = queue + self.program = clUtils.loadProgram(context, clUtils.path() + "/lsqr.cl") + # Create OpenCL objects as null objects, that we will generate + # at the first iteration + self.A = None + self.B = None + self.X0 = None + self.X = None + self.R = None + # Create dot operator + self.dot = ReductionKernel(context, np.float32, neutral="0", + reduce_expr="a+b", map_expr="x[i]*y[i]", + arguments="__global float *x, __global float *y") + self.dot_c_vec = ElementwiseKernel(context, + "float c, float *v", + "v[i] *= c") + self.copy_vec = ElementwiseKernel(context, + "float* out, float *in", + "out[i] = in[i]") + self.linear_comb = ElementwiseKernel(context, + "float* z," + "float a, float *x, " + "float b, float *y", + "z[i] = a*x[i] + b*y[i]") + self.prod = ElementwiseKernel(context, + "float* z," + "float *x, float *y", + "z[i] = x[i]*y[i]") + + def solve(self, A, B, x0=None, tol=10e-6, iters=300): + r""" Solve linear system of equations by a Jacobi + iterative method. + @param A Linear system matrix. + @param B Linear system independent term. + @param x0 Initial aproximation of the solution. + @param tol Relative error tolerance: \n + \$ \vert\vert B - A \, x \vert \vert_\infty / + \vert\vert B \vert \vert_\infty \$ + @param iters Maximum number of iterations. + """ + # Create/set OpenCL buffers + self.setBuffers(A,B,x0) + # Get dimensions for OpenCL execution + n = np.uint32(len(B)) + gSize = (clUtils.globalSize(n),) + # Preconditionate matrix + self.precondition(n) + # Get a norm to can compare later for valid result + bnorm = np.sqrt(self.dot(self.b,self.b).get()) + FreeCAD.Console.PrintMessage(bnorm) + FreeCAD.Console.PrintMessage("\n") + # Initialize the problem + beta = bnorm + self.dot_c_vec(1.0/beta, self.u) + kernelargs = (self.A,self.u.data,self.v.data,n) + self.program.dot_matT_vec(self.queue, gSize, None, *(kernelargs)) + alpha = np.sqrt(self.dot(self.v,self.v).get()) + self.dot_c_vec(1.0/alpha, self.v) + self.copy_vec(self.w, self.v) + rhobar = alpha + phibar = beta + # Iterate while the result converges or maximum number + # of iterations is reached. + for i in range(0,iters): + # Compute residues + kernelargs = (self.A, + self.b.data, + self.x.data, + self.r.data, + n) + self.program.r(self.queue, gSize, None, *(kernelargs)) + rnorm = np.sqrt(self.dot(self.r,self.r).get()) + FreeCAD.Console.PrintMessage("\t") + FreeCAD.Console.PrintMessage(rnorm) + FreeCAD.Console.PrintMessage("\n") + # Test if the final result has been reached + if rnorm / bnorm <= tol: + break + # Compute next alpha, beta, u, v + kernelargs = (self.A,self.u.data,self.v.data,self.u.data,alpha,n) + self.program.u(self.queue, gSize, None, *(kernelargs)) + beta = np.sqrt(self.dot(self.u,self.u).get()) + FreeCAD.Console.PrintMessage("\t beta=") + FreeCAD.Console.PrintMessage(beta) + FreeCAD.Console.PrintMessage("\n") + self.dot_c_vec(1.0/beta, self.u) + kernelargs = (self.A,self.u.data,self.v.data,self.v.data,beta,n) + self.program.v(self.queue, gSize, None, *(kernelargs)) + alpha = np.sqrt(self.dot(self.v,self.v).get()) + FreeCAD.Console.PrintMessage("\t alpha=") + FreeCAD.Console.PrintMessage(alpha) + FreeCAD.Console.PrintMessage("\n") + self.dot_c_vec(1.0/alpha, self.v) + # Apply the orthogonal transformation + rho = np.sqrt(rhobar*rhobar + beta*beta) + c = rhobar/rho + s = beta*rho + theta = s*alpha + rhobar = -c*alpha + phi = c*phibar + phibar = s*phibar + # Update x and w + self.linear_comb(self.x, 1, self.x, phi/rho, self.w) + self.linear_comb(self.w, 1, self.v, theta/rho, self.w) + # Correct returned result due to the precoditioning + self.prod(self.x, self.xf, self.x) + # Return result computed + x = np.zeros((n), dtype=np.float32) + cl.enqueue_read_buffer(self.queue, self.x.data, x).wait() + return (x, rnorm / bnorm, i) + + def setBuffers(self, A,B,x0): + """ Create/set OpenCL required buffers. + @param A Linear system matrix. + @param B Independent linear term. + @param x0 Initial solution estimator. + """ + # Get dimensions + shape = np.shape(A) + if len(shape) != 2: + raise ValueError, 'Matrix A must be 2 dimensional array' + if shape[0] != shape[1]: + raise ValueError, 'Square linear system matrix expected' + if len(B) != shape[0]: + raise ValueError, 'Matrix and independet term dimensions does not match' + n = len(B) + # Set x0 if not provided + if x0 != None: + if len(x0) != n: + raise ValueError, 'Initial solution estimator length does not match with linear system dimensions' + if x0 == None: + x0 = B + # Create OpenCL objects if not already generated + if not self.A: + mf = cl.mem_flags + self.A = cl.Buffer( self.context, mf.READ_WRITE, size = n*n * np.dtype('float32').itemsize ) + self.b = cl_array.zeros(self.context,self.queue, (n), np.float32) + self.x = cl_array.zeros(self.context,self.queue, (n), np.float32) + self.xf = cl_array.zeros(self.context,self.queue, (n), np.float32) + self.r = cl_array.zeros(self.context,self.queue, (n), np.float32) + self.u = cl_array.zeros(self.context,self.queue, (n), np.float32) + self.v = cl_array.zeros(self.context,self.queue, (n), np.float32) + self.w = cl_array.zeros(self.context,self.queue, (n), np.float32) + # Transfer data to buffers + events = [] + events.append(cl.enqueue_write_buffer(self.queue, self.A, A.reshape((n*n)) )) + self.b.set(B) + self.x.set(x0) + self.u.set(B) + for e in events: + e.wait() + + def precondition(self, n): + """ Preconditionate matrix, ensuring that all linear system + matrix columns has an acceptable norm. Of course, final + solution vector must be corrected conveniently. + @param n Linear system dimension. + """ + gSize = (clUtils.globalSize(n),) + xf = np.ones((n), dtype=np.float32) + for i in range(0,n): + col = np.uint32(i) + # Compute column norm + # We can use v as column vector because has not been used yet + kernelargs = (self.A, + self.v.data, + col, + n) + self.program.column(self.queue, gSize, None, *(kernelargs)) + norm = np.sqrt(self.dot(self.v,self.v).get()) + FreeCAD.Console.PrintMessage("col ") + FreeCAD.Console.PrintMessage(i) + FreeCAD.Console.PrintMessage(", norm=") + FreeCAD.Console.PrintMessage(norm) + FreeCAD.Console.PrintMessage("\n") + if norm < 1.0: + continue + fact = np.float32(1.0/norm) + xf[i] = fact + kernelargs = (self.A, + fact, + col, + n) + self.program.prod_c_column(self.queue, gSize, None, *(kernelargs)) + self.x.set(xf) + diff --git a/src/Mod/Ship/simRun/clSim/bem_minres_cl.py b/src/Mod/Ship/simRun/clSim/bem_minres_cl.py new file mode 100644 index 000000000..51e82d585 --- /dev/null +++ b/src/Mod/Ship/simRun/clSim/bem_minres_cl.py @@ -0,0 +1,157 @@ +#*************************************************************************** +#* * +#* 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 + +# pyOpenCL +import pyopencl as cl +from pyopencl.reduction import ReductionKernel +import pyopencl.array as cl_array +import clUtils + +import FreeCAD +grav=9.81 + +class minres: + def __init__(self, context, queue): + """ Constructor. + @param context OpenCL context where apply. + @param queue OpenCL command queue. + """ + self.context = context + self.queue = queue + self.program = clUtils.loadProgram(context, clUtils.path() + "/minres.cl") + # Create OpenCL objects as null objects, that we will generate + # at the first iteration + self.A = None + self.B = None + self.X0 = None + self.X = None + self.R = None + # Create dot operator + self.dot = ReductionKernel(context, np.float32, neutral="0", + reduce_expr="a+b", map_expr="x[i]*y[i]", + arguments="__global float *x, __global float *y") + + def solve(self, A, B, x0=None, tol=10e-6, iters=300): + r""" Solve linear system of equations by a Jacobi + iterative method. + @param A Linear system matrix. + @param B Linear system independent term. + @param x0 Initial aproximation of the solution. + @param tol Relative error tolerance: \n + \$ \vert\vert B - A \, x \vert \vert_\infty / + \vert\vert B \vert \vert_\infty \$ + @param iters Maximum number of iterations. + """ + # Create/set OpenCL buffers + self.setBuffers(A,B,x0) + # Get dimensions for OpenCL execution + n = np.uint32(len(B)) + gSize = (clUtils.globalSize(n),) + # Get a norm to can compare later for valid result + B_cl = cl_array.to_device(self.context,self.queue,B) + bnorm2 = self.dot(B_cl,B_cl).get() + FreeCAD.Console.PrintMessage(bnorm2) + FreeCAD.Console.PrintMessage("\n") + # Iterate while the result converges or maximum number + # of iterations is reached. + for i in range(0,iters): + # Compute residues + kernelargs = (self.A, + self.B, + self.X0, + self.R.data, + n) + # Test if the final result has been reached + self.program.r(self.queue, gSize, None, *(kernelargs)) + rnorm2 = self.dot(self.R,self.R).get() + FreeCAD.Console.PrintMessage("\t") + FreeCAD.Console.PrintMessage(rnorm2) + FreeCAD.Console.PrintMessage("\n") + if np.sqrt(rnorm2 / bnorm2) <= tol: + break + # Iterate + kernelargs = (self.A, + self.R.data, + self.AR.data, + n) + self.program.dot_mat_vec(self.queue, gSize, None, *(kernelargs)) + AR_R = self.dot(self.AR,self.R).get() + AR_AR = self.dot(self.AR,self.AR).get() + kernelargs = (self.A, + self.R.data, + self.X, + self.X0, + AR_R, + AR_AR, + n) + self.program.minres(self.queue, gSize, None, *(kernelargs)) + # Swap variables + swap = self.X + self.X = self.X0 + self.X0 = swap + # Return result computed + x = np.zeros((n), dtype=np.float32) + cl.enqueue_read_buffer(self.queue, self.X0, x).wait() + return (x, np.sqrt(rnorm2 / bnorm2), i) + + def setBuffers(self, A,B,x0): + """ Create/set OpenCL required buffers. + @param A Linear system matrix. + @param B Independent linear term. + @param x0 Initial solution estimator. + """ + # Get dimensions + shape = np.shape(A) + if len(shape) != 2: + raise ValueError, 'Matrix A must be 2 dimensional array' + if shape[0] != shape[1]: + raise ValueError, 'Square linear system matrix expected' + if len(B) != shape[0]: + raise ValueError, 'Matrix and independet term dimensions does not match' + n = len(B) + # Set x0 if not provided + if x0 != None: + if len(x0) != n: + raise ValueError, 'Initial solution estimator length does not match with linear system dimensions' + if x0 == None: + x0 = B + # Create OpenCL objects if not already generated + if not self.A: + mf = cl.mem_flags + self.A = cl.Buffer( self.context, mf.READ_ONLY, size = n*n * np.dtype('float32').itemsize ) + self.B = cl.Buffer( self.context, mf.READ_ONLY, size = n * np.dtype('float32').itemsize ) + self.X0 = cl.Buffer( self.context, mf.READ_WRITE, size = n * np.dtype('float32').itemsize ) + self.X = cl.Buffer( self.context, mf.READ_WRITE, size = n * np.dtype('float32').itemsize ) + self.R = cl_array.zeros(self.context,self.queue, (n), np.float32) + self.AR = cl_array.zeros(self.context,self.queue, (n), np.float32) + # Transfer data to buffers + events = [] + events.append(cl.enqueue_write_buffer(self.queue, self.A, A.reshape((n*n)) )) + events.append(cl.enqueue_write_buffer(self.queue, self.B, B)) + events.append(cl.enqueue_write_buffer(self.queue, self.X0, x0)) + for e in events: + e.wait() + diff --git a/src/Mod/Ship/simRun/clSim/clUtils.py b/src/Mod/Ship/simRun/clSim/clUtils.py new file mode 100644 index 000000000..676a23019 --- /dev/null +++ b/src/Mod/Ship/simRun/clSim/clUtils.py @@ -0,0 +1,58 @@ +#*************************************************************************** +#* * +#* 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 +from shipUtils import Paths + +# pyOpenCL +import pyopencl as cl +import numpy as np + +# Standard +import math + +def loadProgram(context, file): + """ Loads a file and comnpile it. + @param context OpenCL context where apply. + @param file File to load and compile. + @return Ready to use OpenCL program. + """ + f = open(file, 'r') + str = "".join(f.readlines()) + return cl.Program(context, str).build() + +def path(): + """ Gets the OpenCL kernels path + @return OpenCL kernels path + """ + path = Paths.modulePath() + "/resources/opencl" + return path + +def globalSize(n): + """ Compute global size from amount of data. + @param n Amount of data. + @return global size. + """ + localSize = 256.0 + return int(math.ceil(n/localSize)*localSize) + diff --git a/src/Mod/Ship/simRun/clSim/evolution.py b/src/Mod/Ship/simRun/clSim/evolution.py new file mode 100644 index 000000000..4f62ba6fc --- /dev/null +++ b/src/Mod/Ship/simRun/clSim/evolution.py @@ -0,0 +1,258 @@ +#*************************************************************************** +#* * +#* 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 +import FreeCAD + +grav=9.81 + +class simEvolution_cl: + 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, bem, waves, t, dt): + """ Compute the variables unknow for the next time step. + @param fs Free surface instance. + @param bem Boundary elements method instance. + @param waves Waves instance. + @param t Simulation time. + @param dt Time step. + """ + self.BC(fs,bem,waves, t) + self.Integrate(fs,bem,waves, t,dt) + + def BC(self, fs, bem, waves, t): + """ Apply the boundary conditions to compute time variation rate + of the unknow variables. + @param fs Free surface instance. + @param bem Boundary elements method instance. + @param waves Waves instance. + @param t Simulation time. + """ + nx = fs['Nx'] + ny = fs['Ny'] + nFS = nx*ny + for i in range(0,nx): + for j in range(0,ny): + gradp = np.copy(bem['gradp'][i*ny+j]) + z = fs['pos'][i,j,2] + bem['dpdt'][i*ny+j] = - 0.5 * gradp**2.0 - 9.81*z + fs['vel'][i,j,2] = gradp + # Since the inverse method returns significant errors near + # to the free surface borders, we will modify 3 area + # elements of the border such that the last one will be + # exactly the analytic solution. Also we will use it as + # numerical beach in order to disipate waves generated + # inside the domain (that will be refelceted otherwise) + # 1.- Corners + for i in range(0,4)+range(nx-4,nx): + if i in range(0,4): + fx = 1. - i/4. + else: + fx = (i - nx + 5) / 4. + for j in range(0,4)+range(ny-4,ny): + if j in range(0,4): + fy = 1. - j/4. + else: + fy = (j - ny + 5) / 4. + factor = max(fx,fy) + pos = fs['pos'][i,j] + dpdt = 0. + vel = 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*9.81*np.sin(k*l - frec*t + phase)*np.exp(k*pos[2]) + dpdt = dpdt + amp + amp = - A*frec*np.cos(k*l - frec*t + phase) + vel = vel + amp + bem['dpdt'][i*ny+j] = factor*dpdt + (1.-factor)*bem['dpdt'][i*ny+j] + fs['vel'][i,j,2] = factor*vel + (1.-factor)*fs['vel'][i,j,2] + # 2.- rows + for i in range(0,4)+range(nx-4,nx): + if i in range(0,4): + factor = 1. - i/4. + else: + factor = (i - nx + 5) / 4. + for j in range(4, ny-4): + pos = fs['pos'][i,j] + dpdt = 0. + vel = 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*9.81*np.sin(k*l - frec*t + phase)*np.exp(k*pos[2]) + dpdt = dpdt + amp + amp = - A*frec*np.cos(k*l - frec*t + phase) + vel = vel + amp + bem['dpdt'][i*ny+j] = factor*dpdt + (1.-factor)*bem['dpdt'][i*ny+j] + fs['vel'][i,j,2] = factor*vel + (1.-factor)*fs['vel'][i,j,2] + # 3.- columns + for j in range(0,4)+range(ny-4,ny): + if j in range(0,4): + factor = 1. - j/4. + else: + factor = (j - ny + 5) / 4. + for i in range(4, nx-4): + pos = fs['pos'][i,j] + dpdt = 0. + vel = 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*9.81*np.sin(k*l - frec*t + phase)*np.exp(k*pos[2]) + dpdt = dpdt + amp + amp = - A*frec*np.cos(k*l - frec*t + phase) + vel = vel + amp + bem['dpdt'][i*ny+j] = factor*dpdt + (1.-factor)*bem['dpdt'][i*ny+j] + fs['vel'][i,j,2] = factor*vel + (1.-factor)*fs['vel'][i,j,2] + + def Integrate(self, fs, bem, waves, t, dt): + """ Perform time integration of the unknow variables. + @param fs Free surface instance. + @param bem Boundary elements method instance. + @param waves Waves instance. + @param t Simulation time. + @param dt Time step. + """ + nx = fs['Nx'] + ny = fs['Ny'] + nFS = nx*ny + for i in range(0,nx): + for j in range(0,ny): + bem['p'][i*ny+j] = bem['p'][i*ny+j] + dt * bem['dpdt'][i*ny+j] + fs['pos'][i,j,2] = fs['pos'][i,j,2] + dt * fs['vel'][i,j,2] + # Since the inverse method returns significant errors near + # to the free surface borders, we will modify 3 area + # elements of the border such that the last one will be + # exactly the analytic solution. Also we will use it as + # numerical beach in order to disipate waves generated + # inside the domain (that will be refelceted otherwise) + # 1.- Corners + for i in range(0,4)+range(nx-4,nx): + if i in range(0,4): + fx = 1. - i/4. + else: + fx = (i - nx + 5) / 4. + for j in range(0,4)+range(ny-4,ny): + if j in range(0,4): + fy = 1. - j/4. + else: + fy = (j - ny + 5) / 4. + factor = max(fx,fy) + pos = fs['pos'][i,j] + phi = 0. + z = 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*frec/k*np.cos(k*l - frec*(t+dt) + phase)*np.exp(k*pos[2]) + phi = phi + amp + amp = A*np.sin(k*l - frec*(t+dt) + phase) + z = z + amp + bem['p'][i*ny+j] = factor*phi + (1.-factor)*bem['p'][i*ny+j] + fs['pos'][i,j,2] = factor*z + (1.-factor)*fs['pos'][i,j,2] + # 2.- rows + for i in range(0,4)+range(nx-4,nx): + if i in range(0,4): + factor = 1. - i/4. + else: + factor = (i - nx + 5) / 4. + for j in range(4, ny-4): + pos = fs['pos'][i,j] + phi = 0. + z = 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*frec/k*np.cos(k*l - frec*(t+dt) + phase)*np.exp(k*pos[2]) + phi = phi + amp + amp = A*np.sin(k*l - frec*(t+dt) + phase) + z = z + amp + bem['p'][i*ny+j] = factor*phi + (1.-factor)*bem['p'][i*ny+j] + fs['pos'][i,j,2] = factor*z + (1.-factor)*fs['pos'][i,j,2] + # 3.- columns + for j in range(0,4)+range(ny-4,ny): + if j in range(0,4): + factor = 1. - j/4. + else: + factor = (j - ny + 5) / 4. + for i in range(4, nx-4): + pos = fs['pos'][i,j] + phi = 0. + z = 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*frec/k*np.cos(k*l - frec*(t+dt) + phase)*np.exp(k*pos[2]) + phi = phi + amp + amp = A*np.sin(k*l - frec*(t+dt) + phase) + z = z + amp + bem['p'][i*ny+j] = factor*phi + (1.-factor)*bem['p'][i*ny+j] + fs['pos'][i,j,2] = factor*z + (1.-factor)*fs['pos'][i,j,2] + + diff --git a/src/Mod/Ship/simRun/clSim/initialization.py b/src/Mod/Ship/simRun/clSim/initialization.py index 5e4f30417..02b1c1661 100644 --- a/src/Mod/Ship/simRun/clSim/initialization.py +++ b/src/Mod/Ship/simRun/clSim/initialization.py @@ -1,113 +1,229 @@ #*************************************************************************** -#* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * -#* * +#* * +#* 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 * +#* 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 * -#* * +#* USA * +#* * #*************************************************************************** -# Simulation stuff -from Utils import * - -# pyOpenCL -import pyopencl as cl +# numpy import numpy as np +import FreeCAD -class perform: - def __init__(self, FSmesh, waves, context, queue): - """ Constructor, includes program loading. - @param FSmesh Initial free surface mesh. - @param waves Considered simulation waves (A,T,phi,heading). - @param context OpenCL context where apply. - @param queue OpenCL command queue. - """ - self.context = context - self.queue = queue - self.program = loadProgram(context, clPath() + "/simInit.cl") - self.loadData(FSmesh, waves) - self.execute() +grav=9.81 + +class simInitialization_cl: + def __init__(self, FSMesh, FSData, waves, Sea, context=None, queue=None): + """ Constructor. + @param FSMesh Initial free surface mesh. + @param FSData Dimensions data of the free surface mesh (L,B,Nx,Ny) + @param waves Considered simulation waves (A,T,phi,heading). + @param Sea Tuple with the number of free surfaces that must be repeated in each direction. + @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 + self.loadData(FSMesh, FSData, waves, Sea) + 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, FSData, waves, Sea): + """ Convert data to numpy format. + @param FSMesh Initial free surface mesh. + @param FSData Dimensions data of the free surface mesh (L,B,Nx,Ny) + @param waves Considered simulation waves (A,T,phi,heading). + @param Sea Tuple with the number of free surfaces that must be repeated in each direction. + """ + # Data will classified in four groups: + # Free surface: + # Is a key part of the simulation, so is + # separated from the rest of water involved + # elements. + # Sea: + # BEM method requires to artificially extend + # the free surface in order to send the bounds + # Inlet, Outlet, Left and Side to the infinite. + # Here is specified how many time must be + # repeated the free surface in order to get + # virtually infinite far bounds. + # Body: + # Is the main objective of the simulation. + # Waves: + # Data that is append as boundary condition. + # BEM: + # Used to solve the BEM problem and evolution. + + # -------------------------------------------- + # Free surface data + # N, Nx, Ny = Number of points in each + # direction + # pos = Positions + # vel = Velocities + # n = Normals + # area = Areas + # -------------------------------------------- + nx = len(FSMesh) + ny = len(FSMesh[0]) + L = FSData[0] + B = FSData[1] + dx = L/nx + dy = B/ny + p = np.zeros((nx,ny, 4), dtype=np.float32) + V = np.zeros((nx,ny, 4), dtype=np.float32) + n = np.zeros((nx,ny, 4), dtype=np.float32) + a = np.ndarray((nx,ny), dtype=np.float32) + for i in range(0, nx): + for j in range(0, ny): + pos = FSMesh[i][j].pos + normal = FSMesh[i][j].normal + area = FSMesh[i][j].area + p[i,j,0] = pos.x + p[i,j,1] = pos.y + p[i,j,2] = pos.z + p[i,j,3] = 1.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 = {'N':nx*ny, 'Nx':nx, 'Ny':ny, \ + 'L':L, 'B':B, 'dx':dx, 'dy':dy, \ + 'pos':p, 'vel':V, 'normal':n, 'area':a} + # -------------------------------------------- + # Sea data + # N, Nx, Ny = Number of free surfaces + # repetitions in each direction + # -------------------------------------------- + self.sea = {'N':Sea[0]*Sea[1], 'Nx':Sea[0], 'Ny':Sea[1]} + # -------------------------------------------- + # Body data + # N, Nx, Ny = Number of points in each + # direction + # pos = Positions + # vel = Velocities + # n = Normals + # area = Areas + # -------------------------------------------- + self.b = {'N':0, 'pos':None, 'vel':None, 'normal':None, 'area':None} + # -------------------------------------------- + # Waves data + # N = Number of waves + # data = Waves data + # -------------------------------------------- + nW = len(waves) + w = np.ndarray((nW, 4), dtype=np.float32) + for i in range(0,nW): + w[i,0] = waves[i][0] + w[i,1] = waves[i][1] + w[i,2] = waves[i][2] + w[i,3] = waves[i][3] + self.waves = {'N':nW, 'data':w} + # -------------------------------------------- + # BEM data + # N = nFS + nB + # A,B = Linear system matrix and vectors + # p = Velocity potentials (phi). + # gradp = Velocity potentials gradient + # (grad(phi)) projected over the + # normal + # dpdt = Velocity potentials time + # variation rate + # -------------------------------------------- + nFS = self.fs['N'] + nB = self.b['N'] + N = nFS + nB + A = np.zeros((N, N), dtype=np.float32) + B = np.zeros((N), dtype=np.float32) + p = np.zeros((N), dtype=np.float32) + gp = np.zeros((N), dtype=np.float32) + dpdt = np.zeros((N), dtype=np.float32) + self.bem = {'N':N, 'A':A, 'B':B, \ + 'p':p, 'gradp':gp, 'dpdt':dpdt } + + def execute(self): + """ Compute initial conditions. """ + # -------------------------------------------- + # Free surface initial condition. + # Since RK4 scheme starts on the end of + # previous step, we only write on last + # stage value (p4 and dp4) + # -------------------------------------------- + nx = self.fs['Nx'] + ny = self.fs['Ny'] + for i in range(0,nx): + for j in range(0,ny): + # Since initial values of the potencial, and this acceleration, + # depends on z, we need to compute first the positions. + self.fs['pos'][i,j][2] = 0. + self.bem['p'][i*ny+j] = 0. + self.bem['gradp'][i*ny+j] = 0. + for w in self.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 + pos = self.fs['pos'][i,j] + 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 = - A*frec*np.cos(k*l + phase) + self.fs['vel'][i,j][2] = self.fs['vel'][i,j][2] + amp + # And now we can compute potentials. + for w in self.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 + pos = self.fs['pos'][i,j] + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + amp = - A*frec/k*np.cos(k*l + phase)*np.exp(k*pos[2]) + self.bem['p'][i*ny+j] = self.bem['p'][i*ny+j] + amp + amp = - A*frec*np.cos(k*l + phase)*np.exp(k*pos[2]) + self.bem['gradp'][i*ny+j] = self.bem['gradp'][i*ny+j] + amp + + # -------------------------------------------------------- + # Debugging + # -------------------------------------------------------- + """ + self.fs['pos'][i,j][2] = 0. + self.bem['p'][i*ny+j] = 0. + self.bem['gradp'][i*ny+j] = 0. + # We can do phi = Green's function + dx = self.fs['pos'][i,j][0] + dy = self.fs['pos'][i,j][1] + dz = 15.0 # An arbitrary value > 0 + self.bem['p'][i*ny+j] = 1. / (4. * np.pi * np.sqrt(dx*dx + dy*dy + dz*dz)) + self.bem['gradp'][i*ny+j] = - dz / (4. * np.pi * (dx*dx + dy*dy + dz*dz)**(1.5)) + """ + # -------------------------------------------------------- + # Debugging + # -------------------------------------------------------- - def loadData(self, FSmesh, waves): - """ Convert data to numpy format, and create OpenCL - buffers. - @param FSmesh Initial free surface mesh. - @param waves Considered simulation waves (A,T,phi,heading). - """ - mf = cl.mem_flags - nx = len(FSmesh) - ny = len(FSmesh[0]) - nW = len(waves) - # Mesh data - p = np.ndarray((nx*ny, 4), dtype=np.float32) - n = np.ndarray((nx*ny, 4), dtype=np.float32) - a = np.ndarray((nx*ny, 1), dtype=np.float32) - for i in range(0, nx): - for j in range(0, ny): - id = i*ny + j - pos = FSmesh[i][j].pos - normal = FSmesh[i][j].normal - area = FSmesh[i][j].area - p[id,0] = pos.x - p[id,1] = pos.y - p[id,2] = pos.z - p[id,3] = 1. - n[id,0] = normal.x - n[id,1] = normal.y - n[id,2] = normal.z - n[id,3] = 0. - a[id,0] = area - p_cl = cl.Buffer(self.context, mf.READ_WRITE | mf.COPY_HOST_PTR, hostbuf=p) - n_cl = cl.Buffer(self.context, mf.READ_WRITE | mf.COPY_HOST_PTR, hostbuf=n) - a_cl = cl.Buffer(self.context, mf.READ_WRITE | mf.COPY_HOST_PTR, hostbuf=a) - v_cl = cl.Buffer(self.context, mf.READ_WRITE, size = nx*ny*4 * np.dtype('float32').itemsize) - f_cl = cl.Buffer(self.context, mf.READ_WRITE, size = nx*ny*4 * np.dtype('float32').itemsize) - phi = cl.Buffer(self.context, mf.READ_WRITE, size = nx*ny * np.dtype('float32').itemsize) - Phi = cl.Buffer(self.context, mf.READ_WRITE, size = nx*ny * np.dtype('float32').itemsize) - self.fs = {'Nx':nx, 'Ny':ny, 'pos':p_cl, 'vel':v_cl, 'acc':f_cl, \ - 'normal':n_cl, 'area':a_cl, 'velPot':phi, 'accPot':Phi} - # Waves data - w = np.ndarray((nW, 4), dtype=np.float32) - for i in range(0,nW): - w[i,0] = waves[i][0] - w[i,1] = waves[i][1] - w[i,2] = waves[i][2] - w[i,3] = waves[i][3] - w_cl = cl.Buffer(self.context, mf.READ_WRITE | mf.COPY_HOST_PTR, hostbuf=w) - self.waves = {'N':nW, 'data':w_cl} - # Ensure that all data has been written - self.queue.finish() - def execute(self): - """ Compute initial conditions. """ - # Global size computation - N = np.ndarray((2, 1), dtype=np.uint32) - N[0] = self.fs['Nx'] - N[1] = self.fs['Ny'] - n = np.uint32(self.waves['N']) - gSize = (globalSize(N[0]),globalSize(N[1]),) - # Kernel arguments - kernelargs = (self.fs['pos'], - self.fs['vel'], - self.fs['acc'], - self.waves['data'], - self.fs['velPot'], - self.fs['accPot'], - N, n) - # Kernel launch - self.program.FS(self.queue, gSize, None, *(kernelargs)) - self.queue.finish() diff --git a/src/Mod/Ship/simRun/clSim/matrixGen.py b/src/Mod/Ship/simRun/clSim/matrixGen.py new file mode 100644 index 000000000..69430d9be --- /dev/null +++ b/src/Mod/Ship/simRun/clSim/matrixGen.py @@ -0,0 +1,184 @@ +#*************************************************************************** +#* * +#* 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 + +# pyOpenCL +import pyopencl as cl +import clUtils + +import FreeCAD +grav=9.81 + +class simMatrixGen_cl: + def __init__(self, context=None, queue=None): + """ Constructor. + @param context OpenCL context where apply. + @param queue OpenCL command queue. + """ + self.context = context + self.queue = queue + self.program = clUtils.loadProgram(context, clUtils.path() + "/matrixGen.cl") + # Create OpenCL objects as null objects, that we will generate + # at the first iteration + self.A = None + self.B = None + self.dB = None + self.pos = None + self.area = None + self.normal = None + self.p = None + self.gradp = None + + def execute(self, fs, waves, sea, bem, body, t): + """ Compute system matrix. + @param fs Free surface instance. + @param waves Waves instance. + @param sea Sea boundary instance. + @param bem Boundary Element Method instance. + @param body Body instance. + @param t Simulation time. + """ + # Create/set OpenCL buffers + self.setBuffers(fs,waves,sea,bem,body) + # Convert constant parameters + L = np.float32(fs['L']) + B = np.float32(fs['B']) + dx = np.float32(fs['dx']) + dy = np.float32(fs['dy']) + T = np.float32(t) + # Get dimensions for OpenCL execution + nx = np.uint32(fs['Nx']) + ny = np.uint32(fs['Ny']) + nFS = np.uint32(fs['N']) + nB = np.uint32(body['N']) + n = np.uint32(nFS + nB) + nSeax = np.int32(sea['Nx']) + nSeay = np.int32(sea['Ny']) + nW = np.uint32(waves['N']) + # Call OpenCL to work + gSize = (clUtils.globalSize(n),) + kernelargs = (self.A, + self.B, + self.pos, + self.area, + self.normal, + self.bem_p, + self.bem_dp, + self.waves, + L, + B, + dx, + dy, + T, + nx, + ny, + nFS, + nB, + n, + nSeax, + nSeay, + nW) + self.program.matrixGen(self.queue, gSize, None, *(kernelargs)) + self.queue.finish() + # Read output data + events = [] + events.append(cl.enqueue_read_buffer(self.queue, self.A, bem['A'].reshape((n*n)))) + events.append(cl.enqueue_read_buffer(self.queue, self.B, bem['B'])) + # events.append(cl.enqueue_read_buffer(self.queue, self.dB, bem['dB'])) + for e in events: + e.wait() + + + # -------------------------------------------------------- + # Debugging + # -------------------------------------------------------- + """ + for i in range(0,fs['Nx']): + for j in range(0,fs['Ny']): + x = fs['pos'][i,j,0] + y = fs['pos'][i,j,1] + FreeCAD.Console.PrintMessage("pos = {0},{1}\n".format(x,y)) + A = np.dot(bem['A'][i*fs['Ny'] + j,:], bem['gradp'][:]) + B = bem['B'][i*fs['Ny'] + j] + phi = 2.0 * (B - A) + bem['p'][i*fs['Ny'] + j] = phi + """ + + # -------------------------------------------------------- + # Debugging + # -------------------------------------------------------- + return + + def setBuffers(self, fs, waves, sea, bem, body): + """ Create/set OpenCL required buffers. + @param fs Free surface instance. + @param waves Waves instance. + @param sea Sea boundary instance. + @param bem Boundary Element Method instance. + @param body Body instance. + """ + # Get dimensions + nFS = fs['N'] + nB = body['N'] + n = nFS + nB + nW = waves['N'] + # Generate arrays for positions, areas and normals + pos = np.zeros((n, 4), dtype=np.float32) + area = np.zeros((n ), dtype=np.float32) + normal = np.zeros((n, 4), dtype=np.float32) + p = np.zeros((n ), dtype=np.float32) + dp = np.zeros((n ), dtype=np.float32) + w = np.zeros((nW,4), dtype=np.float32) + pos[0:nFS] = fs['pos'].reshape((nFS,4)) + area[0:nFS] = fs['area'].reshape((nFS)) + normal[0:nFS] = fs['normal'].reshape((nFS,4)) + nx = fs['Nx'] + ny = fs['Ny'] + p[0:n] = bem['p'] + dp[0:n] = bem['gradp'] + w[0:nW] = waves['data'] + # Create OpenCL objects if not already generated + if not self.A: + mf = cl.mem_flags + self.A = cl.Buffer( self.context, mf.WRITE_ONLY, size = n*n * np.dtype('float32').itemsize ) + self.B = cl.Buffer( self.context, mf.WRITE_ONLY, size = n * np.dtype('float32').itemsize ) + self.dB = cl.Buffer( self.context, mf.WRITE_ONLY, size = n * np.dtype('float32').itemsize ) + self.pos = cl.Buffer( self.context, mf.READ_ONLY, size = n*4 * np.dtype('float32').itemsize ) + self.area = cl.Buffer( self.context, mf.READ_ONLY, size = n * np.dtype('float32').itemsize ) + self.normal = cl.Buffer( self.context, mf.READ_ONLY, size = n*4 * np.dtype('float32').itemsize ) + self.bem_p = cl.Buffer( self.context, mf.READ_ONLY, size = n * np.dtype('float32').itemsize ) + self.bem_dp = cl.Buffer( self.context, mf.READ_ONLY, size = n * np.dtype('float32').itemsize ) + self.waves = cl.Buffer( self.context, mf.READ_ONLY, size = nW*4 * np.dtype('float32').itemsize ) + # Transfer data to buffers + events = [] + events.append(cl.enqueue_write_buffer(self.queue, self.pos, pos)) + events.append(cl.enqueue_write_buffer(self.queue, self.area, area)) + events.append(cl.enqueue_write_buffer(self.queue, self.normal, normal)) + events.append(cl.enqueue_write_buffer(self.queue, self.bem_p, p)) + events.append(cl.enqueue_write_buffer(self.queue, self.bem_dp, dp)) + events.append(cl.enqueue_write_buffer(self.queue, self.waves, w)) + for e in events: + e.wait() + diff --git a/src/Mod/Ship/simRun/theory/abstract.tex b/src/Mod/Ship/simRun/theory/abstract.tex new file mode 100644 index 000000000..3aa57fbb2 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/abstract.tex @@ -0,0 +1,56 @@ +\chapter{Introduction} +\label{s:introduction} +% +\section{Objective} +% +The objective of this document is introduce briefly how the waves of the +seakeeping simulator are propagated.\rc +% +In the seakeeping simulator Boundary Elements Method (BEM) will be used, +that is detailed described in several books, like \citet{bem_2007}. +\citet{vinayan2007} gives a detailed description of the propagation +of waves in a 2D case, and is a good starting point.\rc +% +We will start briefly describing the governing equations in order to can +start working with the 2D problem. First the incident waves over our +computational domain will be described, introducing also the potential, +discussing then the BEM applied to this case. As we will see the Laplace +problem in the 2D case will not be really useful for us.\rc +% +After that we can start working in the 3D case, that is our real objective. +The incident waves will be rewritten, and the Laplace problem and the BEM +application purposed again. +% +\chapter{Governing equations} +\label{s:governing_equations} +% +Assuming no viscous fluid (that allows to transform Navier-Stokes +equations into Euler ones), and imposing an initial condition such +that\footnote{With no viscous fluid this condition is preserved along the +time}: +% +\begin{eqnarray} + \rotational \bs{u} = 0 +\end{eqnarray} +% +The fluid velocity derives from a scalar function potential $\phi$ +% +\begin{eqnarray} + \label{eq:governing_equations:v_potential} + \gradient \phi = \bs{u} +\end{eqnarray} +% +Then the Navier-Stokes equations can be rewriten as a Laplacian problem +and Bernoulli equation: +% +\begin{eqnarray} + \label{eq:governing_equations:laplace} + \laplacian \phi = & 0 + \\ + \label{eq:governing_equations:bernoulli} + p = & - \rho \left( \vert \bs{u} \vert^2 + g \bs{z} \right) +\end{eqnarray} +% +And in order to solve the Laplace problem \ref{eq:governing_equations:laplace} +we will use the BEM as described by \citet{bem_2007}. +% \ No newline at end of file diff --git a/src/Mod/Ship/simRun/theory/bib.bib b/src/Mod/Ship/simRun/theory/bib.bib new file mode 100644 index 000000000..ed2200659 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/bib.bib @@ -0,0 +1,91 @@ +@Comment{THE COMMENTS IN BIBTEX ARE IMPLEMENTED THIS WAY!} +@STRING(OE="Ocean Engineering") +@STRING{AA = "Astron. Astrophys."} +@STRING{ACA = "Extraits des comptes rendus des s\'eances de l'Acad\'emie des Sciences"} +@STRING{AG = "Adv. Geophys."} +@STRING{AIAAJ = "AIAA J."} +@STRING{AIAAP = "AIAA Pap."} +@STRING{AMR = "Appl. Mech. Rev."} +@STRING{ARFM = "Annu. Rev. Fluid Mech."} +@STRING{ARAA = "Annu. Rev. Astron. Astrophy."} +@STRING{AMCFD = "Advanced Methods for Computational Fluid Dynamics"} +@STRING{AMC = "Applied Mathematics and Computations"} +@STRING{ANM = "Applied Numerical Mathematics"} +@STRING{BAPS = "Bull. Am. Phys. Soc."} +@STRING{CUP = "Cambridge University Press"} +@STRING{CMAME = "Comput. Methods Appl. Mech. Engrg."} +@STRING{DI = "Dantec Information"} +@STRING{EF = "Expts. Fluids"} +@STRING{EJMF = "Eur. J. Mech. B/Fluids"} +@STRING{IJHFF = "Int. J. Heat and Fluid Flow"} +@STRING{IJHMT = "Int. J. Heat and Mass Transfer"} +@STRING{IJIE = "Int. J. Impact Engng."} +@STRING{IJNMF = "Int. J. Numer. Methods Fluids"} +@STRING{INPG = "Institut National Polytechnique Grenoble"} +@STRING{JA = "J. Aircraft"} +@STRING{JAM = "J. Applied Mech."} +@STRING{JAMTP = "J. Appl. Mech. Tech. Phys."} +@STRING{JAP = "J. App. Phys."} +@STRING{JAS = "J. Atmos. Sci."} +@STRING{JCP = "J. Comp. Phys."} +@STRING{JCAM = "J. Computational and Applied Mathematics"} +@STRING{JFE = "J. Fluids Engine."} +@STRING{JFM = "J. Fluid Mech."} +@STRING{JHE = "J. Hydraulic Engineering"} +@STRING{JM = "Journal de M\'ecanique"} +@STRING{JOT = "Journal of Turbulence"} +@STRING{JRNBS = "J. Res. Nat. Bur. Standards"} +@STRING{JTAM = "J. Theo. and Appl. Mech."} +@STRING{JWEIA = "J. Wind Engng. Indust. Aerodyn."} +@STRING{MC = "Math. Comp."} +@STRING{ME = "Meccanica"} +@STRING{MRP = "Mathematics Reports and Preprints"} +@STRING{MWR = "Mon. Weather Rev."} +@STRING{NACA = "NACA"} +@STRING{PFA = "Phys. Fluids A"} +@STRING{PFL = "Phys. Fluids Lett."} +@STRING{PFO = "Phys. Fluids"} +@STRING{PRA = "Phys. Review A"} +@STRING{PRE = "Phys. Review E"} +@STRING{PRL = "Phys. Review Lett."} +@STRING{PTRS = "Phil. Trans. Roy. Soc."} +@STRING{QJRMS = "Q. J. R. Meteorol. Soc."} +@STRING{RA = "Rech. Aeros."} +@STRING{RF = "Rapport Final"} +@STRING{SJAP = "Sov. J. Appl. Phys."} +@STRING{SSSR = "Dokl. Akad. Nauk. SSSR"} +@STRING{SV = "Springer-Verlag"} +@STRING{TAM = "Theoret. and Applied Mech."} +@STRING{TAJ = "The Astrophysical Journal"} +@STRING{TCFD = "Theoret. Comput. Fluid Dynamics"} +@STRING{EJBE = "Electronic Journal of Boundary Elements"} + + +@BOOK{bem_2007, + AUTHOR = {Whye-Teong Ang}, + EDITOR = {Universal Publishers}, + TITLE = {A Beginner’s Course in Boundary Element Methods}, + PUBLISHER = {Cambridge University Press, New York}, + YEAR = {2007}, + VOLUME = {}, + SERIES = {}, + ADDRESS = {}, + EDITION = {}, + MONTH = {} +} + +@ARTICLE{vinayan2007, + AUTHOR="Vinayan, V. and Kinnas, S. A. ", + TITLE="A BEM for the Propagation of Nonlinear Planar Free-surface Waves", + JOURNAL=EJBE, + VOLUME=5, + PAGES="17-40", + YEAR=2007, +} + +@PHDTHESIS{yang2004, + AUTHOR="Jinghai Yang", + TITLE="Time domain, nonlinear theories on ship motions", + SCHOOL="University of Hawaii", + YEAR=2004, +} diff --git a/src/Mod/Ship/simRun/theory/deep_water.wxmx b/src/Mod/Ship/simRun/theory/deep_water.wxmx new file mode 100644 index 0000000000000000000000000000000000000000..7677b0dc57a4444328b766fe21e41ba95b6a3b87 GIT binary patch literal 73355 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 literal 0 HcmV?d00001 diff --git a/src/Mod/Ship/simRun/theory/images/CC_88x31.png b/src/Mod/Ship/simRun/theory/images/CC_88x31.png new file mode 100644 index 0000000000000000000000000000000000000000..49f272f828c17c9f52b64c27fa6a3c399bee9344 GIT binary patch literal 5281 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 literal 0 HcmV?d00001 diff --git a/src/Mod/Ship/simRun/theory/images/Integral.png b/src/Mod/Ship/simRun/theory/images/Integral.png new file mode 100644 index 0000000000000000000000000000000000000000..2e53f03a45c51c85f3e3037d72ea2500f004f84a GIT binary patch literal 32720 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 WX)e!Oi>Tmll9UwGPEh17-2M-Z4 + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + dx + Dx + Z(xa,ya) + + + + + + + + + Z(xa-Dx,ya+Dy) + + + + + + + + + Z(xa-Dx,ya) + + + + + + + + + Z(xa-Dx,ya-Dy) + + + + + Z(xa-Dx,ya+Dy) + Z(xa-Dx,ya) + + + + + + + + + Z(xa-Dx,ya-Dy) + + + + + Z(xa-Dx,ya+Dy) + + + + + Z(xa-Dx,ya-Dy) + + + + + dy + Dy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Ship/simRun/theory/images/Omega.png b/src/Mod/Ship/simRun/theory/images/Omega.png new file mode 100644 index 0000000000000000000000000000000000000000..e9ed7117132542afdc9a7549d85443693b4f0756 GIT binary patch literal 28285 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 NplkdyOXt|R{{pi^f};Qc literal 0 HcmV?d00001 diff --git a/src/Mod/Ship/simRun/theory/images/Omega.svg b/src/Mod/Ship/simRun/theory/images/Omega.svg new file mode 100644 index 000000000..00c10c872 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/images/Omega.svg @@ -0,0 +1,206 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + δΩBottom + δΩFS + Ω + + + + + + + δΩInlet + δΩOutlet + + diff --git a/src/Mod/Ship/simRun/theory/images/Omega2.png b/src/Mod/Ship/simRun/theory/images/Omega2.png new file mode 100644 index 0000000000000000000000000000000000000000..0ebe7e232d050ece46bb94acb397485f45a808bf GIT binary patch literal 43277 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 literal 0 HcmV?d00001 diff --git a/src/Mod/Ship/simRun/theory/images/Omega2.svg b/src/Mod/Ship/simRun/theory/images/Omega2.svg new file mode 100644 index 000000000..c93a3d4fb --- /dev/null +++ b/src/Mod/Ship/simRun/theory/images/Omega2.svg @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + δΩBottom + δΩFS + Ω + + + δΩInlet + δΩOutlet + + + δΩFS,I + δΩFS,I + + diff --git a/src/Mod/Ship/simRun/theory/images/test_bem.png b/src/Mod/Ship/simRun/theory/images/test_bem.png new file mode 100644 index 0000000000000000000000000000000000000000..4d8d097bd329e42646f57e848bc0fc272eb06d58 GIT binary patch literal 49139 zcmeFZWmHvf^fh{Dm6n$DASEp&jgm@(ba!|6K|~rvIs_!8yIWGayCkK%>ptiAzW;m2 z9pjGs`F^+zgV>zC_p{fUYtFgWb3zp4Br%`8cm{z$Fh59%DM27eOb`g7@e@?=ozs&X zdhj2z)B6vfo`4VUC&t0x>!C7MK^DJ@kg|y z;T#A8Vl-9P$or>ap;b?$R5W2Y42V!JPIU1Rw6p7cd~pOuA=u~7Uuea%pFY7AZ*Yzy zc3|_+ym>v(rIvRzq>wV_q}tso+(2BclvL(l8%s7H+6gW zdrXXCrKzmU4?cp{yAyQN!DJLaKR@SxBM4!H%#MotA@BeZNO-4+-?bPwQhB~RP5t`y zvoIo7i6{!ef%*9wn=o)?R4-p52nk*E_~hs3Kf%Nl?+PU-H|Zxd`;-L#^*VorS%||njPEVbTx&Av})ALp?v%g1wJDy-; z*Y1etYgE!gR(hkU%_n{-=Jv3?hyZ`;95E9!s&4r`}5Q+ zELaeQGW~Zlz)?jL=-~a=9R}^zkWr;iQpFySeR7F5h(DwJW#K(PHHTC=ka8otR88e zynd|QsAr_n&F<8VzmFG{N#h9?R?TeK_taEtUm?ahisWCv=&S6ODLR6%Ye~xR=@lRl z914m^uy&hOb7He6>oM{b&C$~3gVFqDi_!dvE%S;)4kJE@3=A0krvB~+6 zA-@!}Bx<5aaB=-fd2Cnu;ux{=so{|xU2E9(J#gp;{~GwK-r`+fCCJT9`10jT^O1~q zHIaGr&uXk^Klf00g(H>0mod1aEw+qFOhO{lWp~Q`d{WI}cZ&H_!KbJ2NYK_MBV^V@ z4rqr!h~L^%Z4ReLahMHdSkG2KU|Z>a6xCMK-OBQUfh#NeuV`tZ;6z%rwq0s^K5@n8 zTEVH?;1Ui>5I5MZoz}6e-Ne#D5W>h+i`4zymORkF-H1CnzWLqJQEvR_x%1)DVpEjG zj^RFEs%$c6`^iQ>yU&gDLW2wXyLa!vWwwDO8Y$7?cWWYmrhsR&eeha=qJvxVpv_fs zJ*jT2d5G+-J>-06vg6_YmY40DHZ6$UjlMW1H!gZ?gA{5v{YGlFRX4sK1G(q8$4IH# zkv5SF{`--=9PBjV!6!vAbn>epR1Qi|qx(@%Q8Pcry#}A-M(Y3oRZMd}S^w}QFtEPy zg_y0=YUfi_X0df#IJD--3^6X!nv}aHr?)x2xj!QvtusMfQA8B#E-!#*hNL1<~ zwgdxE{gQ^JYf;5M<><&B>+7pN>XVb|$le%-5kXvo-(Q}Bb;6AvKh^{{^ZyLlb*}r# zjfEm&>&{J6xE{0s>AxT#q1H7%6BCo`u_BK)gBJ*5Vc(|z`$3%+J|B2)E)TIODJfsQ zdX-rFgWnBHNJuC+B;?Ojxn`9)0wtyIKy>IdA9T2rkrz~x(02VYtH$D$ZpX*)NO3W- zv;cI;=eW@&^r6tW{#b^9t1EYWX3Yu9gEJ7rUsW9n>GBFLzPEuq4{+|neYrg^m7i{~Slr*eFr!mv8 zE0kWnj4G6nIh0m5Ssx^y>TPoOm+YLJzgba2@8e#pC}fBr#4@U38Fh!ZgDfi6t+bqc zeRi-&YG7bMuU*IXjEE)N^L*!TKWpokQS++8$eQl5tE(&hhr4SCY-B_MeBRd6gZA_1 zPu25k8h{Ms{H|gl&uIn@e=6t6U7b(s?HAyA(CY363*agL4t~O6I$-ZcAnTSKX?ud>8mBOQGJwJo>-smUKo*_a`TWfT)eD={Oy=P=MHWP=lOG}px?!w2AQDe1R0r3>RViS!E<~<7VY3aF?3m<@|8Ayrc3qgT)f2< zM{4c#;3uP&2p0)J#jMadbXe>DyEj|83Cq#0cXVxL0qaZYeT48@rQi#wXPM61V`Ha8 zEZV)UI-q*gCq9=Diw)91#e;lf)f2)X=fekO=4!uoxhU=NYAq@!E&MYIdZt>bE+`AC z3_LZFc5K9Kj_Xp8HrCd=@AI|an8$Nvks$CzRc(I;DO?E;4qk{71SH5q{r!7Hcyj9b z-4kpLr`IN{FtW2Nz9z*$oha2?-g#@%7mEPVZuQlfON)*DA}@4}ygOamlf+^6?fZAA z;NcEMgz&=^5(8KdTMJauWO?fYlfv&)l{>K2ZM8(|pqL71Ies<@?dh zNJ`OFxpcn=UQqCHK^C?6+p_-5l(nJT@Cni*VW+GPt`sCgyi7I$Ho)cC?Y8 zx4Co0i;Iu{1>E%-xI7Ha6RQ70z6adoT$RPz!Rv3NseCTaPy-Nj8eOYBZTsVyv3P|b zdF0C=Vqpt~F>w+RFF-vq1mRgPB(BEnkn#_lM_EQQysHt8I)Pm;k5m4Ye;2$ z58yQH7Gv4kl)`V{62pjtj7tA@1R+6|yiaAd8=U{_c=WULi;1oK!lU)%*R-w|=Jm;j z=;guUXr4S}I0*+TJdbWK_D74gcv4FLn5%eb-CXR40my)-%)hy6#wE{PW)Na1n55id zL0IIDI*+Qwng|e7Y>M#OWnWUjD5^BgIx1Q~D0Vj-+h9E0pF z&SZf~2mfJH%&sS>rABb}U8Gsvx2QtJ^9zs_Zo8#$vosIX-KpY^fg}!xts(Lv?fU1X zO(&s~52yj{oA1L(1l1axEv)BjFvzx@hiXR`|CDO=!-Mb zps3d=+{H2=ogHAF?b5Y8!NJ|`O5$j%91gXL&sovug|Xjjl|xq!4{sWt|M%oh977SC zPM+C6G&L04>a6T(;P#r|-?FlKR9t!7SY+7gt#lD}B_KedZi@K&{}ko{g1n+Z;CBn9 zWEK|AP@?B|?7!C2HJr=^DIQw%kIEn&+Q8hSywaY(2 z_c?=+%MJuJV0Q@}cSDxP4zaYgB>w)s%jGqd2r~5e_@tGH)zq~r%HWxLi4LAHzbnLP zGniuY@mAQZ1rOTC06*u>Ur}7`h2}!r+au8oUBO)+wG!>mpHcjysr_3Y37c8ai4YT5 z`)_p`QST1@R`Vnc@!F|oR+~!bq<@5v>USHK~A}!d^mo~i60yud)extyigPp zl@O2=L+2laonY*q7J}EsRV+h7*Yp(HN8sxF+#}y@8Rg5sGUapu ziuX-^-F%%b`A9SWH{sTED=bRX?r>bngZ+6V$;h`?n1F-TnqePJs#(@MZWMXF3nfH> zLSaHaowCUr{axp;X;9v}6i`hSBMIGN5Whh-9})3cZ1&nScsa%hzg_cj+Lajj2}k>~ ze_Vg$d~4FvpNPe?5V-M}4I-v_bbAVC;a**vu@7zh?O2%pp}hrk+0pUwUqessyNBCD z@M-&(r+5oGan|_?KM~)Hih}G4l9ENy_0_AXP7Y9yJT$bB^=m6C&AY9V5wTr^v=>6S&IB(-UH zwi1e+DiHNDAt1VGTe>1=;bFP6yZblbD*(-%6e23(=lOQKsw_?t8xnL8HLD%>c)h)0 ztS#SaBVN#;efVGC*%X`!K|<>bkPE^hXr@de5%jED-1?=2aUc^2|{rNDHm$x2FJe+4NtY zJP*R|57;@~B2p$sLpHvj`#V=3RcUc$pCR_NTEOFt{gzxLwj_(O6^1mZn}65V0{kAX z(JD;`-w!5p;o{)HlyW{A^nQC;=W&|rp*Q|E>dP18({dT%_%*}TwYAY!KfhRJEkaOK zCG(YXMhewfQ{OuLF3`>8OBM7Y1c)pSUPck*GP?xmi1iKpM%FrfXZutPWJq7g@lZZOvS{6Vb^j^ zTcTCeIhQGpjzP=@^dBA`_5CB9n_o)H%EHxC;8#r2OsQxn{ik0zJ5$ABBpjy3#Q$W{ zg~$QRloSzx^Z^=f(DC&{E2(^qXZ01k#l#b0ff@Fmp?{i0FJ3FP%MATM%9V2&;0>X_ zd|S*OO;qQG{cl#eh5BkcPh>E8NZ9S?`!>JFLf;v^dPJFYmRyQ+K7b=ZSoMc@TvnkB z-^d138^->PX5kVM1^xSH4&>n~xXlj0>>Pmlf#<}3TsoYT2TOUpbv9zmd#zBXvF7?1 zT=__jG!b!xgqXPaPsfeEw|)--aLEVMr2&ZHU&?urD&!L3#Qva|!wm-@$B)j>VxRSzKp{JXrU@)G-vbz){PF4JnBD4IC? z3mvxyuS}=+_uZ8C(h39K{&mLF6V*#Q~!O+lfU>=ai zJYo#gocDpx`apmW&MPY`#{pK#fEw^_w%M!JITc82MxcJUhoe(di;z)J7-&AmDu6X* z5p=scGRU$2`}^Y$K9}tMT)tQaWeHxlgVafO9=oL?@Ty(*vVEmJfFPhf12FhcbB|ZYYac<9#Cl(!FaY{l&DR6KGyDGWdW&+qjuvF85(a9( z8;=uXi(7!R@ZTFq;Ti6JjLZb_B*#vS(Fe?p?6usS90nvbtWV(J3Lx=LFMv=>TwVr7 z)!_W$a%(B4<%ASCnB;*)=IoC5w42m1hLWSZdMlkvTIg}5y+lyhgGlhP*yBa+7hI3J zYAf-muOIT2R#^;OyRW)?dbSF%P@V-Rb;y+H)uwp_3G@RNrYKSQIjyv`ly}f-xy8qo z(hP`3fFZQB00DrQ-L40rVg!7YtJ7g&hqHf*h0~D~f-g4u6NZmwR0=+|Ta`A`+Jr?$ zN`Odr*qLB}vp~qv(O*%xzvS=l50`~G_Z`1~vl(_i5%4_gEuia&2T3x!7yUxOoedEQ z=@`gXV-F0xtWom=hU>k`;q0}WtE-i9dEvlz{kBZ;uz~rlp&#fF_pKjpIQaO+OKHM> zzCki+D{_7hPra{mG+Fd0i20|=w|aLpdF(S5I0Vfi)nyWb7s40}#3=Sw#iJ`Sxa=s7 zuGVJxhZ5P1%0OsnPnxtr*zM03coiS+oTBG&$x;hDzNbt~v&cmc;kT(rPWBD})c}E@ zVN-O1hg+P+6JZb%71a}yyU{<+HBz!;CJIu)#@24Bi5KoJ2|wQ90R-(hUh8pqeDDF5 zbfR*3m1d1~2)6JY4tSM;lY4OYPe3UA2G*uMSV_3iBatH281f=xC##31 z)wCNmYY9!V6pLnokeY3LDkc^QZ1Y}Gk_eGj-?nP2of@8HWPs8S<+)ak=8p7wLJmBf zKH==P%Y2 z0F}nXb1&SKhogCj^U30wokUONf-nc1g#*p5kgr7Je6T>0^D*u{h^3$O&vNB{gn|`- zKjZPoL7=FQ0hrD&^qf3)f0EQXTm+J!D~zc2_RjN-RlNG-Qnr;^hA3K3dQX~_PNAyE zr`UhZs4zW0f~d-5inQR=AV5xoZdTD9riZiT$lIXvUADYQQ#0{GK4LJ(lWh9OL%+7( zXkAY8YIDVMbEMfp{HweB%jN&vL*10gIhq7ky_))aAQ;B#WgnAkv>Fmy?4ygRWZ?;* zUTsOBS#22z)TKr;vWOzSOwt>g@oB9$KT4$&Sk!H|epAj}8rG|uSz5jZ0kT=vYNqx< z1|QEY5gD~F-yqWX@NqCN9g&n9lAoV>m;MN`neS7k#Eaf_H(h2|q;Ok--680eWhDNd zS&TutzDAfEh>yi*A7uC7(bHST@X~p~Wr+-#X>cj*7;XfJmoom4Y|73tD4<$xsRF9$ zN@?pu#cWuG$EhhqWU;}8LvT4?IS&FE7Jh6RBCO1h2Q@rj00J%Nj8mT765oC|UNh}2?vtkudOna0OO^6}B_Iq9e=tHFu>psq z*gVi-4?ND2+^KoIm-lYlc^5?iyO6k<)?QXF_-Js@J(0ivWJ41>=c z_GZ|f>ir%cATW?_3NNIcK@Q%jc@cGpTF*e3v~uHjCu5LM++Oe#y6>@93m71NOWkX^ z!Pzj8c}ji4MlBiI=tIlelo3h#C!aw%ccr*?sc-S!*!30Uuoc^R8`_6W5&Vg3>BpIF zv1aveU^l>RSx$>FWVl-2pR2|tAP9tOa`5H9g?f$`+}6SI%v!5|=+eIc2m>{#+-jNy zI4|T33=FeEcE-l9;10mu-RbZzl|n+fAAErXjHagHC+7!c4C8L4wHDpD^;j3DKa0O;UwePRM{iogXuDAER# zYo`Mo!x_L*OyqNU4et^_ec~o@sUATRXQD`cRG+Ch$% zJ8j8%pN&d_t_2UJ-PO_GL~ffGmJ`4HLDc_VUZyNmE0wUfXZx7I^5d^zjAzVuL~}Zi z(_@5|YY7Z*xA;Bn-B1Fg?kF@}Kb_c8J)(DEm1C2^^hQ9QoKW>AAXSon;*5f&=(!ZdlCURL3ZVvqj%aV-B1UyI`(C^5dkun2OICFD9T0t-!Nc0Em z1pgt(FUA)=ctp;l|{5JLm-UAAZc$?XA`%KRx{u;GIzeXP@2eKs%hApAdeb;B=5+|C2)1 z;@_ZUr3g~ENUIhLZd?JX1%Uu>Myyn~IorthdLse8yl@K`aAj10G~$h}`$wQKQt7pL z&pzDO_jiVzxENg7UpM^4m~EbFzA0Gnx}Q`NVKMWk%Oqo?Pjh6XjRMZ{|9B&2N%FED z(m>QqD2v=&k`ZIH9kwD3Cf8SMl4!Q-rftyCqL$Td@2lQvoocr}KJce`9q@)z3R4)7 zH!Da|WCYdttv^v{tl|45_zL;0s|-fnG-*G{Z$4)QGaTx^aEgbiCKOm6=rokxXbW zRv9-Mtdr!Lu5oUZpxLk zBh8JP5Bog&r>1%7@xcpHiej&4I)Zj;SX&^UKQAa#N^0-QjFVXb@tt$LU$94gO ztPQX0UgE8s+&XHB^(i`0XbK)}u@(|*%fE_oEnbjHs90o)yK57r*k}9b1L>@Nx0hj; zbG3FQ*s@~W@EL{$ou^9V|5pd@hY(Kk*=~Lw47f>A9lv2$?r7fm!XD3o>+en>r>B?U zXp$j;iQAiv#_>z3>nF9*?Ils+Qp(+3r9fC>VXA<~b0DcpgxRCzfHX%0+}dI8I3@;e z5?X7*>L?wr%IXHzfl?x?B;^sS9qb4)6l>isH{s3diQhP~XGc*Nfi0@k+rQIJS5^|c z4xtm9d`8gMbxU3P`_MVEgMtwHgV*6brYZz2Ct$IKS)$pj##}@*xmTRum+b0T(xtJr zl~^nb)387d?X}ADcXHej`F2KPqphn?k4K&rB132vl zTwIY?P0i-S6iXgW8Gp3c;p|sKv7-r_(VnMzHw7Y-QTgZ&G{qYFE ztP}k@bN~JE4(;kfYjhqFlJ1R&L4gs=u$ImDd_$4U*)E7hrvct#0}V(4ZtEEs=xm(r z&EkP3^3a(}y7$S`gXPvJ&>Dw#3liTtK(QzUffJ$9p{%>^j%tOk#{3gwrjx z*k-R{*WH=&tfrSV;)+-lpJGwa@i+Es320t_RD3TA6yQzLo34X`2;!Hm6RYy!O{pp= z)TM8na_=siU94EJT(=@KzXbk4yE{`BpRJKqbUh@TE})jg-gfq zu%r?z8HL|v&Pmy4+IYLiaXm9x5aKk)z$~i>g|3V4E&T|)l-3Pc-X;qIqY}VG$;M|; z>U_p!X! zVo?f(0}g+sp4~f9q=5&q2VGEW@dVtnvV zgH2~J#@2%Mcy5GG53{!V0OwSz@X>Z2G~K%!qgB3yA zzbmspV<1Qo9qbtSzb8;YE3a@r*XF~A53ZDqTwDZ5s2Cz(Mh3LZ;VCL+@ zohS3K=omnugCirm;UZ=qKCmGp6Rxu8dG@dU(qPRem5=7@7swh!CfXFOf9kf*32juR z(6G_9IB;{Y{4Ml1?_riIvzYM1+kw`IAN>9#9D6rD;Uq}NsEBQxkSunC&%|rkb&r<@ ztK0jbhXIEjlZQs_pOFPT@i9f3u*bi=nDwP(ZGL47Ghdd>`KVrP61KM7^Y{?Nps1*1 z9Cy^m80>q%+vrF6;lt?BrP^{&<00a*-{He@P;C`sb88gn(SuH@(#_ITy^~qtv@%wG zW0>S&!KeJpDy!)sOD~XS@Q4KLd)_6rs){qmZn-72wY9YZI2IU}MwbRl=cAI2AKU$r zcm+mo5Bt$xYpE)-=((Ef6sPj%(FdXzZZWAVD9WYR?B*Et^iBTY>aSO!fo|D+s< ze3DW;SnO|q7cL>by`a(ZHk@qxs6jL7t)h@wv8JI+`i~_~Y2WJ>AGspNZHm@$UMw&5 z3LG*r>q;UTUf$U|Z&iG8xan1HJ_-c}eI^)Y!78Qm5VE-u$@wU4wXR2Zx8E|=R=YfK!UF49}5?nVV4_D`=boap;5zV zz&n~f|GfKMyBx};RPk*Rf6>+B+9bonsk+Id@~t1?=g;fsBoFsQSDPsdYC&g%FKr^7 zw`!MR{B9GDkyC1XUaH~s9LJY{iwzj8Q}W)6q+tm0i7u9f zQ#Svc94_eNi3V9yP%+EOU^(8_H0%dpJI-ua50<#96~sRIR^=9fiitRsTE0s**M4a> z9NOg&LhnXgW(@D)!<)o#nKN5yW(52^;y1=mfKoXE4sgde-*=>79_sG?-a+?t!@4sV z_v)bW5E%IZz_M705`JKNB%4^0%M*|%E&EjTWFkK%f`~L?6-k#L2Q+%SzW0}?*1tLW z8)SKXVKaLAy^Fc~ci=|X6pLOw9VKY5NJ}HBma6s-3o+(-&27ZUL-s|sb7i|Cu+^+4 zpIx;+D)-mgBCxhR5%5mjkY=`f%g!9$i?AT@wVN7fKS_`K^XWKX=r97Qt!6o0QVd24 zKh5QV5)~R16?FpKk;Gb+UkdNQn2I8(bCdGs=D!A=9AK(TPB&EoQm4hW6&|psc5U6Q9H_W=2ZR^{SMV@N=9k&S|6x5D(6H!1 zhI+!c?HIPyNO7>4t*nn;XBR@aE49TVqu#m+yHD82FWK9l}@HfW)x!rh8zL%G7 zja}h)=MXf(Ea~mz59HCwhH`E51E2k|VJ<8B6UdT>Br_ddznfKv)N<9fK1|)O%l7gh z1YdQ$X%oU`^Frb0XX=7@4qxB4)h?K;MZmByQA~>QJ1=r!H>{c3VK_091`{9kN!eZv)QX)eps>*73sp^$26QqYI0QNIJk~2K zUUpq^2hIJ_)P^;pG1kQim;J1533>$^N;$A34ktDh!zss!13p*eC3jJ zEw4b&Hdvv*Ki;8+Epq|h(32pH8JTnV79l8f)UKOt+Y5#`oUfR%GUXp*ydQ04HB?2}XNE>yF zvdOO`spe~u@Mw*1p6{RErTf8}y_{Svp1H|7)itsDn%eG^Qjh-{51=rXACQ4 znekJF?BIs|4s0+(^~U?@`0rrAanPevQUw{YJF6JUt6B85t13~ z@Fjs|cA@z_O1<*eFsbJoWT36f^T(A>-MdK&WjtAsKP9YYrbegnz&~rFpH8X6n=>Ir zO%J6+Z}^Btr{PzW-Qx2?vlurA%M|K_iqyg366dln$fGHSt6Ox0R!r(6KV2$gcU`B8 zQ|f$^v|E@;`X#ak7pw6?-!O;&H-S_iV#23>f0MN5eM)_2s;T5)FH5f-o{d=(%C09gRA2<%iQ^RXIs+=wA)!J#Z6vMUZJ(L%@U9Aa; z-u2i^HQwGiWvDV&H(B6;@rXg4`rudpHDVnDoVM2aZCIPWec($Rr60qROI4_?wtgy; zv|4ttVi@zxk<5=TFn z6NNEp;sX*8^Mg_V$4Xq#`rBW`H|K5B2MY%SSL8tD6 zJ0UC=!@?)zH5lU{$B~)TOwu^ee(B8TpF1@~2|X_?NE%3G$P3D5R75nN`@~$To%FX( z73vrei?6>XQN8dpAkm0g^st%EQ(Y!A%l}Rzow}s zvEl_7@o{8t9B(INLAG5`=(lTOP*rpN44Rz$8+F_SuaUiPi<@jls8Xcotj2${Xs=-K zFLmbFM5eAL=yk4^&?e;u*vuk==?qQ4+#Sg6e_LK8Ik-16YO9Bvjj~XjPid(VG1_R( zfR#B|j4Vctt_5Dkx*_1=jvMO;Nv5GtPYRij@%Vyxa!MuIym{pFx$(?hR|GK}W-zzq z>bXHjLA2aJ5A1|mUdOjKeCiK(Nky0Lr?exrr3=MuW|99ST-fuf8a1oeb>k$XU=)Jc z8YA%N;0Mv6P5<&;OJ%$P-^|dDw!a;g9xH83j?9i`b*|bWh2D4U3c2B$4=2*cEnIzZ zF+G<>>g}JN+5L^@mc)ules*^jqiH+&>^&fn~7t5`+P=2fGqil1+tM3{RoK$STF4}j>?Eq~z$g?^IU zfWdUu+(*t)-xdB3-rh~)!_hxkTX2k=WxxO=sCwEM=t!0m3hA3~2@hAMxFzc|=}&ep zB1p~H$V}!qS8iOY?}qqAvLxh6^-NQj4#2cWnzs`3a2j)Wl}L7=#qtBTFdHBvy6~sd zS>ntl9zCA@{(YzRPdRSW0ph%LYSFIHKj>vSIUy5lgPNFgy73)B{&;lS>cWoCYHN7= z;sVe%UNUfxw~vj%X4I?6C|Gj2TsiV;`2!H#Hwdb|x1X1pM%4dmK6t!k1qi65-~x^XMkMWEFz+V6q`u zb6maCWY5EcVW1be{f9>MXWyp>!0wK>9?xOKjlETDnS1bzL5$Zcv&jw6sfR|PI zT};o%(ZBpm7&GyyTop+yUVOS_N7?JLkAXpK{Y5;-xkgDGGNjH`HqsJUOz)#TLb#bR za5#c<#$9Rk>Zqb@UP0&KF$Jrc7k(v{7PV}BpnbX`17RVtF6C!!p~qH_h#;sxDw9L6 zl#zZ3-Ku0H-@85Bu$qM-$Q8%1OqOC#6c@&C4ROiO4*kz18oTBMkVK4;zy0(J0tQ4w zcMu>zm#$Vgne^#@8()DdgbgA{+qgWEyueSPt}3?S+!Suf*-T9Jz63PO>6)2$iUWdK zkWR{C^imTI2aU!`GVk06^OQxBxG#)~NspRMTD{M&ZuPefKC9tvzxg}ley-8-uMVZ}pjEyWW0?@!9 zn`*z$ZG-VDj#quv;`!cFWYhwaL1K6u?8`Dk;U;qLpQ_4$z%RyS82+xWjf900@)Tss z)Qd)oDg3l`18pZ?N8@4h>MP<~)F_;=HCQ?sC#3s6_j98K5n2_nk3dD+o$u1el2Ft5 zJFp9rIA(vot7-3B&pHAe=AXfD<>pdPe@m`KL>5pk((#b8G-jDwk9T5kKq-`S{QFrzWYUyx zW>`4PqEqH8#vgt04_hxXdia0F*B@?kU{_l+L>W!8=!m9?CfG#2$(BU}{9d!RX6EI~ zc7ZHP2zx=3y+OhRGylTafv!6Oy{ZgzUS43}mtG4OZL#n4MgWac;b^q4f9rh>d$|9h zk%JLIDZIqIHTY?xPvmsd(&N~WiU#HS6iHEWXA_fjfP`@Uo%8HwZ*CAam|U80G=8N} zmeD15y46p8;_~8KL(U=!a_{s-vzPzpBM`A(<=KsDs zT?k+U5=!LuVUcNalEprk?!Pri$`aYf;0JOfBTyjBcAiY*`rhq$%giti(C@y=0F`{h zwaPuxH?ks%1 z74PmUE0x?J4(sAy^b>WNH1Dx)vY%f*qjarW(Y8Kfr3yv74-^|QtZ-#MTJi6tW!=hAT%(d6Z>#aG5} zfU{7$6rCC)l%bPQWnloj?vLhX-kV}(?_&4B(y8TrGvBDz@<{`@@(nZ%C^As$uGnC{ zjVag5yHk-r-z_~hWkeK<#(viUe#!-w0?YL{Q+;Fx3`s;wyiDR%_94TeD*d{L3Jf&+ z-D?h&Rw0GTTtH1x#>Q|6XiAaV0V-wga!ZI@ZNT|3*%Ia4@)u4wED-*G&u@qP%#oGYEy(0F6t3FPKPQ@O+RV!8i%> zHiVWrP=Eg1iQhw8s2bv;(aZ6#VK92OKxJpm^Bh)T!t6Sd8$iIyq8dBFUR&GP97kZO3btvjuJ&{}h4QFyVN(lu6|OhVaE}>^9IAm-=W3h#w(p-f}#swK!Jx+?vpO~1E=_jB&w#3nyuQU^2P z>)6+EjJ!1T(OKq5@xYTc{%Q*5m(dA-ZFruqmz&0xU+jb7@d?M96)!jzt4n1zMS=xD z(#Q?4Xq7?whBi<18X0IB>7BSZFn#Ez_R^|YtN-bl(gr;lDRap1Ge4Ed_dn|K?mj59ElK;$bn|k zkBE!AL)%{^Fh&<;;p7nusGjkMjCV+bF$pXo)!8x)&JMRSK^J4Pjp$Dis+t8E)esX{ zKBSW-usT6;p?L5}&)gSaP?c#>{_1rJ^EjPw6hl_Xi!3bI6nw3U45T`|zq`=PcwUhz zgn4&gyIUx+&Rn90#%-tCKRQa-+=WimSNkCNid@F6il-P1r60B!fha+RUo|YVcUylj zS;M=HRS)YGU7-p2d5L?fKhk7RtsPQ-0vvYyr%Ds1Ilqs!*hnP~wXARDD+=k-?Ct*NuqV;4<~WYTS#SyU<06M-d`wHbrG2c1vz z6E=SfSR*(jzrPlEOQP(a_Me{AQ1 zfdO`b{^&Fu5;rdxd@#4T7KH@nXyT_!#PcP$a#C~wCc<40oHu#N(dMeh1?mk0iFr(aw_im5Bp)~DM65KE z4wKTYH(U&pkDUh1`o0{$M*<^tnQZ5>9BF^8+6jOk{9oItE-SQ~o^*6$DzWx2HH*Ce z3=fO^v9ZpxJz8e1zK$+%JXGA8Y3M!gSQP^fMM-??J)sVt5CD*9R3ySo?Fup+1{9{b zxcxAKn8pVNH(k%C@M-PgB%?UO+-5Bqv84HWJU~O4rMLCXhI*aIFZZ6}GySV*@Zbt~ z*OKIN4E=bZ!#GG-V;CslM5?IU0Sly0sM0w{d1g+?E?_URu*tK%thbjT%FfPyQ1bo) z1+CxBeY&J;e1nzxmDplu72EwuFZb3)6+%lpRjF0*jJk&zwk+DXP2=vkqzt{`8z)*I z12{nxZ;Zt=@2p8gaPr(Uqs?QJtXA-uB-pC@4YAm0s$0JHCS?9*m}oQKS(TA3OfkRN zG}9fivxbTZ8_O9-x3F+*19R+~LqOBoG!iV16x>hG;8<3{_DKP!fzbRTA_ivGMfYM5{5$Sf6=$? zOxpe;GWlaPpPKOTMBA1f=zi8NuL^`5#@xJu8&0@4^TzK@E>h z08FeeaDRTIf>;0g!OO!|fn3gHkHFizlMj{l_}D!85F3b(6u2Db+E-G95u@4Wl3O2c zp`9JurG*%68QHOHZ zWZ2oq7Ij-^c*perf{?aduorC(76^7d!O_!;UU~+Rl8Z;H6%$9G`B+zF>+yAC<<@F? zWKpkW4NO?Fl;B0n!NU;6rVVTr6|w*u-`e#2^5rqe=!Z>nMCX|sLj^uupFp_=jJK7X zt=xLFWn@u&Z~kDOXUcdur<}eADIrImVgL8+_i9%g(m6|O9###{s88eWta6c1DvSBC z%tS$s&>$@Emb0|19VjLQg6VP!9|_Gg;A`QRwuM!nnxI* zMY1yJiJ59j2}EH7Hb>ZM0huBcU8{{3b9z`YO(8l7ctMF zjvVk)R2c>JKD@D5B3q3C*X&|6Un9~L%2KN3$_#9;MU~zkaz8qm__y!22H$;(y*c}e zdGZbFC=5T7@ujT?TP=8IyR7VjjUSd=(3~{Pd8SvneT-H=BYtR%>OG zvxO7+)qLNVS|u6>NLDrGrHx@g5&LYCqB0*CHs6f@re_6E6DvA*4q5=Hp@fR-)oN+( zh+{Usjvyh3VP?ZVbj9P>Yf&sE*wH~FSi8SeWe4y+gPv$0`Xt>8uIKXKt;|uENo^O} z{1^+v%GmUOHUU&r!~!+OF+?_*E1(y5oW+>Uo(gQZI%(L@sJ23K*-Z|+Zb=WqvY|-o zx0>!V3JQ_R{=7ez6F=C@D185l(2V`~sQrQ>Pm70Pu=O7L6^QIuB)_|t zTi!fYs2+QvQP^ze-}-msl)?O(s~Z8C=xxrnAoHnmZ+e(}^1b&qyd2Z8C`T07PJKT|3gqK~Yi5+Zk*$j1PMCw`0;kN~%pJbHU zE>g)hZnX;(ENX=NlSS*v@&bQtg9~7TqX=o4!1b#m_f5|P%zXd*LOZ!pnO`Q+-N6FkhWge6TA&CU92WKn(QcpQRNKVxrr28%9xIi%hxM{x7#njekNfW|M z72N&Ghr9hPvlrhv;|80G+{Tu8vCo9ww-Yz-%x5B&G(|S*vw-w{%u9I>q0uFxnPUPIN z*572ulhS;ikY2g_oWKbhW$pHZKZTO;lhViwsM2h`a@yaB-V`{_eg#I$Lgch80pm5QeU7yOY43SqayjhK}GqD>h&yxCZ!bZV0nb*u2aClF-Anx|dEfRQ6 zzPhuU0==z|h+9MX8@aMCORe>a5+yGP&AO=Pb@Zu53gYT#aE0563}3S41}f_Q^;j-i z$N=5cL}5Rn?kLJAuw|AC3Plw3y66ONrorK}2u7)oz@#{Q_shR;X#tiiE8&aF5a+<(1!$f*oE!4U{o$}w}ymry0Jy8LWp~qg{M{PO; z)Q-Y7ZAuvsg~J_G4+Cu0J)L9o(NU$tW{a9KU<67hET}L*rwzcHWPo!(+1PNv){S0w$7fA~KRHx? zLmWC{1-oO3*!2JW1_%M(ECP!%%;71Q)f6&>jMuS~d=kn72A`zlRQngxW>{1Y-yE+v zm&L~7yQ#JFT23PFOmPwM8^m3+3$HKsTg|7UNy(vNQL6S2lI9@-vw;+Bdst-A{Xgh> z>!7NiFMRycBHi7BD3?-+OE(BeD~%u^-QC^YAqav90#ef5AdP?^-4~Ds>Gc*bLsZ-BDr#=7MZ9 zo&w-Sh#}ZTHXpA{D%n^RtId$e zI40~Ve7tslCRzW-InH)d{gnS7xQQ?ytJZTY0uN5<1dRFfVkZp%TZ~h}IPv7Mgnat6 zxq5<6#QeDcNw>DXL``ZxpQcT%i8o$U>A5d6V_-+*M~nR#%^u9)Lgh!D)m+D}{|_iK zWXW40xy?2@RixSl%#KXZMgC(%f$km8F)po0eypimvnDtBXN^dinGnKyZ2vW_`5z^7 zS+NUE7`tk9+ZIo{}gBfK3K|>nZSGt zTm#<=tUZ10529vW1`H}g?hmQc z^w?PqK*2!Z^nnmWnn9cQr6crhD|K5zd1x!31)lI8Q-knRewmqA;B&^v)g`<~-y4q? zXexm-*Fecf%H~%1ydZ=|5M8f+xlDe;1~Ih($BzEPiA;Y$&07!m;0B+M9yB?qMt7}B zidpZKre2feX59WR3@{mTK`8<#FF`XNoqlG3o~kOX-w89D!T5fob3)`71JX0{BtFD+04dODXY#9@ zqGC5NYKOyRaiF`SKWnx>-yo-;APK0|fc7WWYyN_fo&A-k;zuB%!|$fVUZ*_uIS35{ zC5E!0St%JMv$_H@FH6;pv>Yb1LG$%%dzrqahy5i#Omt{)qN7>n_9~ALO4C=VV$cqr zdswrJDS`D-k%c@<_W60;3tm6lYHbR74)1bW1mohW1g`t;GfGVYDh{G@{db#ogDWsB zQHhh^T(fJ<^*!{lW)u15Q#{l2&?aZL*v9XT-W)pdZ&X4?e0rlLG*nd8S_s1~18U;X z%^iP6!)S(elF6ol=)v@$rqh1LINJu-^J$+lCz=BWkcqW2Bgg;!I{-z@x0RRH3$AX1 zPlOUp`^`^9!^g--o+)9aU&2_g6OuUEuOG;AJ32zzociT3V$+>in9_nmKB4Z#$-$#yXxS4`53c57VByO}!x?e_=3v3GuO<$fq`s$N;AOHM?33wuA35!{#00{x!pT`bbU zfEi`8sc-Vx@%@OFcc}ZkNvA|@PjE;P;W5Syy|wK8H-%ZW56M9=`S0)LlTZ^X+~YHz z@IE5?J(czrIqh>D=frIuZPkOXP$;EaLiCF){!hFS3{_YxP^pyo!HzG%m)W*< zCq$oY6rN%=kv$%#39~<8sjx~5;3f!3_dY3LSNh~IBEE;bG+1ge&ri?$i_gT%xav9L zzt23PQRQOSu{0Ahgp5@c+##v%y~M<7ui|nH-L>9>TexJoG`86EbVG<(E<%$kC{^pb zs<^6{!G9$I6bF7SPogTK*iQ?4#N!e_@9UN*aD*=#>l2Nw^86VIRn2{%W<++Be}uN3f!%SKz+}IEFp%Sd5iA@u~N8 zp5M(zc?D2?UYY?qiEVYKw)Mip`9@PiMclP|m|1QX_44}5BPZ(P@$2HrYuBHT9LmBZ zXKWY2!z~Mq7j4k~@>zvl4q^@bofZqii(f9bt+rs{LF(bOxn6DyYnTNNycVO>Tx}#( z#HCWI37%w`5`zv-BVxzRv_UT6tPLgl_FAy?y-oewtM($*))h&u04^Zp6>S{`%nPj< zQvujAzV#HX`xZk14~O2Einv)E`DaEghVz9n+s`Cr`4MKH)H8t>rRe zm^12>(1^Y9HUxSWCyz>H_&*04en<&|scEJEqpEu*{`b)lam*p5*4X0}Bs~22+65+MvkGcaJ`apQV^C$HS(xRa9Z92Cg?>ax6!K zlr)4%7Z5krdJV*Dzjy%=yBdro)E{8mRqnY<=>gwR|_~pw2f-DqeDu`0xCV zBNT>z-hA`uuWNVht<82*)1DFL4_TZU1$IIL>}2EcW7{*zKLi*S`U_t+3;~1|?CCAA zsI|W9P@+oog!;iMu583GVvB8g&Vsw+DCW~j_x{-L=R6)WLm^xw3Kj zoni2OGtj}vlp@*KkN&x;0(D-Dk=JNJU@!JX!juP5>Kpzjk(qMg_KCf{jYThMLLJM8 zsVnVB%d0)|29hQWz~kKP&SQcnHgC~W%)$Ny@SHSqP<^17i5eVs9g1g!rj-42q?Ep@ zs#C&nngg*%Z|Iy2ff>9ElXLAenh#qO!cVgf!o*6TJGe`^n~5Q<&lNVDaO9G;nv}E1 zqo1Yn(jt|qU2eHVzDNn;u|O6&^yd~=-MUB#0c#B0i4EdQ)?R5PcQGRAK86CZw-*Aa zYjUPWHuj`Gm1&q!xYWXM=T&x$C~+hi$;K%WhrFt)tw*&V-2kj?Z|*u&y)v1(%!CSj z$s=j$yb|2yI==!pyIdPx1$6=acitpO)b4DFY^PGz%j~>|Nqu(Gs739 zK|?U$QSI|LZ!{sgX+Z?Z!PR6UeZm)+rbZ?fIexhF&6p5c9;26vs5?{7pF$tjbOfzf z{2Jn07a{%6u@N5JkuV!sEKqJu^ridD(Iq`*>k6v~TyW|C*}P%sQ-Sv_K3^DE+!-k; zdYUr|3uXp?ya$@JG#0HKZ1lNZ#YaEYN070Iv#-=B|egSZJ~hXgI?6j0^k)7u8zYRMB`gA3rP%ND-< ztw4PA3n{T#hdqDC3N$QIa+<(OJ&ui05B@5Ab@!e+4FABHCe{4qvXYcrgaOniZXkwxZ41*{Xk2ZV`=DEGo-ocpuKYAVTnv-Nh(~l?GTe#7 zSt$$uaTZ^n2k?A*NU1?E<3(v{hF$S*MDy;Y(r>QVQBW9*g~9PE;I%`~v&Z-$H^HHl z4v~_jB1={Rk#!7ihdYz((+>%cjbTKo_^Vl1GzU8mmFqYMxlfdyVny}XyqKvWoi3*$ z$5Uko6AEPgG}BBW*Ud87^=c0ZBRNR*YZ0qMuEEzMt*D@;hYo*>fg_#rcl!`p>h4O&xRE)!_X_SWA-5nTS|(YjCh+(g!W_QtcT!I=hISUvl6Z<4)A4%`)`km zt~EpP$lRD|3_<(^3=#Lok3%V$E5tb+?34(0;&{QKhwr787$3n;Y>rn!jqU$^Q@@)@ zM_UU;uWMMDkCF`g-{;9`c^Zq(E|74 zqSl6pxoqGrC6*>YDLWc#z=WFbV79uW#}&o9Ykf|^!BBK*sNeJ7aJ!ngznWoOhGIRO z6`z1;<>D6pkZF~trsGTs3BPlHu9kHq7!iCEOMj1;oT(@jL!IAY@y9~vewXIVIm7=3 z%Fh9E@8K%b&@ zoFQFV3ROO_hSS@)0{6qO`Da}8UMpExWu?$I+b|;|F~=$gq>N;Bxc;r`tvy3kjNQEB zV@Cj5vcW`ydw=C1R+LiG+pv|PaRTAB@P?wU`N{nY`?+UkTQ?&rviu=xWZg9yfi12sHw z>pM~M;YzQJw;I8X+3eRs1CC}M!1WHP1yHM7FVO_VX48N_-*7x`j=HR^jbp~9&AJ&J zkpK9~gaa&orQRH;jGAZG4eJQQRK3y+AzV07@@^aCGJF@DgF$ihCO~Taq zdc}TST-PP)rLLvn3#q9tFr%-zkotr0r3Ge;+UH-2nY}d?OsLkLDf!m-w3~+y94l)H z(Fj2F8xfnK>a2%)R{c{1E|8;-H(K)tT}FzSA1sqxlN(CX{4Dy^2X;ZEY(XmWgv#UN z<7nKD>K#QdeA{~Owcr@Gryjg$z}WePXqU&n43YuiJH`n!FbKec3#T;u zBX_{as2?jM`*3_=pteOA#?$pv54Quq7-^AJ@3kAh6Lf5C6e3c`&#OFE1n7GTW;fLl z=rYF5Kpv5TCh#kXp8^}=c~E(M+Xem_FUzT8Woe}T5ihNr;tMWDC#S3CKZ|X+yfSg; zF}l7V(dS#N45g$3KwuENb_CgLl{<;ClkG<73Z)=VI0CAGz=MAIwUhB<;9_5P5GS%* zgdZMg{O1b@IveeFGr4HPBcJ^n6$=YR>HODOWjD!^zn6My009A7D6ry@2xDfs#(bZ4 zxHHuto_n!|#`y?8QQ@9LO4knS`2Rm4~$j~iKjanjI*GzuFQ1Tg&ISf!eb5a_E8uWw~J{G@N z|HLvA+R^GTIjh_u$YtUR%*sKiWU7pnJ!c)`1_;Z7Tl19CS6R3aKD6Y%rDJ11GG*Xe zJ3DeAlNKO0@daJR#5c>Wz2zMF15tHK{Z*PWvTQ6c8PzF-ADnlRQqXFRJctN){e~Ug zOAR!T5KA;|)GM|g%5xI)$F!YBn1)8;Be? zdx1r4^rn%GeN(w^7nn}kFoYa#ez2pY3EXaA>~ttk5&>)pvsAL59=yF5Zb>vF z3K<#xAeQ4an>JMPcNSUL6MTvG%b%=dA|b9QEc?s6?SMU#*nsd@4h0q)hSTx>BTH0z zKfXt3oZp+jux0qg*Lp%Q*x66+#i!TBWpdp+9eU*K^-yoFw*4ciPAB1}1B#XVj&KGU zu*ujw#_H>5U3~Lz+=M7!L~wD@S7q{MzpG$Y5_JByKxXBi$B4qjSU7MyY8EaQVK;vm z@e*A|@(r<|5o%ffN4wok5z=Se;1H5C|DMBtTe=71U;41n(X6JXR_sfN1Q}7-i&={* zUmFQ!2d1r`?n+g;KGda|>{Q(O24i5`B*wtD9WEtZ z8U)`D1V8+^E%fijIcR>GZL%>|6J>W&X7UQ`SXR?a%tv_5t@_(qd7vwW9o;X$fAE4y zR^oRbp@SgZO!bd?|L~`Xv&8+{asO< zXr?aB54YT3uR<~3Z&;>+01)I*_+6iZT&5uMgE1{TZCVH9um12Bpltp644X zeNK=qKtYbD{bsGV{o|(2^$d$f_>=3zTD;~0?NmD;37ED271@y3|jJO+rst_ZG6^rg`B_5g3s9+ zAesNrG|VS7&zr&bwm9HKDJ8v#1quNs{iVAOR@K(zMv&St!lxH?L@orKZ}%U1%)>La zg%35octG|>QrGmW9~V}=>u`H`X_!;l;N7Ls|HT5lFXOz#Ua`OKMT-!+sRawK5krOI z;_2G!AXnlHj64_^`K_rLQx(?|pQ78VZU{#OE6``Rc7BkW7!RTT^LZf!`#c%4E%dil z08DiAiqWQ~9>Q%7V;XNaFAX~>D^<;(Qa=y|B909Wz}ah%f_qVP`_zC>uYa4H_UH(` zSF%=x)AZ3X0i0?{d%y=u{LYq-a(9eyO)*-c?UM^OcK9y+6HG14J#WgiK9o`e8(>?e z;M~lel>Q=2r6CXJ=%NC*|L>k~2bV*N-mBiSY929%$^e3dy}h}xMzq=NgCLtkkCPBf zo9+jOAFNo*@>*RJz(eU7_`Jo|JIboL{1+1Ib_~at}FjxYS&pr{*T_->;VY-LkzY(~AJq zRfN{}3?No2jSK1-F;w`r*rkV>VAE2frwz8JD_Z`0(!RWNV`gd(xXSE+$!U8GY@})=NXt_`}WZj1+P9mioQj&UiisWEpfANNKGF%t6yKjANaLginlqM>4R6Tl%;9 z;6(RzSAG8uZqq867+0ed=baWa05DzJ)~7{|H;t?=t0T7d?{{V@X_(MAk6@wg_B|h1fOK&2{ zb2fCu#gV{p1K#+bzkErZOV}8frNg;BaJb>OUqw|ykwZFUK+pB_bC8`^Ym@z|a_@1o z{#dlK=fJ2tC(K*(*ab35MuJ2^k$Np`;(6l%)v9PGZ3}~%wDl=)ir=w6%TF3__>Sg> zM|9)SeAtOqdm$`w1m||=!Y6s{AEt`BWLIfL2BdQfeDT`TMdN&LuMn0ya9#@}p^`m> zr{cq&PF5PrDmywlX8eJ{V6XXPzSen&{FQo_T4&Yi)C5zS`Cl5M3W&%CFd0|S=KD+wS^a`A zGo#Cx`er#H4GadE!IhTcHw=&boJDLjBj4O{}J<7faLb@5MzD?3rDVX z{q}PteF67LvP=xJJbnOAdXfIk?(>2*mIQ+I3XOL_gg)`y)Chz^gN&E~2J)E>pzOG`fF6H@fcr@a3h*%Wc5i-=L6Uu8q>r&?Zdluir zAUb*`CKN1EsDDW{=3SDqNCeP{&w@Gip3iE3fBy;edO!#@f#fSf`5qzA)fY#{`8^>z zQ1K}Sn*{1FBkTjYHywUmjIWhPKZ+T3y_rGzibF$`D(^6Ymirl1PIHc8Y2pcG47h)i zdJx^RU-Hd0)jU~MXllr=WR8iqi!O1pxy}-E2DuDtI>F#^ngW!Z5I{1n7tY9dlVVH9`c(9aPKpn%xO3EG)=Hyxl$SpFBj5lWkzi2wAC*@B||wBwB%$ zRabDSlCsqC^>zfce^m#sYe%r}Gc8o{XR2i#QrI+>hC;mU9-1|uA1$L3R$xZVN`LfJ zMmO$M3#qT?Z$6u~>i_XW+{lOlh%ba~PZY9^dI0?vRd8ZAV=932Lr99nr=^7j1|oxg z8EE-3F+ZPs!(pDp7n@W|W4d93!3B>05;TKs=VLr&RT?0(0r@#h=1;XB6mU{zxmf;$ zjiKgr_y^M2J`W2$BY0CZC4h9n5$M=}SJ8(QqN7GwLFVH?`}6&iR8|h}ptQpJ^cbhXkJ%of*Eh~E(^;h2E)XrwkXI8m->1eg((qL7TGN)1R+lUJ zz*M~5gN*z@gmiz9={uOt8AD3Yf;cg+So0b#rHO{vFMt!V0~t?tAmEJ_eljc!0fPGrn1r<56hd3EgJ(+i4tfJYW~rMhRo zh}Jt-ybxpmS7qMikH2nRG*&b<$Tt4&>IjmzVIS=1f3WBSHC1YX>%T0Hb)2O*-$Co{ zqawzGsWq4yx$TF44v{lMOaX*JUPP%KK`{?Pv#cjsm$7G8A)c0G+UKvP7+P|CVrluq zel=f8G@jTtkGAvAizlB!?AqgzK#(acM|b$xo-;O|2~t*pY6+xxKt_^k!*%+18y&yb zuXKOKNT)JnGEQW#vx`s*uzTlKhAYijdhii|Hxm=tVI+Dvi&FB&;VtcUEGCxrQjJyn zuWzlN>arcWLd6P|dP7W^(a_KkV}8?#@F=Y2L$4oL1;H@#_Vz$Lrh>i0BHGAC@iIF0 z`9=a_K7W1AGPa7<2d}$80@qRjdiyiq?zeuF9pxTLwdypZy@8_-qfU# zvHFglsf+Ih+gLSP4x8rbzAMr8a8suv<=&)^hoaVhi#j`RyAivN9xcJ}4g${5S~T^O zJIyEgtWe^YSgO*lyO1)2zc|15;-fchrf@G>a%lJ=St2%yD(iA!M`q9Vi2ha=G}9dl zeb4p$mr{9?`2xxFjM%OJw|=2_mea` zivM9hatVa5O3BlX%SiFaAyU$>PZ^6jMw)g`$|{n7r_~vu*q?mi7Ef3Mi}7b*5Xj1% z<7j%ZT=~B5R1@~OKI0KUoulBEaQg`t6@zVzLg^6mJ-%y_Wa& z#|x6=Fu;TwpFK-HraYi|=}&iT(tPzd!1vbQZj3f;?3I_lDX|8vMa=~zVFgYQ5=1hL zk_11Yw`rgX*H|Uod=IHLCqW5Vipxv7!;lq+{!V+ys)@lzZL#+%`|qcOz5KJNK^otw zI5(S{ek6(US!P{#4a7k!ZXDRDCL27LAmkx<3w=o>EC_yQyiPvP-tyL2ro+-EIJt;Z3=v(oS{>$F0@X7FTmXoS%sY$~$kp7_;EcDOPvZw*3c`1HavcI(1>lk8KphxPug?~8A*VrdH(it353SX60 zC495JZm+tTYZi$H{xD)>yn-Ucm=e!s)uQ9lt!QCRJ&E87;h7PQXzdI+^+T#}) za==#{EUv;^wxZ_yQ)h!f=-z$dD))~fG0?F|M^``jHCw}Ngk6Ol`-kA0ns?ct! zk#_KL1@+`wO~3er9O7IJklIO7Gc$#~YQasS6S5aWzaB=cPIj%_}Sss623 zd&jjFKU~E~aIJ!CIRGR2LH`~9fu-4nJ-v|LO*3u210SP|*H{OiA?qoy=bDR}=Xdu? z%7?c@f{7+?0F~wFXw?jqG~r6)Qh`}7<+Wma&U>W81vy$gElxuE6?dkH4$L4b;pEm) zH2K2y?{PrD77y<2UyRJq5dG`rsFK+)qF^`PBqX$l|GYgL5Fw2VD_j(u`u%-?_DezC z?~(M<4&BvGZ615C!`;i>+9$o@Px3o8oDcjQM&PbE$T3W|?$Sw(Q{8eAVA_~kb- zNXy7N%Ni4Rvq5ZcD)a?IP{CorZE*e~j`I2Aq{uP`E-EAAfCmnm$N$lsogVh=JngVD`v%+A};a z#CSt3@D3-v%#N(8<2_>*aDV8m$DH?#V`?63f791$PCqasMkInLQ=#L&vC-X@Z85$m z7=it#fOc1)JHxjG3B&tCi$@`4Y3AJ^>8B^5zLXAbj*j*KfRmi%|GsTJ3y>rLk#QTu zs0&hpo0=M^{n`4U`BkWoPFg{keoYIK#`AxLdfBa?Xy(5ZZ}c`Ny~13uoOZJWozOvz zi*Nq7+#gr1Lfo;!I0A84m@!;GURoBV>$CLgGgG5^HYstC*B!F!LSNo_y)-8Lm%w_d zOc)q%P2WV$-xWuTnx(gSM6C~-l)c7`uC=HI;WtWkZ=EIQ+MXFARA}79MpkD$$dHdk zQitqj*OU%0sUH6oS*TQbjUi&~~P-aGNd=+7IQnF@xnuSxr=1XEgJxU(=SZSq)Mg1^-m zG_`R(4prY7IPnh5<4c90IX2=Zu85OJFnf_i^KB)8uh#pNKt(Oj&(K5xG3xrh;mS(; z`VaZeXYO31&1zNjKpn)rai$)$w1txp<-*teW}7&HuohF z$~#AL*^wsv#Pdo(*>y1=vCFRu$&`%Fy z{}uc5`%R4oBMW?>e74~%M7YcSu*U~)DYzh3=av)?mj+K)`aQ@b?yj|-?Fcg}{rLM% zn;Z=jWHic$KTN&qj}r>CnVT#G1!8{EBa?UfKirr#jS1yDnQE|bFa6!-vjklpUaVp* zah3a3&EMdIs~kTG1!lV#qE&9NQ;A%1{sKcLc9H|C&1fq^I7JA?yIfu*Z9yn|8XmaFmE3iM_Hz@j&?k5&EsCO`-Y+1Z8cRIeNK!9i`3#(3{q>U&~t=24mD3?=#jqB!?vDLf7??34$c0$_AcN*V9`keUtyzO`{dU{cYk)> z>OslS!*;nU5f8e-m_&X(a{BBaRhA?mHoX&9wZBXWGP-i!Xerg?q!%%`uLuu(!c7pK zTDwwED9Mi15EA0`2=NRtls?^_FO;3U4%U?kVM=SlIoKoE!I4dV0uQ{v;y2{ae zHVv+~9%y)hdiUT?p+9=4m z+BrXnWj-+eU0aU3uas4)51Ja#xLWrUIF)5Na`EDEr!sA3i{H#q6&9iZ&GtPB@c=m; zkj=!z$_ShL#sZZLg#d`fnkrFh0#na+Be9TO^HJzH1Al5(Mg2m187=_1s1j6oH{6MD zw-Y#xlv87Og+9Sl01v+=*Q>A%lh|}ObkH`!nc&wp4-^YaP<}*D$vgi3~@s;4n5! ztPf#Zqh}{0VjO9+i|!!Bn);Yj?&UbgmjWa{+bue3ZCbD#c=wJKVRYy!uJ@7NvYGum z?~JExjdIFj0t>5&2_c|KnwY`Iy8zWa@8bv^T##%U$x=P|flX8FrzQ32QCi4C3tJ*- z0d#kSW_&fhC==KN%w5Q`^BG7o=aMu~mr7$T-(9=J#;|s?$cN3pt%rC|DL=(xdqUvF z(64hd*b$1SIg98#Byk4%ci|I!ikX-|il)PR^vIk{n^cAe-14bjLDk;Y`y7Z!Q?6-L_W-{5+X4a4zqu^f@BuuW%xjAMz9 z&t+NN-o{VzshU)L#Dr4sD1AQDKZ}@bzZ(M7ADbJ;4 z)YiiW8vkB;CN{uRy5DUWf&lb<9>xD!^Yr-ND}3#TsnJ|55?^8gp8GwnC$Hfj*!j5Z z>}bJ;A;?%>pIfDAw0j{9{NvPT%r%P%@;^^I3&qId$Y{7OdjAwHSJ6(tZy4^Z$lWFd}5p-;Y|q* z4UK&=zW~lS8tweciMh@e1}?D0cC!I_I1vB+w@?kwIF<88y7u%f6_qMvq+dkP87gHS(qL}(a;L` z=wxFx(hTY?6{mm&M7u1DZO1mN{gg4jzhyhtCLz}Q2ZIRIAx%xg*o`G$w>rRSe?xaz zo8?5tkxVP3YPq99FGM|E9t8v&dZWihUl3Zu4iwFIwQBOsJO%s@?Q1gnH;2WPV)rW( zc)$`FzaFE(Ryi*}-9iGg;OdIFFYFeD@+Ik$ZS0y^h6_?v0V*_0=&PLy!@EI*+kK<+ zGcDum{#y#cH}LxYzSNVEU`ifjT6ZzvAkyyW+j1^7weVjDVq#JB-47RQa^@P#Ld1MU zDvZO<@XyPG-+ye}bdoFQS3#{espeDrJ-2M@#E#lC`wL>We_HdT zKaz;1y&E$6Yi)KujZ2Y$3Qow)jW?p#mibgM z3Fw_M2KqfhaSyS&fb`}Oq7wsPW`VXpvLK*9)R6FHtr~B{_L@N`22&v@%YmM7RB5`T=rix9(j}rW6-d5-RxEfT z7Z5Z$?QeBw=e7jxC zU(()Kny3aRc;}w0=G7G_>aA~Xz5~rRF1D5Ziq$7cL2|r(JbzY8N58>aTbLjdxDq>1 zYC=qlk!h;w&}tgF=iCjv^T#ztWEe6FB&n07(Rasb)E{pzBpi2n~$UwNfYj+vfbwf>nB<@}K9= z>vY-eXm|$F`r^f{c@Cgr21ZDqtGNE>ZoYPZk_;MV6jAbXb**(222#-Atp+8U%m491i{r5uD3Z2?HTxAfteG9=+^3(OyPv9h-FO_H zb1fWzt|N{clD^}4*q?>&o6T?cYTPTg{qUM@JT$Jn^qRNWFuc&)JInNM2RhD><&feF zA3?ud3qMM|J6S$3YFv{1Lwbe{`uK)NkueN(()wsz&p90CvXbx}9jsilKfO3Xv^@o# zt#ZBXK0Gr8MM`xX4{FBe&nMO#8<4Ny?ExsXaeZsspmh5f25T5umQ3atIoc6?(Sirrcaj)5aBD5#Cb^ZFz0&YXAMTbkp0; zAAx<^iM6v7;sh6>9c3#oB6B<76;QmITbdM2!lClU1M#`O?b2d9c?5PfFe1(MAUt_G zerGu!pvQm{^PHIaC|l_!Y(dJB-u$S{tB8|6jfDDQLa}>V4`s{ToDJ zQd!B5%gZ41ZFy;+AOyO!{@mh{d*;9hgsErwg=y0NZsoUQahj8nan|l~*v<{X8kkEo za9yu!`IQHvHViinKX{lifFj077@u9FgQvh@HxYi$?Ls5cVq{cLRDj1x_YQ#B_dS9l z=&B&ITl_Z@bS`BC8*E#r`@7E(kgFhKfZ7#Ana@Nm$buVv>bXv^F${bYrlwgQd6dc1UaCzam2;rq)ZGJq9BXgnV=@B%0uC0~_^wP3uGKek6Sas6g%ToRWfase<~j0z&mKisHV$ zBB>WN_7{s@2Z%0)h$6grg7(bgoFe0|g6VzvWfhNDB1y}MJ=bn@8{$_$QS@l7#z97A zn*#lK^LnBXH0yJTV<)%fhCkf`lY;3q^1eSnp$*6;cfWDQ-sP z>XkQWKhtUz`zS5QWtSB<8tSr&N`Jr9hv)7na4C7W`3f*_ir{3B8-G4Ew1p1H-gjgAuwl^iFRU*>71e0_X8~xn`S@@(ijxtvRRFB)PS8Y+ z3#1=5JpQX6HVt{OAvy?yERuLX3QTF@x&nzpyPPw8<+{g(R?|wt*Svs9 zr*bE9`ga;AWH$Cl0}N`xLx4m<^xBS3N($=ilt7S9CvFeykr5prKm~DiuHs5OcRVDng&gqd8PzJTuKGOOA%oA1k}~lbK}l2h;(vnqU~PBu zm8E6zID-n>x;p3;kFJy*sFj_3AEqJ+7rgo)Ji|Q7>0XHtblSVl7H8fqN5qIALm%kZ%2(RzZ(q{>%%Fo@Ae9$F z20I`C=l`tXWaaYYXQef0hSCKxeZDu`A0pyGWEHabRee_6O)LYvE2S-6dbY+>g)rh+ zO+d6182I!1Ln^*EbIR=c4?&MzFY8!!1DIB@EBg1WiWgSshu%hvF@A7Kkp44{vk-k- zpG!L+AKMokB2gZ>ZwTrSAV~&twWoYen~M38x$@Ceh5MD9b-FWCC8l-3&fC2Mbf>Ge z?a|F&6%0UKgZGRXn)DbYAz>DU^vb_(H!EqdBlCsoK!@u-s_pz3?R!}IrIzdB@8H3L zvMLj^C`kvTaORgDNrR7b!U?fKE&7uR$Suya>Qi02{1=I33q+{B`I&YvUSuKyqQJDb zkxp9UxdB((ZQd{yts*aL9-|+yv=1ezLBcl`YPg$L6FQL?GMRDA@a*A!JMEqxUq1GY zs*2|3Dz_IuD$^@e%wLbw?4H>G`j*YmzM<3xTU`rxZfeLv^R_0jlKAVFF!J0t>!6Pg zh)LD;q(~E!KXYKSnHu?eb(U6JDt-cw3kd~|9P?ZQvN zX3OvMStWVY)@w3Lv;PD%Z)^4|FH_xJV$rr9ni#&b@EVL_@B@Jg^qGVfe_ZicI= zEeEix5^LY;KI=QPs*50jS0^LmqdVM{0%}u1cE-;<$1oRa}%;WeH+5-_~+e zCR~C8xZLRa>JiicbjV)1waq9reP3)0jO)!@tqpkFA+I}rErEXEi+U~wDKa&ZmR`k1 zNvcBpg5XR?5M$xd>K%#G_n~H|2Vf0nxR?Kw-+tus;sv!)-n-j_hJjTTu&wnsnwod# zep5^~3gFw{y_;-;er|&~ZIT0X56Y?_CVA-~wxFBk>4CS>O^4xc7fK-%Mc zHC$7qEuP3Ifya6vyk>gxO)*JnS(X4AfKT#*TPSZQB2Lrpv|O8sXCrB_Q(oSGQbXVP zdy47cQ+5nCC^55#fpKqmqA=q_MUb)fZRRy-qpkOvK6rU_)P6E*wRQpr>mdf#gCD3J zo|idqL4@wy8f(1#^lXp0S+Ha|B({mG;FY0+6#`(S2xI{}$ccSz8 zd^=z7kl|SIO?Qf_1z5SL!jNEC!g=LQzn-up(W5*;IsqRM*VQjUC>mB zQiD-*?UwNSWL|q3w0cRWsu+2#g+Bm7tTh-TAJG=Ql*=oS-(USN51Wz-m;~T9K>L#8 zhWo-ctMQq(t+tk4R^tHBSLHv5p$4?jsl^nw_P2L=F$XPmoh@v%agBba>;2DY;(kE> zWein#Ty`FjK5OyD#G>Dq8TfGEckfjxxFn@03NHrq_eq>{pQ|F%GZQ7mk4%2X94pV^ zRZ=Kfj!+iG0hx=Kw>~K)P+U-Wwk&U+N_mLO$nU9v&2UG3)xrd6`Fubc79>@=f_YawgA2?+F|Q4UHix zY6!7dBRTibY#oec&9>sxbTg1m1j%))Y5ZOp6DKBFWS1Rth z>C&*!-s~~UFQD@+o0Iu*n9EN1*{+nvb37q>rPlMOZgg0X?%v`OC>f_?N)H3LQNEq;Ngnps@$gOtOwklfWT6F!z|}@75z;YU8=rmgA3c| zql6>G58f`_zqWEQz4slzor${E9Lo1s*hyth1EQMrcONfbm_u$Z`erXK91M@%Exap< zege;$!)d;$;w@9hxVRi06xu5(_qS^u@11XZNAo4i4OMKR&vB2k!pRIxIXdR`y}{-t z_%r|jQW@53EiEf^-hJSGJ(toN41Vg5>7@dtcBJ24-A^D^ZEED;Fgx?81o|b*Ng*wg zrp-X~hG8sEI-?NOPeADP=G}mYEMyYpQGonFC*;UYUBoW31X>F`tmWqY9bW(FbnolZ zG6?VrUi(NuyX}>^l+w>nC}R!Z5zg|3EjG}U<`r>7y;vvGfA>8Z7|FVhM}!{kFJQIb z&BBeD9R1&X1A_9^4gf8Hq>9H@UZvNFdb4N85ET;*ex>-}*mSwvZ>pC@5cC(+xJm@I z=TfK*$Wi7kCk%Gh+F=|Y-+Vm$o)dxRUJjnOcHgm9l9c@=!>W%al+&6T)ztFJNP(hJ z@KI7SD=P>K7n-DNG(&t3QT`rm1)}MhR&uuvtNp#*R-Q7@|6M7$C)9t-wwb88NyVWZ zkyYU?BqkHOM3l)(^0vJNmxl107mi6W4BpmANThCS#wF$*ah&ajk{YBP^L3LZW##Q^ zakb?+84=3OD%mVQC!YJsaD2CPFDMvKC8c3B-!<~?PktSkBFX(P5Zrub^$Q9@OC53% zy@fAowoiJTM!$Y5^}V(FOHYuUVL9USf6Dvnx2n3X-7SbnD2M_|3QCuVbeEJgNQ1P1 zh;)~NfTRdWC?%cJ9V$q(m6Y5_NQ302_Zd9zIp6hu&%bc^0WS8n*IIMUIp&yi-ecVN zIN^SA@R`r=$fioncou{61~0rS(RNz>mUKwLre*ww`GtVoRE>s%)89lZSG3Eo0JlSw z7v>KI_3{!tUNNX7X1HN|jD{q$WfBw5M?8y)iZa`O zw7XXD(;3-63S--k2i@bt7aHspX4TP()4$*BW=}d?=(_UaKT~C<+rY?kt&G*gZ8agU z5Dn|s&hkV}DeN#f0MGXH%yh|*SWF{FU2Y^awB+vl072)OaIVU&Xuqt~t=nBlTsTL3 zH#91vfd>@CG)6BBFzjs_)-_{%%gj-$ME+{ghPMqM+!45gYS^9)zffFaVT~;-JD#}k zMCOZ*rMJ0+PoDT;7TMwj&4OTJ+Hk)+X z2~KqMI8FYrhF{?}&1f~O&w{D2LG=UPb;AUY0Q+GS;q#|5cNO2wC!{YhvIjiHp}3VF zY2r8bqlx|X(bAonC3X9gUY<-zNt}77&wpPuzrPkNmBP0Y+1DOEoFlq0%Nh>J4H>N` z%c`~wt>h**(tcft0sMHKV5pRK{#V`z8K>b>*lk?gX6@OSYHbf+5XrYUnDIspeiwF& z6U9@Hw|T5>#ZirT>;{k92_O@n-1x_L zosv9$y{>JT*dWA>1+`=--8TqDj-E12o4uZYD zeF=aULe|NK4-LnURj?Tub#I&UD0>Tx?-$SyQedo%p`F9a0dY!9#PHnV%Ao9A>^$c9GI{{3e> z!XhrdzCvL3OeQNd;^Ozn!SA%0@;TZ`(NnnK7smy7u6K6h+dRurGc01X-rCYGDe(|l;Y)jaXSf+h=7!HJTx@D# z+d1?!loa6=qBvOKs@fVZ1m6Kf1kkH9bae%6^vTg~fQjFk$cy>Vf3`b6-XZTH+PLqK z9xZSUpJlWhD$ASQj~~*SIdHTWvAzm*lC!x$Ikz#*vy3W&dDoD$O1x9YBy44vweJH< za=3?Md^;J8bGvO_J^lN0)~cBmprQaJOAcfPL$%Po-yyB*6Qm+zEp0m$NGySD4gta> z=Y`^ulQnDY=0}{k*omKYZ=qI;7Q&bcJQ)dYU+sw3(JL{+KHGl(B;=tGIHiT2K5Zi7 zl>wYYzG8h0zMyGXxOrbqQeUblh#)YBrg|wJAFgQ6yi;ZM+{T=h3XRyrx5o&gH~q1h zRG!Y!Vs1Vi%Ikg)i~Z_IraHaeb$D2|GUeW-FLJc`q5-VCO`8|i$8F}sF?x47E%ac( zef$qz)z@ziC=KfyZFxZC;9E#|3XO%z-2BIJ3(vva!l|#*UWKtt?yHwXwnJf0gYCAC zulLNj9$7bQ#(S&KfE!y5GZuE zD9+~TRBAkH5IEW$-`ea;7uG{8E4#9y2-#D`B?wD&X~eDTZMC6!irn0-fHlkkK_JBe z%fr+n%ZumFk?Ty==u2vv`7OZ_h}soKuL9wpuMTYxbu6FWR!IpvZd-vB8L zi~=VCcH6O@1WZ*&wUSZTRPlYCU&Lj5FaY@{8s{s>O1BbMen=0_lVi7^mxiFcv@M2B z-a0=&A8d~9Hmu8aSnNjnUGI+fupyfMUFkg*F41dtzNtTko`r1UhYJ7kK}`mf6;!=P z2gcUQ*ti9KoYVfaFB-5tGBB(?k(8M{X73oyv=6@#wVSxy7xjz0+ZRl*vhoIFHHqjd zWaA|NJO55HG*Zg;pY$^cy1&27Go4FyvMo&!e+y0W=ZH(nm-rUN4kVrx?0D_#LAkmB zMu!C!_rsWmt}|aKn`|@-)(x~7*P?o|hx7+QZyXLQ zd=QVw!uz_?9ZA`mDLd}bd(#z3d2N|VjOL)biE8{eBe-hLT~9S8_4l$ygf@wry; zSE@8mUb&ux1k2dy0%X4AF+chB`S$mRGQ-;kb1OQr0sJVrhgcvyzaLgsW=YG%c?mL% zlm_}zuoVRZ!LzUg=zvBz}8VP<2Q{ ztjyO4~T}lF5pGT#Tq=+v}j!F=tcERe|zp zW;mA18jehI8>br!ZsEeh;%8+7E;fIkIEGd?Dk{Bx@^w}V!U3w7z0yE2-?lF?Rfhk( z1{75ap~06blF>5vJ$|#!V!YXeJ6WgMMev$X{Wyk8U#q=5LSd@Oz|D1G%o^M8aMYyG zC*=ll>ekc?)TciuQf4}VMdI~t^b$igGtwU?W&BMGsYXS`Qy*^5LV=2KihEHs$~q$|@crTOgns zOdep=AVYtLcA7Z-CDsfIGx8n0r$2|@H^Rf~0nc&)5t=}ae5d3?bVTcH(R*?!Dd7D* zM&a`2#Prv>qi|HxM!t)m=6h+mk*cKLh^II1>U!4qoE&D27)G`{0BM1z1?O%T=D)e( zVdFoh8UjsDq_lG4n8azH4l;I1#)voLOtihvm9o!h-y6v&`7gt?)k6WZJEzthx+Dl+`^FpN}>3v*@7$`xHQ&J3FSWr5Wc z;OeTn=azF{-JrZStdBX%r0-#y;nB1Gx21#!5)xY%AA)Pa zYAt@YdV>v{Z#MTyo$7|P6K2h3hIORLOnx-(Tz&B;g0JMy3KUXo{Te)8t4ho3aEIQ! z&Tw`$YBXOnv+O-5=J&=_`!T2&X5Q*5EKM-l&WL&P)l7DxCVYoPzvhw^l5CHffx$9O zCpYR>#{NbFZ1l{e$JWLqP3lG9;O*@tdL}U8udiHvf-7JB4y9r4z5 z$xA04A4BlMNqL{%ek|YpF6Q=8IF}y%_=RF!y63W5L*-nTPn48&uUd%$ckG_f#epw1 zEydH1@|<>>Fsw@IZx0BJ)$?t5gDm=+cA|dWTivTji}xRq!V#ejrzj@|Nv1)xmF~c7@`)x>>T{--rtB1EuEssa?Mr zV9p=|oeqQ4h~fAL;FQPRTgj((8!0A8KOAifn?1Qu8bP>4eme6-znx@P(0ws#+z;x} zm1P=Uq2$L3A+npxO(h{1wx9*`BmzIPzfSR?ODf@OP!{;@qVwwF5HQlRQ*6~neSxRYKwpL;doJecsPDBwQytw zA91o*I*$DPd-9os96Tc$m-Yslp>f)Gv{v^#eO!0=gW#-4Je@S*dJT(1b#$cV;l;OO zS8gJ9SF$5fp1E)O&;cH4WA&s@QN|4rtz^ENCMq1@FL@cT;p(+*mi=B=1lc~rS$m{1DleCNeiZF++)6OvF$g{@ZXx2{9^URUObHmnH%?=^llQr zr;Y!o@ko!gHv>mL$cyO&CjaU zRo1O{z0R<1p=>`<4Y_#(>L7ymDcW`}g0RetA_kK5by~0n28OVoi}oV*M(qM~?`Pc9&nZhm+&(j;lhEHi%Wq9q+GSgEF~5Je-3q zLI)n@8a@PO;Go8odXJNgzMxt1Ra-`%@n++lD82jy?~QB1MyIQi@43huj_t;dZU%HR z1L#)igmzGv$auBX*Z3lXS*H-djhP)})fT!1`N|=zC`*qAf*AIVE;edWZ|L8dLXr+B zLeIV;5(9*5CnhyD>H_wqCqP%1S5_|GuJS+lMysZ)8%hrQ6+0;4;NX93a30nKK2bY- zmLa{H@%A044-`k{s%W!Ghn`{fH$+7WRwm~T9Hb<^E+E3vQ*S6T)0i|C37t_ zAU{3E3Bh~8TZU8W7@@%)nk<n1JeMLTC&Ycfe(>Yxgu{iO3w<2-3A=FWOgL{-P9P zSB|9ZxmSS~G-)-GnzXs-xh*oq#^XKB(i4BW(KOO9<13bS%+f<{Qj2LQDSv&X?`m8) zSyBV}g4j`~g=`hGZ&8zXA3esv!4*07CX9PktJ>i`ux<_y7p9r-Gd`?eEz$pYH2^1f zvkRtul^QYo)&7;b#Z+e>v9tsq)X1fY~`D}WC8lM8t+bN*?X|0;F27$g0ZYHaDl(bRz5vo|>c@F_c(k>& zvPMn(n+DJ|z*d!-kR> zt`b*MrHUD06}gFv&UFgW}1jes`l`AmY|=3Brv}F1o%)(8Md>WxdMP$=2hhxzT)guM2I(fmnIWXRTR~ zC4VFSZ8l=N8uEZ1ulg{lrfNNYoN(S

o#YXdEn`SyXgtZ?M8zwb-a(WUn4bzS+6C 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 D?UfMF literal 0 HcmV?d00001 diff --git a/src/Mod/Ship/simRun/theory/images/test_direct.png b/src/Mod/Ship/simRun/theory/images/test_direct.png new file mode 100644 index 0000000000000000000000000000000000000000..1e8e22e9e5032aa61f185692a4b9651a1b87b819 GIT binary patch literal 48587 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 literal 0 HcmV?d00001 diff --git a/src/Mod/Ship/simRun/theory/images/test_wave.png b/src/Mod/Ship/simRun/theory/images/test_wave.png new file mode 100644 index 0000000000000000000000000000000000000000..ac983211eb9f3ef5d89d50a2ad4ab4e370a1c97b GIT binary patch literal 66196 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

L+fl5_C@E&1DmBeUDu56I2y43wmd*M%I7a9N#<{ z@q=kZE>SC#hJNsl7p$=vYYR6AY5-usz(X95H>kze^JFdI{EM*@wQTPbdWNEGnM?TH?FnwX?HhHJ<%Q zHi|STEDSR{CueoHv{km$u=#M&V|lfk#K?8cLn58#=uIXaoM>@?{US}!<+mPO{Rhyp zvOZS-zC5|kfOI`-q!v5+^+yNFx}7rwwfV4N$xJ-F4W7?orJU9p;q3J3@| z-Jd7P&(EK!bD{^l1v#!yqsXJ%mT&DdiQ#KCwWng2DH)if0%aQ}CVTft- z3z^BAaN3y zS$FU9+0F!BUcwCaOPkNhHiy#+1>9HK zkh*$$)~1T}BG!Nv(Y4+eN7SRHriMpNZDcDG&)IT`y!Izronl~kSk~891OY)2$f%#7|yznGfX)C3@Fntjqkx(eVIh;kh57)9G@j6<0(v8yX}5x%J^l z7@@E2+!!|=ryfY9M=}LaJKu^)+nkrQM+@=?J~UTZxp9g5QUf!~ZMQXa`H}caz|Ld5 z!`)<~_g7-_f6L9}{ub+zuxb{yt#*cjNx{{~SChHEY4*7={S)=<@Z>}auo$t{{4WTCp|VcCJE|V1f{C7G7$jthhSSJct-=> z8uRAjfW-f5gX9<3Ai=S*v0z!kZd&-5nH3;3z;F;u6ZXQXoMro)VyN2o95V@ZwY)yI z{_LKB@r~o|onqzYI@!(x8l%MJ>Nc)!t~ASpUJCu$t=WV)p?E8^hgy}20u1h+Xq3eH z$^R+KUF-IZlu>AD_Xx%X|Htv??Z#Y~vRUu6>z#982ltn2xH|_=(51>bv&LRDJ>1{8 zFHcMbVBM$Whl;Z0U}9l4I&dm_dpDe3B2DL zCbZ8pyeP)h4PRQlySrHS0IfVp482DVa0p=DEGw&!bFho~OaI^%9UUf9JgQ4(k+lwY z-&)%UfuA)h9er^je{0O*XoF+E*cDD-!k1$5GCAVR$`!t#b1hsstG_q!;iXB(r$=Pw zD(A-SY7xMkf`JFQQidYd)Bze4|Bod`-dMtfiCkkl8>|@5!u&@^?TV38+xl}^>PFW8&I0_ETq`&y=`fG> ztu6y@)Lv7SI$-9##I31n=U;S7ueGSo@|IE1wfP{M)+W;Dz#ohNE~M-J98s2RbVsV7 zOPSY+MHDGFGC7}Z+jnO5Y=hoVY;tsJYHIxkR|TO9u!jDCu9rJ+DB8|epeZGC$N={Z z^gIGMq?bWAwQsM!K~sW?Nop0HfJ|jSyJ$G)ko|7hLKXrVQVwU@v`6Oe6u@I}}PUXMI%s702$)QXVP%ukc*+i5A3o zd-RumtK~wr%)aV2exOK

oxJb(TC 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 XJ%ogFwF \frac{\lambda}{2}$ we +can rewrite the phase velocity \ref{eq:laplace2D:c_general} as +% +\begin{eqnarray} + \label{eq:laplace2D:c_deep} + c_j^{deep} = \sqrt{\frac{g \lambda}{2 \pi}} +\end{eqnarray} +% +By definition the phase velocity can be also written as +$c_j = \omega_j / k_j$, so we can relate the wave length +with the period +% +\begin{eqnarray} + \label{eq:laplace2D:k_w} + k_j = \frac{\omega_j^2}{g} +\end{eqnarray} +% +Regarding the velocity potential, let us define it as +% +\begin{eqnarray} + \label{eq:laplace2D:incident_waves_potential} + \phi(x,z,t) = \sum_{j=1}^{n_{waves}} - \frac{a_j \omega_j}{k_j} + \cos\left(k_j x - \omega_j t + \delta_j \right) + \exp\left(k_j z\right) +\end{eqnarray} +% +such that +% +\begin{eqnarray*} + \begin{array}{rcl} + \dsty{\left. \frac{\partial \phi(x,z,t)}{\partial z} \right\vert_{z=0}} & = & v_z(x,t) + \\ + \laplacian \phi(x,z,t) & = & 0 + \end{array} +\end{eqnarray*} +% +This potential is valid for deep water waves if the exponent +$k_j z$ is small enough. $z$ can take values of the order of +$\mathcal{O}(a_j)$, so this method is valid for waves which +the length is such that +% +\begin{eqnarray*} + \lambda_j \gg 2 \pi a_j +\end{eqnarray*} +% +\section{BEM applied to Laplace 2D problem} +\label{ss:laplace2D:bem} +% +We have defined the sea waves outside from our computational domain +$\Omega$, where the waves can be perturbed by floating objects. In +the figure \ref{fig:ss:laplace2D:bem} a schematic view of the +computational domain is shown.\rc +% +The BEM is based in the reciprocal relation application +% +\begin{eqnarray} + \label{eq:laplace2D:reciprocal_relation} + \lambda(X, Z) \phi(X, Z; t) = \int_{\partial \Omega} + \phi(x, z; t) \frac{\partial G(x, z, X, Z)}{\partial \bs{n}(x, z)} - + G(x, z, X, Z) \frac{\partial \phi(x, z; t)}{\partial \bs{n}(x, z)} + \mbox{d} s(x, z) +\end{eqnarray} +% +Where +% +\begin{eqnarray*} +\lambda(X, Z) = \left\lbrace +\begin{array}{lcl} + 1 & \mbox{if} & (X, Z) \in \Omega + \\ + \frac{1}{2} & \mbox{if} & (X, Z) \in \partial \Omega + \\ + 0 & \mbox{if} & (X, Z) \not \in \Omega +\end{array} +\right. +\end{eqnarray*} +% +$G(x, z, X, Z)$ is the Green's function (a particular solution +of the Laplace equation), and the derivative respect to normal +denotes the gradient of the function projected over the normal. +% +\begin{eqnarray*} +\frac{\partial f(x, z)}{\partial \bs{n}(x, z)} = +\gradient f(x, z) \cdot \bs{n}(x, z) +\end{eqnarray*} +% +Hereinafter let we define the function $H(x, z, X, Z)$ as +% +\begin{eqnarray*} +H(x, z, X, Z) = \frac{\partial G(x, z, X, Z)}{\partial \bs{n}(x, z)} +\end{eqnarray*} +% +Therefore BEM allows to, knowing along the contour the potential or +the gradient, not both, compute the another one. The parts of the +contour where we know both potential and the gradient will enter in +the method as part of the independent term in the linear system of +equations.\rc +% +Since we know the potential out from the domain $\Omega$, we can know +the potential and the gradient along the inlet $\partial \Omega_{Inlet}$ +and outlet $\partial \Omega_{Outlet}$.\rc +% +Regarding the bottom, we only can assert that the gradient along the +normal, that is the vertical velocity of the fluid, is null.\rc +% +Therefore, the inlet and outlet have relatively good properties because +we know all the data, so will not be additional work into the linear +system matrix that must be inverted, but the bottom don't have this +desirable property.\rc +% +Nevertheless, since the geometry of the inlet and +outlet is different from the free surface, and the bottom must be +explicitly considered, all the contour must be discretized with an +undesirable computational cost associated.\rc +% +So we are interested to know if we can replace our computational +domain $\Omega$ for other where only the free surface contour is +involved, moving the Inlet, the Outlet, and the bottom infinity far. We +could change our computational domain if the Green's function, and their +gradient, goes to zero as we go far enough. In 2D we can found a Green's +function for the Laplace problem such that +% +\begin{eqnarray} + \label{eq:laplace2D:g} + G(x, z, X, Z) = & \dsty{\frac{1}{4 \pi}} \log \left( \left(x - X\right)^2 + \left(z - Z\right)^2 \right) + \\ + \label{eq:laplace2D:h} + H(x, z, X, Z) = & \dsty{\frac{1}{2 \pi}} \frac{\left( x - X, z - Z \right)}{\left( \left(x - X\right)^2 + \left(z - Z\right)^2 \right)} +\end{eqnarray} +% +Whose limits when the radius goes to infinite can be found +% +\begin{eqnarray} + \label{eq:laplace2D:limit_g} + \lim_{(x-X)^2 + (z-Z)^2 \to \infty} G(x, z, X, Z) = & \infty + \\ + \label{eq:laplace2D:limit_h} + \lim_{(x-X)^2 + (z-Z)^2 \to \infty} H(x, z, X, Z) = & 0 +\end{eqnarray} +% +So in the 2D Laplace problem, if we try to send the Inlet, the Outlet, +or the bottom to the infinite we can't use BEM because the Green's +function is not well defined, diverging with the distance. +% +\begin{figure}[ht!] + \centering + \includegraphics[width=0.4\textwidth]{Omega} + \caption{Computational domain $\Omega$} + \label{fig:ss:laplace2D:bem} +\end{figure} +% +\section{Conclusions to Laplace 2D problem} +\label{ss:laplace2D:conclusions} +% +We have briefly discussed the wave propagation problem using BEM in a 2D +case, seeing that in this case we need to consider all the contours, +including the Inlet, the Outlet, and the bottom. This approach is +successfully applied in a 2D problem in the reference \citep{vinayan2007}. +In 2D problem considering all the contours is not a heavy problem because +the number of nodes is usually small compared with a 3D case, but in a 3D +problem a computational less expensive method is required.\rc +% +We will not continue with the 2D Laplace problem because the solution will +not be useful for us in the 3D case. \ No newline at end of file diff --git a/src/Mod/Ship/simRun/theory/laplace3D.tex b/src/Mod/Ship/simRun/theory/laplace3D.tex new file mode 100644 index 000000000..96854c14b --- /dev/null +++ b/src/Mod/Ship/simRun/theory/laplace3D.tex @@ -0,0 +1,642 @@ +\chapter{Waves propagations in 3D} +\label{s:laplace3D} +% +\section{General} +% +In this chapter the 3D case will be discussed, looking for +a method to solve the BEM using only the information about +the free surface. +% +This case is our main objective in order to can setup 6-DOF +seakeeping simulations. +% +\section{Incident waves} +% +We can rewrite the sea waves system outside from our +computational domain $\Omega$ +% +\begin{eqnarray} + \label{eq:laplace3D:incident_waves} + \begin{array}{rcl} + z(x,y,t) & = & \dsty{\sum_{j=1}^{n_{waves}}} a_j \sin\left(k_j \left(x \cos(\beta) + y \sin(\beta)\right) - \omega_j t + \delta_j \right) + \\ + v_z(x,y,t) & = & \dsty{\sum_{j=1}^{n_{waves}}} - a_j \omega_j \cos\left(k_j \left(x \cos(\beta) + y \sin(\beta)\right) - \omega_j t + \delta_j \right) + \\ + \phi(x,z,t) & = & \dsty{\sum_{j=1}^{n_{waves}}} - \frac{a_j \omega_j}{k_j} + \cos\left(k_j \left(x \cos(\beta) + y \sin(\beta)\right) - \omega_j t + \delta_j \right) + \exp\left(k_j z\right) + \\ + k_j & = & \dsty{\frac{\omega_j^2}{g}} + \end{array} +\end{eqnarray} +% +Where $\beta$ is the heading angle, being 0 for stern waves. For +this wave system still being valid the phase velocity from the +equation \ref{eq:laplace2D:c_deep}. The purposed potential is +compatible with the Laplace equation +\ref{eq:governing_equations:laplace} as well. +% +\section{BEM applied to Laplace 3D problem} +\label{ss:laplace3D:bem} +% +\subsection{Computational domain} +\label{sss:laplace3D:computational_domain} +% +We have a domain similar to the shown in the figure +\ref{fig:ss:laplace2D:bem}, but in this case 2 more boundaries +must be considered in the missed direction, that we will call +$\partial \Omega_{Front}$ and $\partial \Omega_{Back}$. As in +the 2D case we will apply the reciprocal relation +% +\begin{eqnarray} + \label{eq:laplace3D:reciprocal_relation} + \lambda(X, Y, Z) \phi(X, Y, Z; t) = \int_{\partial \Omega} + \phi(x, y, z; t) \frac{\partial G(x, y, z, X, Y, Z)}{\partial \bs{n}(x, y, z)} - + G(x, y, z, X, Y, Z) \frac{\partial \phi(x, y, z; t)}{\partial \bs{n}(x, y, z)} + \mbox{d} s(x, y, z) +\end{eqnarray} +% +We are focused into compute the gradient of the velocity +potential along the free surface knowing the velocity +potential value in each point one. Let we define the +function $H(x,y,z,X,Y,Z)$ again +% +\begin{eqnarray*} +H(x, y, z, X, Y, Z) = \frac{\partial G(x, y, z, X, Y, Z)}{\partial \bs{n}(x, y, z)} +\end{eqnarray*} +% +As in the Laplace equation for the 2D case, described in the +chapter \ref{s:laplace2D}, we want to expand the domain $\Omega$ +such that all the boundaries except the free surface will the +infinity far, adding the boundary $\partial \Omega_{FS,I}$, where +we know the velocity potential and their gradient from +\ref{eq:laplace3D:incident_waves}. In the figure +\ref{fig:ss:laplace3D:bem} a schematic view of the expanded +domain can be seen.\rc +% +The main advantage is that, as happens with the Inlet and the +Outlet, we know all the needed data about the velocity potential, +so we can significantly reduce the linear system matrix dimensions, +and as happens with the bottom, the geometry is so quite similar +to the $\Omega_{FS}$ one, so no additional discretization or memory +storage is needed.\rc +% +This trick will only works if the Green's function $G(x,y,z,X,Y,Z)$, +and their gradient $H(x,y,z,X,Y,Z)$, goes to zero as $(x,y,z)$ goes +to infinite. In 3D Laplace problems we can use the following Green's +function: +% +\begin{eqnarray} + \label{eq:laplace3D:g} + G(x,y,z,X,Y,Z) = & \dsty{\frac{1}{\sqrt{\left(x - X\right)^2 + \left(y - Y\right)^2 + \left(z - Z\right)^2}}} + \\ + \label{eq:laplace3D:h} + H(x,y,z,X,Y,Z) = & - \dsty{\frac{\left( x - X, y - Y, z - Z \right)}{\left(\left(x - X\right)^2 + \left(y - Y\right)^2 + \left(z - Z\right)^2\right)^{3/2}}} +\end{eqnarray} +% +That in the limit +% +\begin{eqnarray} + \label{eq:laplace3D:limit_g} + \lim_{(x-X)^2 + (y-Y)^2 + (z-Z)^2 \to \infty} G(x,y,z,X,Y,Z) = & 0 + \\ + \label{eq:laplace3D:limit_h} + \lim_{(x-X)^2 + (y-Y)^2 + (z-Z)^2 \to \infty} H(x,y,z,X,Y,Z) = & 0 +\end{eqnarray} +% +So in this case, if the potential of the incidents waves is +a good function along all the free surface we can move from +the domain shown in the figure \ref{fig:ss:laplace2D:bem} to +the shown in the figure \ref{fig:ss:laplace3D:bem}, due to +along the other boundaries the Green's functions $G(x,y,z,X,Y,Z)$ +and $H(x,y,z,X,Y,Z)$ are nulls, not computing in the equation +\ref{eq:laplace2D:reciprocal_relation}. +% +\begin{figure}[ht!] + \centering + \includegraphics[width=0.6\textwidth]{Omega2} + \caption{Computational domain $\Omega$} + \label{fig:ss:laplace3D:bem} +\end{figure} +% +\subsection{Boundary conditions (BC)} +\label{sss:laplace3D:BC} +% +In order to can purpose an evolution process we need to use +the boundary conditions along the free surface. In the most +general way we can rewrite the Bernoulli equation, that is +the dynamic free surface boundary condition (DFSBC), as (see +\citep{yang2004}): +% +\begin{eqnarray} + \label{eq:laplace3D:FS_Bernoulli} + \frac{\mbox{D} \phi(x,y,z;t)}{\mbox{D} t} = + \frac{1}{2}\left\vert \gradient \phi \right\vert^2 + - g z(x,y;t) + - \frac{p_0}{\rho} + - \bs{U}(t) \cdot \gradient \phi(x,y,z;t) + - \frac{\partial \bs{U}(t)}{\partial t} \cdot (x,y,0) +\end{eqnarray} +% +Where $p_0$ is the atmospheric pressure, that we will consider +null, and $\bs{U}(t)$ is the ship velocity, in this case will be +a null vector. Since the material derivative denotes +% +\begin{eqnarray*} + \frac{\mbox{D} f}{\mbox{D} t} = + \frac{\partial f}{\partial t} + \gradient{\phi(x,y,z;t)} \cdot \gradient{f} +\end{eqnarray*} +% +We can rewrite the dynamic boundary condition for this specific case as +% +\begin{eqnarray} + \label{eq:laplace3D:DFSBC} + \frac{\partial \phi(x,y,z;t)}{\partial t} = + - \frac{1}{2}\left\vert \gradient \phi \right\vert^2 + - g z(x,y;t) +\end{eqnarray} +% +Regarding the kinematic free surface boundary condition (KFSBC), in the +most general way we can write that +% +\begin{eqnarray} + \label{eq:laplace3D:FS_Kinematic} + \frac{\mbox{D} z(x,y;t)}{\mbox{D} t} = + \frac{\partial \phi(x,y,z;t)}{\partial z} + - \bs{U}(t) \cdot \gradient z(x,y;t) +\end{eqnarray} +% +Where we can expand the material derivative, writing the KFSBC for this +specific case +% +\begin{eqnarray} + \label{eq:laplace3D:KFSBC} + \frac{\partial z(x,y;t)}{\partial t} = + \frac{\partial \phi(x,y,z;t)}{\partial z} + - \gradient{\phi(x,y,z;t)} \cdot \gradient{z(x,y;t)} +\end{eqnarray} +% +\subsection{Time integration scheme} +\label{sss:laplace3D:TimeIntegration} +% +We may start the simulation in a initial condition where we know the +full free surface shape and velocity potential, including the gradients. +% +\begin{eqnarray} + \label{eq:laplace3D:IC} + \begin{array}{lcl} + z(x,y;t=0) & = & z_0(x,y) + \\ + \phi(x,y,z;t=0) & = & \phi_0(x,y,z) + \\ + \gradient z(x,y;t=0) & = & \gradient z_0(x,y) + \\ + \gradient \phi(x,y,z;t=0) & = & \gradient \phi_0(x,y,z) + \end{array} +\end{eqnarray} +% +In the computational part of the free surface is enough to know the free +surface shape $z_0(x,y)$ and the velocity potential $\phi_0(x,y,z)$.\rc +% +For simplicity we will use an Euler's integration scheme, but the same +method can be easily applied for any other explicit time integrator, like +the Adams-Bashforth ones.\rc +% +In each time step we start knowing the shape of the free surface, and the +velocity potential, and basically we want to compute these fields for the +next time step. To do it the following steps are followed: +% +\begin{enumerate} + \item We use BEM to compute the velocity potential gradient, as will be + described in the section \ref{sss:laplace3D:bem_solve}. + \begin{eqnarray} + \label{eq:laplace3D:time_march:bem} + \gradient{\phi(x,y,z;t)} = \mbox{BEM}\left(\phi(x,y,z;t), z(x,y;t)\right) + \end{eqnarray} + \item We use the KFSBC to compute the derivative of the free surface + elevation, and the DFSBC to know the derivative of the velocity potential. + \begin{eqnarray} + \label{eq:laplace3D:time_march:dzdt} + \frac{\partial z(x,y;t)}{\partial t} = & + \mbox{KFSBC}\left(\gradient{\phi(x,y,z;t)}\right) + \\ + \label{eq:laplace3D:time_march:dphidt} + \frac{\partial \phi(x,y,z;t)}{\partial t} = & + \mbox{DFSBC}\left(z(x,y;t), \gradient{\phi(x,y,z;t)}\right) + \end{eqnarray} + \item And then we can perform the time integration. + \begin{eqnarray} + \label{eq:laplace3D:time_march:z_integrate} + z(x,y;t + \Delta t) = & + z(x,y;t) + + \Delta t \dsty \frac{\partial z(x,y;t)}{\partial t} + \\ + \label{eq:laplace3D:time_march:phi_integrate} + \phi(x,y,z;t + \Delta t) = & + \phi(x,y,z;t + \Delta t) + + \Delta t \dsty \frac{\partial \phi(x,y,z;t)}{\partial t} + \end{eqnarray} +\end{enumerate} +% +\subsection{Discrete Laplace solution using the BEM} +\label{sss:laplace3D:bem_solve} +% +As we have seen in the previous sections we want to use the BEM in order +to compute the velocity potential gradient in the free surface from the +velocity potential value known. In the equation +\ref{eq:laplace3D:reciprocal_relation} we can starting dividing the domain +contour as shown in the figure \ref{fig:ss:laplace3D:bem}, getting the +computational one, denoted by $\partial \Omega_{FS}$, and +the extension one, denoted by $\partial \Omega_{FS,I}$, where the free +surface and the velocity potential and gradient is known for all the +time instants. +% +\begin{eqnarray} + \label{eq:laplace3D:reciprocal_relation:002} + \begin{array}{l} + \frac{1}{2} \phi(X, Y, Z; t) = + \\ + \dsty \int_{\partial \Omega_{FS}} + \phi(x, y, z; t) \frac{\partial G(x, y, z, X, Y, Z)}{\partial \bs{n}(x, y, z)} - + G(x, y, z, X, Y, Z) \frac{\partial \phi(x, y, z; t)}{\partial \bs{n}(x, y, z)} + \mbox{d} s(x, y, z) + \\ + \dsty \int_{\partial \Omega_{FS,I}} + \phi(x, y, z; t) \frac{\partial G(x, y, z, X, Y, Z)}{\partial \bs{n}(x, y, z)} - + G(x, y, z, X, Y, Z) \frac{\partial \phi(x, y, z; t)}{\partial \bs{n}(x, y, z)} + \mbox{d} s(x, y, z) + \end{array} +\end{eqnarray} +% +Where we already assumed that $(x,y,z) \in \partial \Omega$. We can start discretizing +the velocity potential, assuming that the potential and their gradient changes smoothly +enough. The our contours can be divided according to the grid: +% +\begin{eqnarray} + \label{eq:laplace3D:reciprocal_relation:003} + \begin{array}{rl} + \frac{1}{2} \phi_a = & + \dsty \sum_{b=1}^{n_{FS}} + \phi_b + \dsty \int_{\partial \Omega_{FS}^b} H(\bs{x}, \bs{x}_a) \mbox{d} s(\bs{x}) + - + \dsty \sum_{b=1}^{n_{FS}} + \frac{\partial \phi_b}{\partial \bs{n}_b} + \dsty \int_{\partial \Omega_{FS}^b} G(\bs{x}, \bs{x}_a) \mbox{d} s(\bs{x}) + \\ + & + \dsty \sum_{b=1}^{n_{FS,I}} + \phi_b + \dsty \int_{\partial \Omega_{FS,I}^b} H(\bs{x}, \bs{x}_a) \mbox{d} s(\bs{x}) + - + \dsty \sum_{b=1}^{n_{FS,I}} + \frac{\partial \phi_b}{\partial \bs{n}_b} + \dsty \int_{\partial \Omega_{FS,I}^b} G(\bs{x}, \bs{x}_a) \mbox{d} s(\bs{x}) + \end{array} +\end{eqnarray} +% +The functions $G(x,y,z,X,Y,Z)$ and $H(x,y,z,X,Y,Z)$, according to the equations +\ref{eq:laplace3D:g} and \ref{eq:laplace3D:h}, are well defined in all the +subintervals where $(x,y,z) \neq (X,Y,Z)$, and are so quite smooth, so we will +change all the integrals that accomplish it for point evaluations. +% +\begin{eqnarray} + \label{eq:laplace3D:reciprocal_relation:004} + \begin{array}{rl} + \frac{1}{2} \phi_a = & + \phi_a + \dsty \int_{\partial \Omega_{FS}^a} H(\bs{x}, \bs{x}_a) \mbox{d} s(\bs{x}) + - + \frac{\partial \phi_a}{\partial \bs{n}_a} + \dsty \int_{\partial \Omega_{FS}^a} G(\bs{x}, \bs{x}_a) \mbox{d} s(\bs{x}) + \\ + & + \dsty \sum_{\substack{b = 1 \\ b \neq a}}^{n_{FS}} + \left( + \phi_b H_{ba} - \frac{\partial \phi_b}{\partial \bs{n}_b} G_{ba} + \right) S_b + + + \dsty \sum_{b=1}^{n_{FS,I}} + \left( + \phi_b H_{ba} - \frac{\partial \phi_b}{\partial \bs{n}_b} G_{ba} + \right) S_b + \end{array} +\end{eqnarray} +% +The remaining integrals must be treated carefully since the functions are +singular in the center of the interval. $H(x,y,z,X,Y,Z)$ is an odd function, +so the limit of the integral when the radius of the interval goes to zero +is null, being well defined. Regarding the function $G(x,y,z,X,Y,Z)$ is an +even function of order: +% +\begin{eqnarray*} + G(\bs{x},\bs{x_a}) = \mathcal{O}\left(\frac{1}{\vert \bs{x} - \bs{x_a}\vert}\right) +\end{eqnarray*} +% +Which their integral is defined if the function $z(x,y)$ is well defined +as well. So the remaining integrals can be numerically computed, being mindful +that: +% +\begin{enumerate} + \item Can't be evaluated at the point $\bs{x_a}$. + \item Changes too fast around the point $\bs{x_a}$. +\end{enumerate} +% +We will discuss later how to solve this integrals, for the moment we will define +new functions such that: +% +\begin{eqnarray} + \label{eq:laplace3D:g:hat} + \hat G_{ab} = + \left\lbrace \begin{array}{l} + \dsty \int_{\partial \Omega_{FS}^a} G(\bs{x}, \bs{x}_a) \mbox{d} s(\bs{x}); \, \, \mbox{if} \, a = b + \\ + G(\bs{x_b},\bs{x_a}) S_b; \, \, \mbox{if} \, a \neq b + \end{array} \right. + \\ + \label{eq:laplace3D:h:hat} + \hat H_{ab} = + \left\lbrace \begin{array}{l} + \dsty \int_{\partial \Omega_{FS}^a} H(\bs{x}, \bs{x}_a) \mbox{d} s(\bs{x}); \, \, \mbox{if} \, a = b + \\ + H(\bs{x_b},\bs{x_a}) S_b; \, \, \mbox{if} \, a \neq b + \end{array} \right. +\end{eqnarray} +% +So we can rewrite the equation \ref{eq:laplace3D:reciprocal_relation:004} +% +\begin{eqnarray} + \label{eq:laplace3D:reciprocal_relation:005} + \frac{1}{2} \phi_a + = + \dsty \sum_{b=1}^{n_{FS}} + \left( + \phi_b \hat H_{ba} - \frac{\partial \phi_b}{\partial \bs{n}_b} \hat G_{ba} + \right) + + + \dsty \sum_{b=1}^{n_{FS,I}} + \left( + \phi_b \hat H_{ba} - \frac{\partial \phi_b}{\partial \bs{n}_b} \hat G_{ba} + \right) +\end{eqnarray} +% +Where we can move all the terms of the computational free surface that affects +to the gradient of the velocity potential (that is the value that we want to +compute) to left hand side, and let all the other ones in the right hand side +of the equation +% +\begin{eqnarray} + \label{eq:laplace3D:reciprocal_relation:006} + \dsty \sum_{b \in \partial \Omega_{FS}} + \frac{\partial \phi_b}{\partial \bs{n}_b} \hat G_{ba} + = + - + \frac{1}{2} \phi_a + + + \dsty \sum_{b \in \partial \Omega_{FS}} + \phi_b \hat H_{ba} + + + \dsty \sum_{b \in \partial \Omega_{FS,I}} + \left( + \phi_b \hat H_{ba} - + \frac{\partial \phi_b}{\partial \bs{n}_b} \hat G_{ba} + \right) +\end{eqnarray} +% +The equation \ref{eq:laplace3D:reciprocal_relation:006}, that +has been written for the velocity potential at one point $\bs{x}_a$, +can be written for all the points of the free surface along +the computational domain using the matrix notation +% +\begin{eqnarray} + \label{eq:laplace3D:reciprocal_relation:007} + \mathcal{G} \left[ \frac{ \partial \phi}{\partial \bs{n}} \right] + = + \left( \mathcal{H} - \frac{1}{2} \mathcal{I} \right) \left[ \phi \right] + + + \mathcal{H}_{FS,I} \left[ \phi \right]_{FS,I} + - + \mathcal{G}_{FS,I} \left[ \frac{ \partial \phi}{\partial \bs{n}} \right]_{FS,I} +\end{eqnarray} +% +Note that the area of the elements $S_b$ has been included into +the matrices. The equation +\ref{eq:laplace3D:reciprocal_relation:007} is a linear system +of equations that can be numerically solved, either inverting +the matrix, or using an iterative method. The matrix inversion +is probably the best way for linear seakeeping codes, where the +same matrix will be ever used, but in this case the iterative +method is the faster way.\rc +% +The method described along this section allows to us to compute +the gradient of the velocity potential along the free surface +knowing the potential in the computational free surface, and both +velocity potential and the gradient along the extended free +surface. +% +\subsection{Integrals computation} +\label{sss:laplace3D:integrals} +% +In the equations \ref{eq:laplace3D:g:hat} and \ref{eq:laplace3D:g:hat} +we have introduced two inconvenient integrals. Even though the functions +are not well defined when $\bs{x} = \bs{x_a}$, their integrals it is. +For instance, if we can assume that the free surface is fully planar +($z = 0$), the integrals can be analytically computed +% +\begin{eqnarray*} + \dsty \int_{y_a - \delta y}^{y_a + \delta y} \int_{x_a - \delta x}^{x_a + \delta x} + G(x,y,0,x_a,y_a,0) + \, \mbox{d}x \, \mbox{d}y + = & + \dsty \frac{ + \delta x \, \, \mbox{asinh}\left(\frac{\delta y}{\delta x}\right) + + + \delta y \, \, \mbox{asinh}\left(\frac{\delta x}{\delta y}\right) + }{\pi} + \\ + \dsty \int_{y_a - \delta y}^{y_a + \delta y} \int_{x_a - \delta x}^{x_a + \delta x} + H(x,y,0,x_a,y_a,0) + \, \mbox{d}x \, \mbox{d}y + = & + 0 +\end{eqnarray*} +% +But can not be analytically computed for every function $z(x,y)$, being +necessary to compute it in a numerical way.\rc +% +In the figure \ref{fig:ss:laplace3D:integral} a schematic representation +of the integration method is shown. Let we want to compute the integral +for an element of the grid $(x_a,y_a)$, then we subdivide the element in +\textbf{a even number} of subelements of area $dx \cdot dy$, so we can +assert that any subelement will be evaluated in the point $(x_a,y_a)$, +but as near as we want because we can ever add more subelements; then we +can numerically approximate the integral by (here in after we will use +only the function $G(\bs{x}, bs{x_a})$, because same method can be applied +to the function $H(\bs{x}, bs{x_a})$). +% +\begin{eqnarray} + \label{eq:laplace3D:integral:g} + \dsty \int_{\partial \Omega_{FS}^a} G(\bs{x}, \bs{x}_a) \mbox{d} s(\bs{x}) + \simeq + \sum_{i=1}^{n_x} \sum_{j=1}^{n_y} G(x_i,y_j,z(x_i,y_i), x_a, y_a, z(x_a, y_a)) \, dx \, dy +\end{eqnarray} +% +Of course the value $z(x_a, y_a)$ is known, but not the function $z(x_i,y_i)$ +because is evaluated in points that are not reflected in the grid, so we must +compute this points from the available data. We will start renormalizing the +coordinates such that: +% +\begin{eqnarray} + \label{eq:laplace3D:integral:uv} + \begin{array}{lcl} + u & = & \dsty \frac{x - \left(x_a - Dx\right)}{2 Dx} + \\ + v & = & \dsty \frac{y - \left(y_a - Dy\right)}{2 Dy} + \end{array} +\end{eqnarray} +% +So we know the value of $z$ for all the combinations of $u = 0,0.5,1$ and +$v = 0,0.5,1$. Then, to can evaluate the function $z(u,v)$ for all $u,v$ +values we may to build a Spline surface with the data known from the 9 +points shown in the figure \ref{fig:ss:laplace3D:integral}. The Spline +surface can be characterized as +% +\begin{eqnarray} + \label{eq:laplace3D:integral:spline} + z(u,v) = k_0 + k_u u + k_v v + k_{uv} u v + k_{uu} u^2 + k_{vv} v^2 + + k_{uuv} u^2 v + k_{uvv} u v^2 + k_{uuvv} u^2 v^2 +\end{eqnarray} +% +In the equation \ref{eq:laplace3D:integral:spline} we have 9 unknown +coefficients, but we have available $z(u,v)$ for 9 points, so have 9 +unknowns with 9 equations that can be set as a linear system of +equations, that results in the following coefficients: +% +\begin{eqnarray} + \label{eq:laplace3D:integral:k} + \begin{array}{lcl} + k_0 & = & z \left( 0,0 \right) + \\ + k_u & = & - z \left( 1,0 \right) + 4 z \left( \frac{1}{2},0 \right) - 3 z \left( 0,0 \right) + \\ + k_v & = & - z \left( 0,1 \right) + 4 z \left( 0,\frac{1}{2} \right) - 3 z \left( 0,0 \right) + \\ + k_{uv} & = & z \left( 1,1 \right) - 4 z \left( 1,\frac{1}{2} \right) + 3 z \left( 1,0 \right) + - 4 z \left( \frac{1}{2},1 \right) + 16 z \left( \frac{1}{2},\frac{1}{2} \right) + \\ & & + - 12 z \left( \frac{1}{2},0 \right) + 3 z \left( 0,1 \right) + - 12 z \left( 0,\frac{1}{2} \right) + 9 z \left( 0,0 \right) + \\ + k_{uu} & = & 2 z \left( 1,0 \right) - 4 z \left( \frac{1}{2},0 \right) + 2 z \left( 1,0 \right) + \\ + k_{vv} & = & 2 z \left( 0,1 \right) - 4 z \left( 0,\frac{1}{2} \right) + 2 z \left( 1,0 \right) + \\ + k_{uuv} & = & - 2 z \left( 1,1 \right) + 8 z \left( 1,\frac{1}{2} \right) - 6 z \left( 1,0 \right) + + 4 z \left( \frac{1}{2},1 \right) - 16 z \left( \frac{1}{2},\frac{1}{2} \right) + \\ & & + + 12 z \left( \frac{1}{2},0 \right) - 2 z \left( 0,1 \right) + + 8 z \left( 0,\frac{1}{2} \right) - 6 z \left( 0,0 \right) + \\ + k_{uvv} & = & - 2 z \left( 1,1 \right) + 4 z \left( 1,\frac{1}{2} \right) - 2 z \left( 1,0 \right) + + 8 z \left( \frac{1}{2},1 \right) - 16 z \left( \frac{1}{2},\frac{1}{2} \right) + \\ & & + + 8 z \left( \frac{1}{2},0 \right) - 6 z \left( 0,1 \right) + + 12 z \left( 0,\frac{1}{2} \right) - 6 z \left( 0,0 \right) + \\ + k_{uuvv} & = & 4 z \left( 1,1 \right) - 8 z \left( 1,\frac{1}{2} \right) + 4 z \left( 1,0 \right) + - 8 z \left( \frac{1}{2},1 \right) + 16 z \left( \frac{1}{2},\frac{1}{2} \right) + \\ & & + - 8 z \left( \frac{1}{2},0 \right) + 4 z \left( 0,1 \right) + - 8 z \left( 0,\frac{1}{2} \right) + 4 z \left( 0,0 \right) + \end{array} +\end{eqnarray} +% +So using the equation \ref{eq:laplace3D:integral:g} to \ref{eq:laplace3D:integral:k} +we can compute the integrals in the equations \ref{eq:laplace3D:g:hat} and +\ref{eq:laplace3D:h:hat}. +% +\begin{figure}[ht!] + \centering + \includegraphics[width=0.6\textwidth]{Integral} + \caption{Integration method scheme} + \label{fig:ss:laplace3D:integral} +\end{figure} +% +\section{BEM test} +\label{ss:laplace3D:test} +% +\subsection{General} +\label{sss:laplace3D:test:general} +% +A Python script has been provided with this document in the subfolder \textbf{test}. +In the script all this theory is tested in order to know if the BEM is well purposed, +and the errors that can be expected from the method application.\rc +% +In the test, for the moment, only one wave will be set, and the computational free +surface will be big enough to contain 2 wave lengths. In this case a wave period +of $T = 2.5 s$ is used, resulting in a wave of 10 meters.\rc +% +In the figure \ref{fig:laplace3D:test:wave} the wave used, that runs in the x direction, +is shown. The free surface will be extended while $G(x,y,z,X,Y,Z) > 0.1$. +% +\begin{figure}[ht!] + \centering + \includegraphics[width=0.6\textwidth]{test_wave} + \caption{Wave used in the test} + \label{fig:laplace3D:test:wave} +\end{figure} +% +\subsection{Direct method} +\label{sss:laplace3D:test:direct} +% +The direct method consist in evaluate the velocity potential in several points +using the equation \ref{eq:laplace3D:reciprocal_relation:005}, testing the error +get.\rc +% +If we apply the direct method for all the points of the computational free surface, +we can compute the root mean square error as +% +\begin{eqnarray*} + RMS(nx,ny) = \sqrt{\frac{1}{nx \, ny} \sum_{i=1}^{nx} \sum_{j=1}^{ny} + \left( \phi_{direct}(x_i,y_j) - \phi(x_i,y_j) \right)^2 + } +\end{eqnarray*} +% +For $nx = 31$ and $ny = 15$ we have $RMS(31,15) = 0.08$. In the figure +\ref{fig:laplace3D:test:direct} the analytic velocity potential, and the +interpolated using the direct method, for a slice in the middle of the +free surface ($y=0$).\rc +% +The results quality is good, and can be improved increasing the number of +points in the computational free surface. +% +\begin{figure}[ht!] + \centering + \includegraphics[width=0.6\textwidth]{test_direct} + \caption{Direct method} + \label{fig:laplace3D:test:direct} +\end{figure} +% +\subsection{BEM} +\label{sss:laplace3D:test:bem} +% +In this case we want to apply the equation \ref{eq:laplace3D:reciprocal_relation:006}, +where a linear system of equations is purposed in order to compute the gradient of the +velocity potential, projected over the normal, for all the points of the grid. +% +For $nx = 31$ and $ny = 15$ we have $RMS(31,15) = 0.04$. In the figure +\ref{fig:laplace3D:test:bem} the analytic velocity potential, and the +interpolated using the direct method, for a slice in the middle of the +free surface ($y=0$).\rc +% +The results quality is nice like in the direct method. In order to get enough good +results at least 15 points per wave length must be used (like in this application). +% +\begin{figure}[ht!] + \centering + \includegraphics[width=0.6\textwidth]{test_bem} + \caption{BEM solution} + \label{fig:laplace3D:test:bem} +\end{figure} +% \ No newline at end of file diff --git a/src/Mod/Ship/simRun/theory/main.aux b/src/Mod/Ship/simRun/theory/main.aux new file mode 100644 index 000000000..e21f47e16 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/main.aux @@ -0,0 +1,125 @@ +\relax +\bibstyle{plainnat} +\providecommand\HyperFirstAtBeginDocument{\AtBeginDocument} +\HyperFirstAtBeginDocument{\ifx\hyper@anchor\@undefined +\global\let\oldcontentsline\contentsline +\gdef\contentsline#1#2#3#4{\oldcontentsline{#1}{#2}{#3}} +\global\let\oldnewlabel\newlabel +\gdef\newlabel#1#2{\newlabelxx{#1}#2} +\gdef\newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}} +\AtEndDocument{\ifx\hyper@anchor\@undefined +\let\contentsline\oldcontentsline +\let\newlabel\oldnewlabel +\fi} +\fi} +\global\let\hyper@last\relax +\gdef\HyperFirstAtBeginDocument#1{#1} +\providecommand\HyField@AuxAddToFields[1]{} +\citation{bem_2007} +\citation{vinayan2007} +\@writefile{toc}{\contentsline {chapter}{\numberline {1}Introduction}{5}{chapter.1}} +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{s:introduction}{{1}{5}{Introduction\relax }{chapter.1}{}} +\@writefile{toc}{\contentsline {section}{\numberline {1.1}Objective}{5}{section.1.1}} +\citation{bem_2007} +\@writefile{toc}{\contentsline {chapter}{\numberline {2}Governing equations}{7}{chapter.2}} +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{s:governing_equations}{{2}{7}{Governing equations\relax }{chapter.2}{}} +\newlabel{eq:governing_equations:v_potential}{{2.2}{7}{Governing equations\relax }{equation.2.0.2}{}} +\newlabel{eq:governing_equations:laplace}{{2.3}{7}{Governing equations\relax }{equation.2.0.3}{}} +\newlabel{eq:governing_equations:bernoulli}{{2.4}{7}{Governing equations\relax }{equation.2.0.3}{}} +\@writefile{toc}{\contentsline {chapter}{\numberline {3}Waves propagations in 2D plane}{9}{chapter.3}} +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{s:laplace2D}{{3}{9}{Waves propagations in 2D plane\relax }{chapter.3}{}} +\@writefile{toc}{\contentsline {section}{\numberline {3.1}General}{9}{section.3.1}} +\@writefile{toc}{\contentsline {section}{\numberline {3.2}Incident waves}{9}{section.3.2}} +\newlabel{eq:laplace2D:incident_waves}{{3.1}{9}{Incident waves\relax }{equation.3.2.1}{}} +\newlabel{eq:laplace2D:c_general}{{3.2}{9}{Incident waves\relax }{equation.3.2.2}{}} +\newlabel{eq:laplace2D:c_deep}{{3.3}{9}{Incident waves\relax }{equation.3.2.3}{}} +\newlabel{eq:laplace2D:k_w}{{3.4}{9}{Incident waves\relax }{equation.3.2.4}{}} +\newlabel{eq:laplace2D:incident_waves_potential}{{3.5}{9}{Incident waves\relax }{equation.3.2.5}{}} +\@writefile{toc}{\contentsline {section}{\numberline {3.3}BEM applied to Laplace 2D problem}{10}{section.3.3}} +\newlabel{ss:laplace2D:bem}{{3.3}{10}{BEM applied to Laplace 2D problem\relax }{section.3.3}{}} +\newlabel{eq:laplace2D:reciprocal_relation}{{3.6}{10}{BEM applied to Laplace 2D problem\relax }{equation.3.3.6}{}} +\citation{vinayan2007} +\newlabel{eq:laplace2D:g}{{3.7}{11}{BEM applied to Laplace 2D problem\relax }{equation.3.3.7}{}} +\newlabel{eq:laplace2D:h}{{3.8}{11}{BEM applied to Laplace 2D problem\relax }{equation.3.3.7}{}} +\newlabel{eq:laplace2D:limit_g}{{3.9}{11}{BEM applied to Laplace 2D problem\relax }{equation.3.3.9}{}} +\newlabel{eq:laplace2D:limit_h}{{3.10}{11}{BEM applied to Laplace 2D problem\relax }{equation.3.3.9}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {3.1}{\ignorespaces Computational domain $\Omega $}}{11}{figure.3.1}} +\newlabel{fig:ss:laplace2D:bem}{{3.1}{11}{Computational domain $\Omega $\relax }{figure.3.1}{}} +\@writefile{toc}{\contentsline {section}{\numberline {3.4}Conclusions to Laplace 2D problem}{11}{section.3.4}} +\newlabel{ss:laplace2D:conclusions}{{3.4}{11}{Conclusions to Laplace 2D problem\relax }{section.3.4}{}} +\@writefile{toc}{\contentsline {chapter}{\numberline {4}Waves propagations in 3D}{13}{chapter.4}} +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{s:laplace3D}{{4}{13}{Waves propagations in 3D\relax }{chapter.4}{}} +\@writefile{toc}{\contentsline {section}{\numberline {4.1}General}{13}{section.4.1}} +\@writefile{toc}{\contentsline {section}{\numberline {4.2}Incident waves}{13}{section.4.2}} +\newlabel{eq:laplace3D:incident_waves}{{4.1}{13}{Incident waves\relax }{equation.4.2.1}{}} +\@writefile{toc}{\contentsline {section}{\numberline {4.3}BEM applied to Laplace 3D problem}{13}{section.4.3}} +\newlabel{ss:laplace3D:bem}{{4.3}{13}{BEM applied to Laplace 3D problem\relax }{section.4.3}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.3.1}Computational domain}{13}{subsection.4.3.1}} +\newlabel{sss:laplace3D:computational_domain}{{4.3.1}{13}{Computational domain\relax }{subsection.4.3.1}{}} +\newlabel{eq:laplace3D:reciprocal_relation}{{4.2}{13}{Computational domain\relax }{equation.4.3.2}{}} +\citation{yang2004} +\newlabel{eq:laplace3D:g}{{4.3}{14}{Computational domain\relax }{equation.4.3.3}{}} +\newlabel{eq:laplace3D:h}{{4.4}{14}{Computational domain\relax }{equation.4.3.3}{}} +\newlabel{eq:laplace3D:limit_g}{{4.5}{14}{Computational domain\relax }{equation.4.3.5}{}} +\newlabel{eq:laplace3D:limit_h}{{4.6}{14}{Computational domain\relax }{equation.4.3.5}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {4.1}{\ignorespaces Computational domain $\Omega $}}{14}{figure.4.1}} +\newlabel{fig:ss:laplace3D:bem}{{4.1}{14}{Computational domain $\Omega $\relax }{figure.4.1}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.3.2}Boundary conditions (BC)}{14}{subsection.4.3.2}} +\newlabel{sss:laplace3D:BC}{{4.3.2}{14}{Boundary conditions (BC)\relax }{subsection.4.3.2}{}} +\newlabel{eq:laplace3D:FS_Bernoulli}{{4.7}{14}{Boundary conditions (BC)\relax }{equation.4.3.7}{}} +\newlabel{eq:laplace3D:DFSBC}{{4.8}{15}{Boundary conditions (BC)\relax }{equation.4.3.8}{}} +\newlabel{eq:laplace3D:FS_Kinematic}{{4.9}{15}{Boundary conditions (BC)\relax }{equation.4.3.9}{}} +\newlabel{eq:laplace3D:KFSBC}{{4.10}{15}{Boundary conditions (BC)\relax }{equation.4.3.10}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.3.3}Time integration scheme}{15}{subsection.4.3.3}} +\newlabel{sss:laplace3D:TimeIntegration}{{4.3.3}{15}{Time integration scheme\relax }{subsection.4.3.3}{}} +\newlabel{eq:laplace3D:IC}{{4.11}{15}{Time integration scheme\relax }{equation.4.3.11}{}} +\newlabel{eq:laplace3D:time_march:bem}{{4.12}{15}{Time integration scheme\relax }{equation.4.3.12}{}} +\newlabel{eq:laplace3D:time_march:dzdt}{{4.13}{15}{Time integration scheme\relax }{equation.4.3.13}{}} +\newlabel{eq:laplace3D:time_march:dphidt}{{4.14}{15}{Time integration scheme\relax }{equation.4.3.13}{}} +\newlabel{eq:laplace3D:time_march:z_integrate}{{4.15}{15}{Time integration scheme\relax }{equation.4.3.15}{}} +\newlabel{eq:laplace3D:time_march:phi_integrate}{{4.16}{15}{Time integration scheme\relax }{equation.4.3.15}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.3.4}Discrete Laplace solution using the BEM}{16}{subsection.4.3.4}} +\newlabel{sss:laplace3D:bem_solve}{{4.3.4}{16}{Discrete Laplace solution using the BEM\relax }{subsection.4.3.4}{}} +\newlabel{eq:laplace3D:reciprocal_relation:002}{{4.17}{16}{Discrete Laplace solution using the BEM\relax }{equation.4.3.17}{}} +\newlabel{eq:laplace3D:reciprocal_relation:003}{{4.18}{16}{Discrete Laplace solution using the BEM\relax }{equation.4.3.18}{}} +\newlabel{eq:laplace3D:reciprocal_relation:004}{{4.19}{16}{Discrete Laplace solution using the BEM\relax }{equation.4.3.19}{}} +\newlabel{eq:laplace3D:g:hat}{{4.20}{16}{Discrete Laplace solution using the BEM\relax }{equation.4.3.20}{}} +\newlabel{eq:laplace3D:h:hat}{{4.21}{16}{Discrete Laplace solution using the BEM\relax }{equation.4.3.20}{}} +\newlabel{eq:laplace3D:reciprocal_relation:005}{{4.22}{17}{Discrete Laplace solution using the BEM\relax }{equation.4.3.22}{}} +\newlabel{eq:laplace3D:reciprocal_relation:006}{{4.23}{17}{Discrete Laplace solution using the BEM\relax }{equation.4.3.23}{}} +\newlabel{eq:laplace3D:reciprocal_relation:007}{{4.24}{17}{Discrete Laplace solution using the BEM\relax }{equation.4.3.24}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.3.5}Integrals computation}{17}{subsection.4.3.5}} +\newlabel{sss:laplace3D:integrals}{{4.3.5}{17}{Integrals computation\relax }{subsection.4.3.5}{}} +\newlabel{eq:laplace3D:integral:g}{{4.25}{17}{Integrals computation\relax }{equation.4.3.25}{}} +\newlabel{eq:laplace3D:integral:uv}{{4.26}{18}{Integrals computation\relax }{equation.4.3.26}{}} +\newlabel{eq:laplace3D:integral:spline}{{4.27}{18}{Integrals computation\relax }{equation.4.3.27}{}} +\newlabel{eq:laplace3D:integral:k}{{4.28}{18}{Integrals computation\relax }{equation.4.3.28}{}} +\@writefile{toc}{\contentsline {section}{\numberline {4.4}BEM test}{18}{section.4.4}} +\newlabel{ss:laplace3D:test}{{4.4}{18}{BEM test\relax }{section.4.4}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.4.1}General}{18}{subsection.4.4.1}} +\newlabel{sss:laplace3D:test:general}{{4.4.1}{18}{General\relax }{subsection.4.4.1}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {4.2}{\ignorespaces Integration method scheme}}{19}{figure.4.2}} +\newlabel{fig:ss:laplace3D:integral}{{4.2}{19}{Integration method scheme\relax }{figure.4.2}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {4.3}{\ignorespaces Wave used in the test}}{19}{figure.4.3}} +\newlabel{fig:laplace3D:test:wave}{{4.3}{19}{Wave used in the test\relax }{figure.4.3}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.4.2}Direct method}{19}{subsection.4.4.2}} +\newlabel{sss:laplace3D:test:direct}{{4.4.2}{19}{Direct method\relax }{subsection.4.4.2}{}} +\bibdata{bib} +\@writefile{lof}{\contentsline {figure}{\numberline {4.4}{\ignorespaces Direct method}}{20}{figure.4.4}} +\newlabel{fig:laplace3D:test:direct}{{4.4}{20}{Direct method\relax }{figure.4.4}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.4.3}BEM}{20}{subsection.4.4.3}} +\newlabel{sss:laplace3D:test:bem}{{4.4.3}{20}{BEM\relax }{subsection.4.4.3}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {4.5}{\ignorespaces BEM solution}}{21}{figure.4.5}} +\newlabel{fig:laplace3D:test:bem}{{4.5}{21}{BEM solution\relax }{figure.4.5}{}} +\bibcite{bem_2007}{{1}{2007}{{Ang}}{{}}} +\bibcite{vinayan2007}{{2}{2007}{{Vinayan and Kinnas}}{{}}} +\bibcite{yang2004}{{3}{2004}{{Yang}}{{}}} +\@writefile{toc}{\contentsline {chapter}{Bibliography}{23}{chapter*.2}} diff --git a/src/Mod/Ship/simRun/theory/main.bbl b/src/Mod/Ship/simRun/theory/main.bbl new file mode 100644 index 000000000..501e72326 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/main.bbl @@ -0,0 +1,24 @@ +\begin{thebibliography}{3} +\providecommand{\natexlab}[1]{#1} +\providecommand{\url}[1]{\texttt{#1}} +\expandafter\ifx\csname urlstyle\endcsname\relax + \providecommand{\doi}[1]{doi: #1}\else + \providecommand{\doi}{doi: \begingroup \urlstyle{rm}\Url}\fi + +\bibitem[Ang(2007)]{bem_2007} +Whye-Teong Ang. +\newblock \emph{A Beginner’s Course in Boundary Element Methods}. +\newblock Cambridge University Press, New York, 2007. + +\bibitem[Vinayan and Kinnas(2007)]{vinayan2007} +V.~Vinayan and S.~A. Kinnas. +\newblock A bem for the propagation of nonlinear planar free-surface waves. +\newblock \emph{Electronic Journal of Boundary Elements}, 5:\penalty0 17--40, + 2007. + +\bibitem[Yang(2004)]{yang2004} +Jinghai Yang. +\newblock \emph{Time domain, nonlinear theories on ship motions}. +\newblock PhD thesis, University of Hawaii, 2004. + +\end{thebibliography} diff --git a/src/Mod/Ship/simRun/theory/main.blg b/src/Mod/Ship/simRun/theory/main.blg new file mode 100644 index 000000000..72657ecfe --- /dev/null +++ b/src/Mod/Ship/simRun/theory/main.blg @@ -0,0 +1,48 @@ +This is BibTeX, Version 0.99d (TeX Live 2012/Debian) +Capacity: max_strings=35307, hash_size=35307, hash_prime=30011 +The top-level auxiliary file: main.aux +The style file: plainnat.bst +Database file #1: bib.bib +Warning--can't use both author and editor fields in bem_2007 +You've used 3 entries, + 2773 wiz_defined-function locations, + 726 strings with 6674 characters, +and the built_in function-call counts, 1030 in all, are: += -- 88 +> -- 41 +< -- 3 ++ -- 15 +- -- 12 +* -- 67 +:= -- 173 +add.period$ -- 9 +call.type$ -- 3 +change.case$ -- 11 +chr.to.int$ -- 3 +cite$ -- 7 +duplicate$ -- 56 +empty$ -- 92 +format.name$ -- 17 +if$ -- 207 +int.to.chr$ -- 1 +int.to.str$ -- 1 +missing$ -- 3 +newline$ -- 23 +num.names$ -- 12 +pop$ -- 25 +preamble$ -- 1 +purify$ -- 10 +quote$ -- 0 +skip$ -- 41 +stack$ -- 0 +substring$ -- 21 +swap$ -- 4 +text.length$ -- 0 +text.prefix$ -- 0 +top$ -- 0 +type$ -- 28 +warning$ -- 1 +while$ -- 10 +width$ -- 0 +write$ -- 45 +(There was 1 warning) diff --git a/src/Mod/Ship/simRun/theory/main.log b/src/Mod/Ship/simRun/theory/main.log new file mode 100644 index 000000000..a224a19a6 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/main.log @@ -0,0 +1,827 @@ +This is pdfTeX, Version 3.1415926-2.4-1.40.13 (TeX Live 2012/Debian) (format=pdflatex 2012.12.24) 1 APR 2013 19:55 +entering extended mode + restricted \write18 enabled. + %&-line parsing enabled. +**main.tex +(./main.tex +LaTeX2e <2011/06/27> +Babel and hyphenation patterns for english, dumylang, nohyphenation, lo +aded. +(/usr/share/texlive/texmf-dist/tex/latex/base/book.cls +Document Class: book 2007/10/19 v1.4h Standard LaTeX document class +(/usr/share/texlive/texmf-dist/tex/latex/base/bk12.clo +File: bk12.clo 2007/10/19 v1.4h Standard LaTeX file (size option) +) +\c@part=\count79 +\c@chapter=\count80 +\c@section=\count81 +\c@subsection=\count82 +\c@subsubsection=\count83 +\c@paragraph=\count84 +\c@subparagraph=\count85 +\c@figure=\count86 +\c@table=\count87 +\abovecaptionskip=\skip41 +\belowcaptionskip=\skip42 +\bibindent=\dimen102 +) +(/usr/share/texlive/texmf-dist/tex/latex/natbib/natbib.sty +Package: natbib 2010/09/13 8.31b (PWD, AO) +\bibhang=\skip43 +\bibsep=\skip44 +LaTeX Info: Redefining \cite on input line 694. +\c@NAT@ctr=\count88 +) +(/usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty +Package: graphicx 1999/02/16 v1.0f Enhanced LaTeX Graphics (DPC,SPQR) + +(/usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty +Package: keyval 1999/03/16 v1.13 key=value parser (DPC) +\KV@toks@=\toks14 +) +(/usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty +Package: graphics 2009/02/05 v1.0o Standard LaTeX Graphics (DPC,SPQR) + +(/usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty +Package: trig 1999/03/16 v1.09 sin cos tan (DPC) +) +(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/graphics.cfg +File: graphics.cfg 2010/04/23 v1.9 graphics configuration of TeX Live +) +Package graphics Info: Driver file: pdftex.def on input line 91. + +(/usr/share/texlive/texmf-dist/tex/latex/pdftex-def/pdftex.def +File: pdftex.def 2011/05/27 v0.06d Graphics/color for pdfTeX + +(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/infwarerr.sty +Package: infwarerr 2010/04/08 v1.3 Providing info/warning/error messages (HO) +) +(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ltxcmds.sty +Package: ltxcmds 2011/11/09 v1.22 LaTeX kernel commands for general use (HO) +) +\Gread@gobject=\count89 +)) +\Gin@req@height=\dimen103 +\Gin@req@width=\dimen104 +) +(/usr/share/texlive/texmf-dist/tex/latex/tools/verbatim.sty +Package: verbatim 2003/08/22 v1.5q LaTeX2e package for verbatim enhancements +\every@verbatim=\toks15 +\verbatim@line=\toks16 +\verbatim@in@stream=\read1 +) +(/usr/share/texlive/texmf-dist/tex/latex/graphics/color.sty +Package: color 2005/11/14 v1.0j Standard LaTeX Color (DPC) + +(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/color.cfg +File: color.cfg 2007/01/18 v1.5 color configuration of teTeX/TeXLive +) +Package color Info: Driver file: pdftex.def on input line 130. +) +(/usr/share/texlive/texmf-dist/tex/latex/colortbl/colortbl.sty +Package: colortbl 2012/02/13 v1.0a Color table columns (DPC) + +(/usr/share/texlive/texmf-dist/tex/latex/tools/array.sty +Package: array 2008/09/09 v2.4c Tabular extension package (FMi) +\col@sep=\dimen105 +\extrarowheight=\dimen106 +\NC@list=\toks17 +\extratabsurround=\skip45 +\backup@length=\skip46 +) +\everycr=\toks18 +\minrowclearance=\skip47 +) +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/hyperref.sty +Package: hyperref 2012/05/13 v6.82q Hypertext links for LaTeX + +(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/hobsub-hyperref.sty +Package: hobsub-hyperref 2012/05/28 v1.13 Bundle oberdiek, subset hyperref (HO) + + +(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/hobsub-generic.sty +Package: hobsub-generic 2012/05/28 v1.13 Bundle oberdiek, subset generic (HO) +Package: hobsub 2012/05/28 v1.13 Construct package bundles (HO) +Package hobsub Info: Skipping package `infwarerr' (already loaded). +Package hobsub Info: Skipping package `ltxcmds' (already loaded). +Package: ifluatex 2010/03/01 v1.3 Provides the ifluatex switch (HO) +Package ifluatex Info: LuaTeX not detected. +Package: ifvtex 2010/03/01 v1.5 Detect VTeX and its facilities (HO) +Package ifvtex Info: VTeX not detected. +Package: intcalc 2007/09/27 v1.1 Expandable calculations with integers (HO) +Package: ifpdf 2011/01/30 v2.3 Provides the ifpdf switch (HO) +Package ifpdf Info: pdfTeX in PDF mode is detected. +Package: etexcmds 2011/02/16 v1.5 Avoid name clashes with e-TeX commands (HO) +Package etexcmds Info: Could not find \expanded. +(etexcmds) That can mean that you are not using pdfTeX 1.50 or +(etexcmds) that some package has redefined \expanded. +(etexcmds) In the latter case, load this package earlier. +Package: kvsetkeys 2012/04/25 v1.16 Key value parser (HO) +Package: kvdefinekeys 2011/04/07 v1.3 Define keys (HO) +Package: pdftexcmds 2011/11/29 v0.20 Utility functions of pdfTeX for LuaTeX (HO +) +Package pdftexcmds Info: LuaTeX not detected. +Package pdftexcmds Info: \pdf@primitive is available. +Package pdftexcmds Info: \pdf@ifprimitive is available. +Package pdftexcmds Info: \pdfdraftmode found. +Package: pdfescape 2011/11/25 v1.13 Implements pdfTeX's escape features (HO) +Package: bigintcalc 2012/04/08 v1.3 Expandable calculations on big integers (HO +) +Package: bitset 2011/01/30 v1.1 Handle bit-vector datatype (HO) +Package: uniquecounter 2011/01/30 v1.2 Provide unlimited unique counter (HO) +) +Package hobsub Info: Skipping package `hobsub' (already loaded). +Package: letltxmacro 2010/09/02 v1.4 Let assignment for LaTeX macros (HO) +Package: hopatch 2012/05/28 v1.2 Wrapper for package hooks (HO) +Package: xcolor-patch 2011/01/30 xcolor patch +Package: atveryend 2011/06/30 v1.8 Hooks at the very end of document (HO) +Package atveryend Info: \enddocument detected (standard20110627). +Package: atbegshi 2011/10/05 v1.16 At begin shipout hook (HO) +Package: refcount 2011/10/16 v3.4 Data extraction from label references (HO) +Package: hycolor 2011/01/30 v1.7 Color options for hyperref/bookmark (HO) +) +(/usr/share/texlive/texmf-dist/tex/generic/ifxetex/ifxetex.sty +Package: ifxetex 2010/09/12 v0.6 Provides ifxetex conditional +) +(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/kvoptions.sty +Package: kvoptions 2011/06/30 v3.11 Key value format for package options (HO) +) +\@linkdim=\dimen107 +\Hy@linkcounter=\count90 +\Hy@pagecounter=\count91 + +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/pd1enc.def +File: pd1enc.def 2012/05/13 v6.82q Hyperref: PDFDocEncoding definition (HO) +) +\Hy@SavedSpaceFactor=\count92 + +(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/hyperref.cfg +File: hyperref.cfg 2002/06/06 v1.2 hyperref configuration of TeXLive +) +Package hyperref Info: Hyper figures OFF on input line 4062. +Package hyperref Info: Link nesting OFF on input line 4067. +Package hyperref Info: Hyper index ON on input line 4070. +Package hyperref Info: Plain pages OFF on input line 4077. +Package hyperref Info: Backreferencing OFF on input line 4082. +Package hyperref Info: Implicit mode ON; LaTeX internals redefined. +Package hyperref Info: Bookmarks ON on input line 4300. +\c@Hy@tempcnt=\count93 + +(/usr/share/texlive/texmf-dist/tex/latex/url/url.sty +\Urlmuskip=\muskip10 +Package: url 2006/04/12 ver 3.3 Verb mode for urls, etc. +) +LaTeX Info: Redefining \url on input line 4653. +\Fld@menulength=\count94 +\Field@Width=\dimen108 +\Fld@charsize=\dimen109 +Package hyperref Info: Hyper figures OFF on input line 5773. +Package hyperref Info: Link nesting OFF on input line 5778. +Package hyperref Info: Hyper index ON on input line 5781. +Package hyperref Info: backreferencing OFF on input line 5788. +Package hyperref Info: Link coloring OFF on input line 5793. +Package hyperref Info: Link coloring with OCG OFF on input line 5798. +Package hyperref Info: PDF/A mode OFF on input line 5803. +LaTeX Info: Redefining \ref on input line 5843. +LaTeX Info: Redefining \pageref on input line 5847. +\Hy@abspage=\count95 +\c@Item=\count96 +\c@Hfootnote=\count97 +) + +Package hyperref Message: Driver (autodetected): hpdftex. + +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/hpdftex.def +File: hpdftex.def 2012/05/13 v6.82q Hyperref driver for pdfTeX +\Fld@listcount=\count98 +\c@bookmark@seq@number=\count99 + +(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/rerunfilecheck.sty +Package: rerunfilecheck 2011/04/15 v1.7 Rerun checks for auxiliary files (HO) +Package uniquecounter Info: New unique counter `rerunfilecheck' on input line 2 +82. +) +\Hy@SectionHShift=\skip48 +) +(/usr/share/texlive/texmf-dist/tex/latex/base/inputenc.sty +Package: inputenc 2008/03/30 v1.1d Input encoding file +\inpenc@prehook=\toks19 +\inpenc@posthook=\toks20 + +(/usr/share/texlive/texmf-dist/tex/latex/base/utf8.def +File: utf8.def 2008/04/05 v1.1m UTF-8 support for inputenc +Now handling font encoding OML ... +... no UTF-8 mapping file for font encoding OML +Now handling font encoding T1 ... +... processing UTF-8 mapping file for font encoding T1 + +(/usr/share/texlive/texmf-dist/tex/latex/base/t1enc.dfu +File: t1enc.dfu 2008/04/05 v1.1m UTF-8 support for inputenc + defining Unicode char U+00A1 (decimal 161) + defining Unicode char U+00A3 (decimal 163) + defining Unicode char U+00AB (decimal 171) + defining Unicode char U+00BB (decimal 187) + defining Unicode char U+00BF (decimal 191) + defining Unicode char U+00C0 (decimal 192) + defining Unicode char U+00C1 (decimal 193) + defining Unicode char U+00C2 (decimal 194) + defining Unicode char U+00C3 (decimal 195) + defining Unicode char U+00C4 (decimal 196) + defining Unicode char U+00C5 (decimal 197) + defining Unicode char U+00C6 (decimal 198) + defining Unicode char U+00C7 (decimal 199) + defining Unicode char U+00C8 (decimal 200) + defining Unicode char U+00C9 (decimal 201) + defining Unicode char U+00CA (decimal 202) + defining Unicode char U+00CB (decimal 203) + defining Unicode char U+00CC (decimal 204) + defining Unicode char U+00CD (decimal 205) + defining Unicode char U+00CE (decimal 206) + defining Unicode char U+00CF (decimal 207) + defining Unicode char U+00D0 (decimal 208) + defining Unicode char U+00D1 (decimal 209) + defining Unicode char U+00D2 (decimal 210) + defining Unicode char U+00D3 (decimal 211) + defining Unicode char U+00D4 (decimal 212) + defining Unicode char U+00D5 (decimal 213) + defining Unicode char U+00D6 (decimal 214) + defining Unicode char U+00D8 (decimal 216) + defining Unicode char U+00D9 (decimal 217) + defining Unicode char U+00DA (decimal 218) + defining Unicode char U+00DB (decimal 219) + defining Unicode char U+00DC (decimal 220) + defining Unicode char U+00DD (decimal 221) + defining Unicode char U+00DE (decimal 222) + defining Unicode char U+00DF (decimal 223) + defining Unicode char U+00E0 (decimal 224) + defining Unicode char U+00E1 (decimal 225) + defining Unicode char U+00E2 (decimal 226) + defining Unicode char U+00E3 (decimal 227) + defining Unicode char U+00E4 (decimal 228) + defining Unicode char U+00E5 (decimal 229) + defining Unicode char U+00E6 (decimal 230) + defining Unicode char U+00E7 (decimal 231) + defining Unicode char U+00E8 (decimal 232) + defining Unicode char U+00E9 (decimal 233) + defining Unicode char U+00EA (decimal 234) + defining Unicode char U+00EB (decimal 235) + defining Unicode char U+00EC (decimal 236) + defining Unicode char U+00ED (decimal 237) + defining Unicode char U+00EE (decimal 238) + defining Unicode char U+00EF (decimal 239) + defining Unicode char U+00F0 (decimal 240) + defining Unicode char U+00F1 (decimal 241) + defining Unicode char U+00F2 (decimal 242) + defining Unicode char U+00F3 (decimal 243) + defining Unicode char U+00F4 (decimal 244) + defining Unicode char U+00F5 (decimal 245) + defining Unicode char U+00F6 (decimal 246) + defining Unicode char U+00F8 (decimal 248) + defining Unicode char U+00F9 (decimal 249) + defining Unicode char U+00FA (decimal 250) + defining Unicode char U+00FB (decimal 251) + defining Unicode char U+00FC (decimal 252) + defining Unicode char U+00FD (decimal 253) + defining Unicode char U+00FE (decimal 254) + defining Unicode char U+00FF (decimal 255) + defining Unicode char U+0102 (decimal 258) + defining Unicode char U+0103 (decimal 259) + defining Unicode char U+0104 (decimal 260) + defining Unicode char U+0105 (decimal 261) + defining Unicode char U+0106 (decimal 262) + defining Unicode char U+0107 (decimal 263) + defining Unicode char U+010C (decimal 268) + defining Unicode char U+010D (decimal 269) + defining Unicode char U+010E (decimal 270) + defining Unicode char U+010F (decimal 271) + defining Unicode char U+0110 (decimal 272) + defining Unicode char U+0111 (decimal 273) + defining Unicode char U+0118 (decimal 280) + defining Unicode char U+0119 (decimal 281) + defining Unicode char U+011A (decimal 282) + defining Unicode char U+011B (decimal 283) + defining Unicode char U+011E (decimal 286) + defining Unicode char U+011F (decimal 287) + defining Unicode char U+0130 (decimal 304) + defining Unicode char U+0131 (decimal 305) + defining Unicode char U+0132 (decimal 306) + defining Unicode char U+0133 (decimal 307) + defining Unicode char U+0139 (decimal 313) + defining Unicode char U+013A (decimal 314) + defining Unicode char U+013D (decimal 317) + defining Unicode char U+013E (decimal 318) + defining Unicode char U+0141 (decimal 321) + defining Unicode char U+0142 (decimal 322) + defining Unicode char U+0143 (decimal 323) + defining Unicode char U+0144 (decimal 324) + defining Unicode char U+0147 (decimal 327) + defining Unicode char U+0148 (decimal 328) + defining Unicode char U+014A (decimal 330) + defining Unicode char U+014B (decimal 331) + defining Unicode char U+0150 (decimal 336) + defining Unicode char U+0151 (decimal 337) + defining Unicode char U+0152 (decimal 338) + defining Unicode char U+0153 (decimal 339) + defining Unicode char U+0154 (decimal 340) + defining Unicode char U+0155 (decimal 341) + defining Unicode char U+0158 (decimal 344) + defining Unicode char U+0159 (decimal 345) + defining Unicode char U+015A (decimal 346) + defining Unicode char U+015B (decimal 347) + defining Unicode char U+015E (decimal 350) + defining Unicode char U+015F (decimal 351) + defining Unicode char U+0160 (decimal 352) + defining Unicode char U+0161 (decimal 353) + defining Unicode char U+0162 (decimal 354) + defining Unicode char U+0163 (decimal 355) + defining Unicode char U+0164 (decimal 356) + defining Unicode char U+0165 (decimal 357) + defining Unicode char U+016E (decimal 366) + defining Unicode char U+016F (decimal 367) + defining Unicode char U+0170 (decimal 368) + defining Unicode char U+0171 (decimal 369) + defining Unicode char U+0178 (decimal 376) + defining Unicode char U+0179 (decimal 377) + defining Unicode char U+017A (decimal 378) + defining Unicode char U+017B (decimal 379) + defining Unicode char U+017C (decimal 380) + defining Unicode char U+017D (decimal 381) + defining Unicode char U+017E (decimal 382) + defining Unicode char U+200C (decimal 8204) + defining Unicode char U+2013 (decimal 8211) + defining Unicode char U+2014 (decimal 8212) + defining Unicode char U+2018 (decimal 8216) + defining Unicode char U+2019 (decimal 8217) + defining Unicode char U+201A (decimal 8218) + defining Unicode char U+201C (decimal 8220) + defining Unicode char U+201D (decimal 8221) + defining Unicode char U+201E (decimal 8222) + defining Unicode char U+2030 (decimal 8240) + defining Unicode char U+2031 (decimal 8241) + defining Unicode char U+2039 (decimal 8249) + defining Unicode char U+203A (decimal 8250) + defining Unicode char U+2423 (decimal 9251) +) +Now handling font encoding OT1 ... +... processing UTF-8 mapping file for font encoding OT1 + +(/usr/share/texlive/texmf-dist/tex/latex/base/ot1enc.dfu +File: ot1enc.dfu 2008/04/05 v1.1m UTF-8 support for inputenc + defining Unicode char U+00A1 (decimal 161) + defining Unicode char U+00A3 (decimal 163) + defining Unicode char U+00B8 (decimal 184) + defining Unicode char U+00BF (decimal 191) + defining Unicode char U+00C5 (decimal 197) + defining Unicode char U+00C6 (decimal 198) + defining Unicode char U+00D8 (decimal 216) + defining Unicode char U+00DF (decimal 223) + defining Unicode char U+00E6 (decimal 230) + defining Unicode char U+00EC (decimal 236) + defining Unicode char U+00ED (decimal 237) + defining Unicode char U+00EE (decimal 238) + defining Unicode char U+00EF (decimal 239) + defining Unicode char U+00F8 (decimal 248) + defining Unicode char U+0131 (decimal 305) + defining Unicode char U+0141 (decimal 321) + defining Unicode char U+0142 (decimal 322) + defining Unicode char U+0152 (decimal 338) + defining Unicode char U+0153 (decimal 339) + defining Unicode char U+2013 (decimal 8211) + defining Unicode char U+2014 (decimal 8212) + defining Unicode char U+2018 (decimal 8216) + defining Unicode char U+2019 (decimal 8217) + defining Unicode char U+201C (decimal 8220) + defining Unicode char U+201D (decimal 8221) +) +Now handling font encoding OMS ... +... processing UTF-8 mapping file for font encoding OMS + +(/usr/share/texlive/texmf-dist/tex/latex/base/omsenc.dfu +File: omsenc.dfu 2008/04/05 v1.1m UTF-8 support for inputenc + defining Unicode char U+00A7 (decimal 167) + defining Unicode char U+00B6 (decimal 182) + defining Unicode char U+00B7 (decimal 183) + defining Unicode char U+2020 (decimal 8224) + defining Unicode char U+2021 (decimal 8225) + defining Unicode char U+2022 (decimal 8226) +) +Now handling font encoding OMX ... +... no UTF-8 mapping file for font encoding OMX +Now handling font encoding U ... +... no UTF-8 mapping file for font encoding U +Now handling font encoding PD1 ... +... no UTF-8 mapping file for font encoding PD1 + defining Unicode char U+00A9 (decimal 169) + defining Unicode char U+00AA (decimal 170) + defining Unicode char U+00AE (decimal 174) + defining Unicode char U+00BA (decimal 186) + defining Unicode char U+02C6 (decimal 710) + defining Unicode char U+02DC (decimal 732) + defining Unicode char U+200C (decimal 8204) + defining Unicode char U+2026 (decimal 8230) + defining Unicode char U+2122 (decimal 8482) + defining Unicode char U+2423 (decimal 9251) +)) +(/usr/share/texlive/texmf-dist/tex/latex/base/alltt.sty +Package: alltt 1997/06/16 v2.0g defines alltt environment +) +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty +Package: amsmath 2000/07/18 v2.13 AMS math features +\@mathmargin=\skip49 + +For additional information on amsmath, use the `?' option. +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty +Package: amstext 2000/06/29 v2.01 + +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty +File: amsgen.sty 1999/11/30 v2.0 +\@emptytoks=\toks21 +\ex@=\dimen110 +)) +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty +Package: amsbsy 1999/11/29 v1.2d +\pmbraise@=\dimen111 +) +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty +Package: amsopn 1999/12/14 v2.01 operator names +) +\inf@bad=\count100 +LaTeX Info: Redefining \frac on input line 211. +\uproot@=\count101 +\leftroot@=\count102 +LaTeX Info: Redefining \overline on input line 307. +\classnum@=\count103 +\DOTSCASE@=\count104 +LaTeX Info: Redefining \ldots on input line 379. +LaTeX Info: Redefining \dots on input line 382. +LaTeX Info: Redefining \cdots on input line 467. +\Mathstrutbox@=\box26 +\strutbox@=\box27 +\big@size=\dimen112 +LaTeX Font Info: Redeclaring font encoding OML on input line 567. +LaTeX Font Info: Redeclaring font encoding OMS on input line 568. +\macc@depth=\count105 +\c@MaxMatrixCols=\count106 +\dotsspace@=\muskip11 +\c@parentequation=\count107 +\dspbrk@lvl=\count108 +\tag@help=\toks22 +\row@=\count109 +\column@=\count110 +\maxfields@=\count111 +\andhelp@=\toks23 +\eqnshift@=\dimen113 +\alignsep@=\dimen114 +\tagshift@=\dimen115 +\tagwidth@=\dimen116 +\totwidth@=\dimen117 +\lineht@=\dimen118 +\@envbody=\toks24 +\multlinegap=\skip50 +\multlinetaggap=\skip51 +\mathdisplay@stack=\toks25 +LaTeX Info: Redefining \[ on input line 2666. +LaTeX Info: Redefining \] on input line 2667. +) +(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty +Package: amssymb 2009/06/22 v3.00 + +(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty +Package: amsfonts 2009/06/22 v3.00 Basic AMSFonts support +\symAMSa=\mathgroup4 +\symAMSb=\mathgroup5 +LaTeX Font Info: Overwriting math alphabet `\mathfrak' in version `bold' +(Font) U/euf/m/n --> U/euf/b/n on input line 96. +)) +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/txfonts.sty +Package: txfonts 2008/01/22 v3.2.1 +LaTeX Font Info: Redeclaring symbol font `operators' on input line 21. +LaTeX Font Info: Overwriting symbol font `operators' in version `normal' +(Font) OT1/cmr/m/n --> OT1/txr/m/n on input line 21. +LaTeX Font Info: Overwriting symbol font `operators' in version `bold' +(Font) OT1/cmr/bx/n --> OT1/txr/m/n on input line 21. +LaTeX Font Info: Overwriting symbol font `operators' in version `bold' +(Font) OT1/txr/m/n --> OT1/txr/bx/n on input line 22. +\symitalic=\mathgroup6 +LaTeX Font Info: Overwriting symbol font `italic' in version `bold' +(Font) OT1/txr/m/it --> OT1/txr/bx/it on input line 26. +LaTeX Font Info: Redeclaring math alphabet \mathbf on input line 29. +LaTeX Font Info: Overwriting math alphabet `\mathbf' in version `normal' +(Font) OT1/cmr/bx/n --> OT1/txr/bx/n on input line 29. +LaTeX Font Info: Overwriting math alphabet `\mathbf' in version `bold' +(Font) OT1/cmr/bx/n --> OT1/txr/bx/n on input line 29. +LaTeX Font Info: Redeclaring math alphabet \mathit on input line 30. +LaTeX Font Info: Overwriting math alphabet `\mathit' in version `normal' +(Font) OT1/cmr/m/it --> OT1/txr/m/it on input line 30. +LaTeX Font Info: Overwriting math alphabet `\mathit' in version `bold' +(Font) OT1/cmr/bx/it --> OT1/txr/m/it on input line 30. +LaTeX Font Info: Overwriting math alphabet `\mathit' in version `bold' +(Font) OT1/txr/m/it --> OT1/txr/bx/it on input line 31. +LaTeX Font Info: Redeclaring math alphabet \mathsf on input line 40. +LaTeX Font Info: Overwriting math alphabet `\mathsf' in version `normal' +(Font) OT1/cmss/m/n --> OT1/txss/m/n on input line 40. +LaTeX Font Info: Overwriting math alphabet `\mathsf' in version `bold' +(Font) OT1/cmss/bx/n --> OT1/txss/m/n on input line 40. +LaTeX Font Info: Overwriting math alphabet `\mathsf' in version `bold' +(Font) OT1/txss/m/n --> OT1/txss/b/n on input line 41. +LaTeX Font Info: Redeclaring math alphabet \mathtt on input line 50. +LaTeX Font Info: Overwriting math alphabet `\mathtt' in version `normal' +(Font) OT1/cmtt/m/n --> OT1/txtt/m/n on input line 50. +LaTeX Font Info: Overwriting math alphabet `\mathtt' in version `bold' +(Font) OT1/cmtt/m/n --> OT1/txtt/m/n on input line 50. +LaTeX Font Info: Overwriting math alphabet `\mathtt' in version `bold' +(Font) OT1/txtt/m/n --> OT1/txtt/b/n on input line 51. +LaTeX Font Info: Redeclaring symbol font `letters' on input line 58. +LaTeX Font Info: Overwriting symbol font `letters' in version `normal' +(Font) OML/cmm/m/it --> OML/txmi/m/it on input line 58. +LaTeX Font Info: Overwriting symbol font `letters' in version `bold' +(Font) OML/cmm/b/it --> OML/txmi/m/it on input line 58. +LaTeX Font Info: Overwriting symbol font `letters' in version `bold' +(Font) OML/txmi/m/it --> OML/txmi/bx/it on input line 59. +\symlettersA=\mathgroup7 +LaTeX Font Info: Overwriting symbol font `lettersA' in version `bold' +(Font) U/txmia/m/it --> U/txmia/bx/it on input line 67. +LaTeX Font Info: Redeclaring math alphabet \mathfrak on input line 70. +LaTeX Font Info: Redeclaring symbol font `symbols' on input line 77. +LaTeX Font Info: Overwriting symbol font `symbols' in version `normal' +(Font) OMS/cmsy/m/n --> OMS/txsy/m/n on input line 77. +LaTeX Font Info: Overwriting symbol font `symbols' in version `bold' +(Font) OMS/cmsy/b/n --> OMS/txsy/m/n on input line 77. +LaTeX Font Info: Overwriting symbol font `symbols' in version `bold' +(Font) OMS/txsy/m/n --> OMS/txsy/bx/n on input line 78. +LaTeX Font Info: Redeclaring symbol font `AMSa' on input line 93. +LaTeX Font Info: Overwriting symbol font `AMSa' in version `normal' +(Font) U/msa/m/n --> U/txsya/m/n on input line 93. +LaTeX Font Info: Overwriting symbol font `AMSa' in version `bold' +(Font) U/msa/m/n --> U/txsya/m/n on input line 93. +LaTeX Font Info: Overwriting symbol font `AMSa' in version `bold' +(Font) U/txsya/m/n --> U/txsya/bx/n on input line 94. +LaTeX Font Info: Redeclaring symbol font `AMSb' on input line 102. +LaTeX Font Info: Overwriting symbol font `AMSb' in version `normal' +(Font) U/msb/m/n --> U/txsyb/m/n on input line 102. +LaTeX Font Info: Overwriting symbol font `AMSb' in version `bold' +(Font) U/msb/m/n --> U/txsyb/m/n on input line 102. +LaTeX Font Info: Overwriting symbol font `AMSb' in version `bold' +(Font) U/txsyb/m/n --> U/txsyb/bx/n on input line 103. +\symsymbolsC=\mathgroup8 +LaTeX Font Info: Overwriting symbol font `symbolsC' in version `bold' +(Font) U/txsyc/m/n --> U/txsyc/bx/n on input line 113. +LaTeX Font Info: Redeclaring symbol font `largesymbols' on input line 120. +LaTeX Font Info: Overwriting symbol font `largesymbols' in version `normal' +(Font) OMX/cmex/m/n --> OMX/txex/m/n on input line 120. +LaTeX Font Info: Overwriting symbol font `largesymbols' in version `bold' +(Font) OMX/cmex/m/n --> OMX/txex/m/n on input line 120. +LaTeX Font Info: Overwriting symbol font `largesymbols' in version `bold' +(Font) OMX/txex/m/n --> OMX/txex/bx/n on input line 121. +\symlargesymbolsA=\mathgroup9 +LaTeX Font Info: Overwriting symbol font `largesymbolsA' in version `bold' +(Font) U/txexa/m/n --> U/txexa/bx/n on input line 129. +LaTeX Info: Redefining \not on input line 1043. +) +(/usr/share/texlive/texmf-dist/tex/latex/anysize/anysize.sty +Package: anysize 1994/08/13 setting margin sizes + +document style option `anysize' loaded +Michael Salzenberg, Thomas Esser, Dirk Hillbrecht +Version 1.0, Aug 13, 1994 +\@Leftmargin=\dimen119 +\@Rightmargin=\dimen120 +\@Topmargin=\dimen121 +\@Bottommargin=\dimen122 +) (/usr/share/texlive/texmf-dist/tex/latex/fancyhdr/fancyhdr.sty +\fancy@headwidth=\skip52 +\f@ncyO@elh=\skip53 +\f@ncyO@erh=\skip54 +\f@ncyO@olh=\skip55 +\f@ncyO@orh=\skip56 +\f@ncyO@elf=\skip57 +\f@ncyO@erf=\skip58 +\f@ncyO@olf=\skip59 +\f@ncyO@orf=\skip60 +) (./main.aux) +\openout1 = `main.aux'. + +LaTeX Font Info: Checking defaults for OML/txmi/m/it on input line 58. +LaTeX Font Info: Try loading font information for OML+txmi on input line 58. + + +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/omltxmi.fd +File: omltxmi.fd 2000/12/15 v3.1 +) +LaTeX Font Info: ... okay on input line 58. +LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 58. +LaTeX Font Info: ... okay on input line 58. +LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 58. +LaTeX Font Info: ... okay on input line 58. +LaTeX Font Info: Checking defaults for OMS/txsy/m/n on input line 58. +LaTeX Font Info: Try loading font information for OMS+txsy on input line 58. + + +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/omstxsy.fd +File: omstxsy.fd 2000/12/15 v3.1 +) +LaTeX Font Info: ... okay on input line 58. +LaTeX Font Info: Checking defaults for OMX/txex/m/n on input line 58. +LaTeX Font Info: Try loading font information for OMX+txex on input line 58. + + +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/omxtxex.fd +File: omxtxex.fd 2000/12/15 v3.1 +) +LaTeX Font Info: ... okay on input line 58. +LaTeX Font Info: Checking defaults for U/txexa/m/n on input line 58. +LaTeX Font Info: Try loading font information for U+txexa on input line 58. + +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/utxexa.fd +File: utxexa.fd 2000/12/15 v3.1 +) +LaTeX Font Info: ... okay on input line 58. +LaTeX Font Info: Checking defaults for PD1/pdf/m/n on input line 58. +LaTeX Font Info: ... okay on input line 58. +LaTeX Font Info: Try loading font information for OT1+txr on input line 58. + +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/ot1txr.fd +File: ot1txr.fd 2000/12/15 v3.1 +) +(/usr/share/texlive/texmf-dist/tex/context/base/supp-pdf.mkii +[Loading MPS to PDF converter (version 2006.09.02).] +\scratchcounter=\count112 +\scratchdimen=\dimen123 +\scratchbox=\box28 +\nofMPsegments=\count113 +\nofMParguments=\count114 +\everyMPshowfont=\toks26 +\MPscratchCnt=\count115 +\MPscratchDim=\dimen124 +\MPnumerator=\count116 +\makeMPintoPDFobject=\count117 +\everyMPtoPDFconversion=\toks27 +) (/usr/share/texlive/texmf-dist/tex/latex/oberdiek/epstopdf-base.sty +Package: epstopdf-base 2010/02/09 v2.5 Base part for package epstopdf + +(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/grfext.sty +Package: grfext 2010/08/19 v1.1 Manage graphics extensions (HO) +) +Package grfext Info: Graphics extension search list: +(grfext) [.png,.pdf,.jpg,.mps,.jpeg,.jbig2,.jb2,.PNG,.PDF,.JPG,.JPE +G,.JBIG2,.JB2,.eps] +(grfext) \AppendGraphicsExtensions on input line 452. + +(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg +File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv +e +)) +\AtBeginShipoutBox=\box29 +Package hyperref Info: Link coloring OFF on input line 58. + +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/nameref.sty +Package: nameref 2010/04/30 v2.40 Cross-referencing by name of section + +(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/gettitlestring.sty +Package: gettitlestring 2010/12/03 v1.4 Cleanup title references (HO) +) +\c@section@level=\count118 +) +LaTeX Info: Redefining \ref on input line 58. +LaTeX Info: Redefining \pageref on input line 58. +LaTeX Info: Redefining \nameref on input line 58. + +(./main.out) (./main.out) +\@outlinefile=\write3 +\openout3 = `main.out'. + +LaTeX Font Info: Try loading font information for U+txsya on input line 64. + +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/utxsya.fd +File: utxsya.fd 2000/12/15 v3.1 +) +LaTeX Font Info: Try loading font information for U+txsyb on input line 64. + +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/utxsyb.fd +File: utxsyb.fd 2000/12/15 v3.1 +) +LaTeX Font Info: Try loading font information for U+txmia on input line 64. + +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/utxmia.fd +File: utxmia.fd 2000/12/15 v3.1 +) +LaTeX Font Info: Try loading font information for U+txsyc on input line 64. + +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/utxsyc.fd +File: utxsyc.fd 2000/12/15 v3.1 +) +<./images/CC_88x31.png, id=92, 88.33pt x 31.11626pt> +File: ./images/CC_88x31.png Graphic file (type png) + + +Package pdftex.def Info: ./images/CC_88x31.png used on input line 64. +(pdftex.def) Requested size: 105.27359pt x 37.08528pt. + [1 + + +{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map} <./images/CC_88x31.png>] [2 + +] (./main.toc) +\tf@toc=\write4 +\openout4 = `main.toc'. + + + +Package Fancyhdr Warning: \headheight is too small (12.0pt): + Make it at least 14.49998pt. + We now make it that large for the rest of the document. + This may cause the page layout to be inconsistent, however. + +[3] (./abstract.tex [4 + +] +Chapter 1. +[5] [6 + +] +Chapter 2. +) (./laplace2D.tex [7] [8 + +] +Chapter 3. +[9] [10] <./images/Omega.png, id=189, 806.01125pt x 479.7925pt> +File: ./images/Omega.png Graphic file (type png) + + +Package pdftex.def Info: ./images/Omega.png used on input line 179. +(pdftex.def) Requested size: 210.54718pt x 125.32878pt. +) (./laplace3D.tex [11 <./images/Omega.png>] [12 + +] +Chapter 4. +[13] <./images/Omega2.png, id=218, 1132.23pt x 449.68pt> +File: ./images/Omega2.png Graphic file (type png) + + +Package pdftex.def Info: ./images/Omega2.png used on input line 117. +(pdftex.def) Requested size: 315.82881pt x 125.43608pt. + [14 <./images/Omega2.png>] [15] [16] [17] +<./images/Integral.png, id=281, 699.61375pt x 699.61375pt> +File: ./images/Integral.png Graphic file (type png) + + +Package pdftex.def Info: ./images/Integral.png used on input line 561. +(pdftex.def) Requested size: 315.82881pt x 315.82675pt. + +<./images/test_wave.png, id=283, 586.8324pt x 442.2924pt> +File: ./images/test_wave.png Graphic file (type png) + + +Package pdftex.def Info: ./images/test_wave.png used on input line 585. +(pdftex.def) Requested size: 315.82881pt x 238.04472pt. + [18] [19 <./images/Integral.png> <./images/test_wave.png>] <./images/test_dire +ct.png, id=301, 586.8324pt x 442.2924pt> +File: ./images/test_direct.png Graphic file (type png) + + +Package pdftex.def Info: ./images/test_direct.png used on input line 616. +(pdftex.def) Requested size: 315.82881pt x 238.04472pt. + +<./images/test_bem.png, id=304, 586.8324pt x 442.2924pt> +File: ./images/test_bem.png Graphic file (type png) + + +Package pdftex.def Info: ./images/test_bem.png used on input line 638. +(pdftex.def) Requested size: 315.82881pt x 238.04472pt. +) (./main.bbl [20 <./images/test_direct.png>] +[21 <./images/test_bem.png>] [22 + +]) +Package atveryend Info: Empty hook `BeforeClearDocument' on input line 90. + [23] +Package atveryend Info: Empty hook `AfterLastShipout' on input line 90. + (./main.aux) +Package atveryend Info: Executing hook `AtVeryEndDocument' on input line 90. +Package atveryend Info: Executing hook `AtEndAfterFileList' on input line 90. +Package rerunfilecheck Info: File `main.out' has not changed. +(rerunfilecheck) Checksum: 47992CAAC05675F8055DF1DA37B7F7A8;1434. +Package atveryend Info: Empty hook `AtVeryVeryEnd' on input line 90. + ) +Here is how much of TeX's memory you used: + 7457 strings out of 495059 + 103785 string characters out of 3182029 + 206801 words of memory out of 3000000 + 10379 multiletter control sequences out of 15000+200000 + 53484 words of font info for 126 fonts, out of 3000000 for 9000 + 14 hyphenation exceptions out of 8191 + 34i,17n,43p,237b,351s stack positions out of 5000i,500n,10000p,200000b,50000s +{/usr/share/texlive/texmf-dist/fonts/enc/dvips/base/8r.enc} +Output written on main.pdf (23 pages, 322361 bytes). +PDF statistics: + 376 PDF objects out of 1000 (max. 8388607) + 325 compressed objects within 4 object streams + 96 named destinations out of 1000 (max. 500000) + 212 words of extra memory for PDF output out of 10000 (max. 10000000) + diff --git a/src/Mod/Ship/simRun/theory/main.out b/src/Mod/Ship/simRun/theory/main.out new file mode 100644 index 000000000..dd5e06dbb --- /dev/null +++ b/src/Mod/Ship/simRun/theory/main.out @@ -0,0 +1,22 @@ +\BOOKMARK [0][-]{chapter.1}{Introduction}{}% 1 +\BOOKMARK [1][-]{section.1.1}{Objective}{chapter.1}% 2 +\BOOKMARK [0][-]{chapter.2}{Governing equations}{}% 3 +\BOOKMARK [0][-]{chapter.3}{Waves propagations in 2D plane}{}% 4 +\BOOKMARK [1][-]{section.3.1}{General}{chapter.3}% 5 +\BOOKMARK [1][-]{section.3.2}{Incident waves}{chapter.3}% 6 +\BOOKMARK [1][-]{section.3.3}{BEM applied to Laplace 2D problem}{chapter.3}% 7 +\BOOKMARK [1][-]{section.3.4}{Conclusions to Laplace 2D problem}{chapter.3}% 8 +\BOOKMARK [0][-]{chapter.4}{Waves propagations in 3D}{}% 9 +\BOOKMARK [1][-]{section.4.1}{General}{chapter.4}% 10 +\BOOKMARK [1][-]{section.4.2}{Incident waves}{chapter.4}% 11 +\BOOKMARK [1][-]{section.4.3}{BEM applied to Laplace 3D problem}{chapter.4}% 12 +\BOOKMARK [2][-]{subsection.4.3.1}{Computational domain}{section.4.3}% 13 +\BOOKMARK [2][-]{subsection.4.3.2}{Boundary conditions \(BC\)}{section.4.3}% 14 +\BOOKMARK [2][-]{subsection.4.3.3}{Time integration scheme}{section.4.3}% 15 +\BOOKMARK [2][-]{subsection.4.3.4}{Discrete Laplace solution using the BEM}{section.4.3}% 16 +\BOOKMARK [2][-]{subsection.4.3.5}{Integrals computation}{section.4.3}% 17 +\BOOKMARK [1][-]{section.4.4}{BEM test}{chapter.4}% 18 +\BOOKMARK [2][-]{subsection.4.4.1}{General}{section.4.4}% 19 +\BOOKMARK [2][-]{subsection.4.4.2}{Direct method}{section.4.4}% 20 +\BOOKMARK [2][-]{subsection.4.4.3}{BEM}{section.4.4}% 21 +\BOOKMARK [0][-]{chapter*.2}{Bibliography}{}% 22 diff --git a/src/Mod/Ship/simRun/theory/main.pdf b/src/Mod/Ship/simRun/theory/main.pdf new file mode 100644 index 0000000000000000000000000000000000000000..798af56aaa56583e7473fbd5fc67c6ef94ded571 GIT binary patch literal 322361 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 literal 0 HcmV?d00001 diff --git a/src/Mod/Ship/simRun/theory/main.tex b/src/Mod/Ship/simRun/theory/main.tex new file mode 100644 index 000000000..f09787f51 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/main.tex @@ -0,0 +1,90 @@ +\documentclass[a4paper,12pt]{book} +\usepackage[numbers]{natbib} +\bibliographystyle{plainnat} +\usepackage{graphicx} +\usepackage{verbatim} +\usepackage{color, colortbl} +\usepackage{hyperref} +\usepackage[utf8]{inputenc} +\setcounter{tocdepth}{2} +\usepackage{alltt} +\usepackage{amsmath} +\usepackage{amssymb} +\usepackage{amsfonts} +\graphicspath{{./images/}} +\usepackage{txfonts} %%does not work on Windows +% \usepackage{dsfont} +% +\newcommand{\NAME}{FreeCAD-Ship } +\newcommand{\rc}{\\[0.2 in]} +\newcommand{\rcc}{\\[0.3 in]} +\newcommand{\rccc}{\\[0.4 in]} +% \newcommand{\bs}[1]{\boldsymbol{#1}} +\newcommand{\bs}[1]{\pmb{#1}} +\newcommand{\SPHint}{\int_{\bs{y} \in \Omega}} +\newcommand{\SPHboundint}{\int_{\bs{y} \in \partial \Omega}} +\newcommand{\gradient}{\nabla} +\newcommand{\divergence}{\mbox{div}} +\newcommand{\rotational}{\nabla \times} +\newcommand{\laplacian}{\bigtriangleup} +\newcommand{\dsty}{\displaystyle} +\newcommand{\sph}[1]{\langle {#1} \rangle} +% +\author{JL Cercos-Pita $<$jlcercos@gmail.com$>$} +\title{FreeCAD-Ship.\rcc +\textbf{Sea waves transport using Boundary Elements Method}} +\date{\today\\[5.0 in] +\begin{figure}[h!] + \centering + \includegraphics[width=0.2\textwidth]{CC_88x31} +\end{figure} +} +% +\setlength{\parindent}{0em} +% +\usepackage{anysize} +\marginsize{1.5cm}{1cm}{1cm}{1cm} +% +\usepackage{fancyhdr} +\pagestyle{fancyplain} +% Pages header and foot +\lhead{} +\rhead{\NAME} +\lfoot{JL Cercos-Pita} +\cfoot{jlcercos@gmail.com} +\rfoot{\thepage} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\begin{document} + +% ------------------------------- +% Title and summary +% ------------------------------- +\maketitle +\thispagestyle{empty} +% +\newpage +\tableofcontents +\newpage +\newpage +% ------------------------------- +% Introduction +% ------------------------------- +\input{abstract} + +% ------------------------------- +% Laplacian 2D +% ------------------------------- +\input{laplace2D} + +% ------------------------------- +% Laplacian 2D +% ------------------------------- +\input{laplace3D} + +% ------------------------------- +% Bibliography +% ------------------------------- +\bibliography{bib} +\addcontentsline{toc}{chapter}{Bibliography} +\end{document} diff --git a/src/Mod/Ship/simRun/theory/main.toc b/src/Mod/Ship/simRun/theory/main.toc new file mode 100644 index 000000000..c60c1e451 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/main.toc @@ -0,0 +1,22 @@ +\contentsline {chapter}{\numberline {1}Introduction}{5}{chapter.1} +\contentsline {section}{\numberline {1.1}Objective}{5}{section.1.1} +\contentsline {chapter}{\numberline {2}Governing equations}{7}{chapter.2} +\contentsline {chapter}{\numberline {3}Waves propagations in 2D plane}{9}{chapter.3} +\contentsline {section}{\numberline {3.1}General}{9}{section.3.1} +\contentsline {section}{\numberline {3.2}Incident waves}{9}{section.3.2} +\contentsline {section}{\numberline {3.3}BEM applied to Laplace 2D problem}{10}{section.3.3} +\contentsline {section}{\numberline {3.4}Conclusions to Laplace 2D problem}{11}{section.3.4} +\contentsline {chapter}{\numberline {4}Waves propagations in 3D}{13}{chapter.4} +\contentsline {section}{\numberline {4.1}General}{13}{section.4.1} +\contentsline {section}{\numberline {4.2}Incident waves}{13}{section.4.2} +\contentsline {section}{\numberline {4.3}BEM applied to Laplace 3D problem}{13}{section.4.3} +\contentsline {subsection}{\numberline {4.3.1}Computational domain}{13}{subsection.4.3.1} +\contentsline {subsection}{\numberline {4.3.2}Boundary conditions (BC)}{14}{subsection.4.3.2} +\contentsline {subsection}{\numberline {4.3.3}Time integration scheme}{15}{subsection.4.3.3} +\contentsline {subsection}{\numberline {4.3.4}Discrete Laplace solution using the BEM}{16}{subsection.4.3.4} +\contentsline {subsection}{\numberline {4.3.5}Integrals computation}{17}{subsection.4.3.5} +\contentsline {section}{\numberline {4.4}BEM test}{18}{section.4.4} +\contentsline {subsection}{\numberline {4.4.1}General}{18}{subsection.4.4.1} +\contentsline {subsection}{\numberline {4.4.2}Direct method}{19}{subsection.4.4.2} +\contentsline {subsection}{\numberline {4.4.3}BEM}{20}{subsection.4.4.3} +\contentsline {chapter}{Bibliography}{23}{chapter*.2} diff --git a/src/Mod/Ship/simRun/theory/test/green.py b/src/Mod/Ship/simRun/theory/test/green.py new file mode 100644 index 000000000..e8f22a530 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/test/green.py @@ -0,0 +1,127 @@ +#*************************************************************************** +#* * +#* 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 numpy import * + +import waves + +def G_val(x,X): + """ Computed the Green's function value. + @param x Point to evaluate (numpy.array(3)) + @param X Reference point (numpy.array(3)) + @return Green's function value. + """ + return 1.0 / (4.0*pi * linalg.norm(x-X)) + +def H_val(x,X): + """ Computed the Green's function gradient. + @param x Point to evaluate (numpy.array(3)) + @param X Reference point (numpy.array(3)) + @return Green's function gradient. + """ + return (x-X) / (4.0*pi * dot(x-X, x-X)**1.5 ) + +def GH(p,I,J,P,n,L,B,x,y,z,dx,dy,t, a,k,w,d): + """ Computes the Green's function integral + numerically, with an increase resolution of n. + @param p Point to evaluate + @param I Point to evaluate x index + @param J Point to evaluate y index + @param P Reference point + @param n Number of divisors in each direction to + discretize each area element. Should be an even value + @param L Length of the computational domain + @param B width of the computational domain + @param x X coordinates of the area elements + @param y Y coordinates of the area elements + @param z Z coordinates of the area elements + @param dx distance between elements in the x direction + @param dy distance between elements in the y direction + @param t Simulation time (s) + @param a List of waves amplitudes + @param k List of waves k + @param w List of waves omega + @param d List of waves lags. + @return Green's function integral. + """ + # Ensure that n is an even value. If n is even + # we can grant that any point will be placed + # in p, that can be eventually the same than + # P, being G and H functions bad defined. + if n % 2: + n = n + 1 + # Get the new distance between Green's points + DX = dx / n + DY = dy / n + # Get the coordinates of all the grid points + # around the evaluation one + nx = x.shape[0] + ny = y.shape[1] + X = zeros((3,3),dtype=float32) + Y = zeros((3,3),dtype=float32) + Z = zeros((3,3),dtype=float32) + for i in range(0,3): + for j in range(0,3): + X[i,j] = p[0] + (i-1)*dx + Y[i,j] = p[1] + (j-1)*dy + if((X[i,j] > -0.5*L) and (X[i,j] < 0.5*L) and (Y[i,j] > -0.5*B) and (Y[i,j] < 0.5*B)): + Z[i,j] = z[I-1+i,J-1+j] + else: + Z[i,j] = waves.z(X[i,j],Y[i,j],t, a,k,w,d) + # Perform spline surface coeffs + K = zeros((3*3),dtype=float32) + K[0] = Z[0,0] # k_{0} + K[1] = 4*Z[1,0] - Z[2,0] - 3*Z[0,0] # k_{u} + K[2] = 4*Z[0,1] - Z[0,2] - 3*Z[0,0] # k_{v} + K[3] = Z[2,2] - 4*Z[2,1] + 3*Z[2,0] + \ + 3*Z[0,2] - 12*Z[0,1] + 9*Z[0,0] + \ + -4*Z[1,2] + 16*Z[1,1] - 12*Z[1,0] # k_{uv} + K[4] = 2*Z[2,0] + 2*Z[0,0] - 4*Z[1,0] # k_{uu} + K[5] = 2*Z[0,2] + 2*Z[0,0] - 4*Z[0,1] # k_{vv} + K[6] = -2*Z[2,2] + 8*Z[2,1] - 6*Z[2,0] + \ + -2*Z[0,2] + 8*Z[0,1] - 6*Z[0,0] + \ + 4*Z[1,2] - 16*Z[1,1] + 12*Z[1,0] # k_{uuv} + K[7] = -2*Z[2,2] + 4*Z[2,1] - 2*Z[2,0] + \ + -6*Z[0,2] + 12*Z[0,1] - 6*Z[0,0] + \ + 8*Z[1,2] - 16*Z[1,1] + 8*Z[1,0] # k_{uuv} + K[8] = 4*Z[2,2] - 8*Z[2,1] + 4*Z[2,0] + \ + 4*Z[0,2] - 8*Z[0,1] + 4*Z[0,0] + \ + -8*Z[1,2] + 16*Z[1,1] - 8*Z[1,0] # k_{uuvv} + # Loop around the point p collecting the integral + G_tot = 0.0 + H_tot = zeros((3),dtype=float32) + for i in range(0,n): + for j in range(0,n): + xx = x[I,J] - 0.5*dx + (i+0.5)*DX + yy = y[I,J] - 0.5*dy + (j+0.5)*DY + # Interpolate z + u = (xx - X[0,0]) / (X[2,0] - X[0,0]) + v = (yy - Y[0,0]) / (Y[0,2] - Y[0,0]) + zz = K[0] + K[1]*u + K[2]*v + K[3]*u*v + \ + K[4]*u*u + K[5]*v*v + K[6]*u*u*v + \ + K[7]*u*v*v + K[8]*u*u*v*v + p = array([xx,yy,zz]) + G_tot = G_tot + G_val(p,P)*DX*DY + H_tot = H_tot + H_val(p,P)*DX*DY + return (G_tot,H_tot) + diff --git a/src/Mod/Ship/simRun/theory/test/main.py b/src/Mod/Ship/simRun/theory/test/main.py new file mode 100644 index 000000000..2b50f978a --- /dev/null +++ b/src/Mod/Ship/simRun/theory/test/main.py @@ -0,0 +1,285 @@ +#*************************************************************************** +#* * +#* 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 sys +from numpy import* +import scipy.linalg as la +from pylab import * + +from green import * +import waves + +# --------------------------------------------------- +# Input data +# --------------------------------------------------- + +# Computational free surface (the part where we will +# compute the fluid dynamics) definition +L = 20.0 +B = 10.0 +nx = 31 +ny = 15 + +# Waves to use, defined by the wave amplitude period, +# and lag. X direction waves will be assumed. +# l = g*T^2 / (2*pi) +a = [0.1] +t = [2.5] +d = [0.0] + +# Green's function maximum value (Error). Used to compute +# The maximum distance to extend the free surface. +G_error = 1e-1 + +# Green's functions integrals resolution (even values) +nG = 8 + +# --------------------------------------------------- +# Simulation setup +# --------------------------------------------------- + +# Discretization +drx = L / nx +dry = B / ny +dS = drx*dry + +# First we may compute how many domains must be +# included in each directions to reach the Green's +# function requested error. +x = (L-drx)/2.0 +Nx = 0 +Gx = G_error*10.0 +while(Gx > G_error): + x = x + L + Nx = Nx + 1 + p = zeros((3), dtype=float32) + P = zeros((3), dtype=float32) + p[0] = x + Gx = G_val(p,P) +print('{0} times the free surface must be duplicated in the x direction\n\tG={1}'.format(Nx,Gx)) + +y = (B-dry)/2.0 +Ny = 0 +Gy = G_error*10.0 +while(Gy > G_error): + y = y + B + Ny = Ny + 1 + p = zeros((3), dtype=float32) + P = zeros((3), dtype=float32) + p[1] = y + Gy = G_val(p,P) +print('{0} times the free surface must be duplicated in the y direction\n\tG={1}'.format(Ny,Gy)) + +# Now we can compute some additional data of the waves +k = [] +w = [] +c = [] +for i in range(0,len(a)): + w.append(2*pi/t[i]) + k.append(w[i]**2 / 9.81) + c.append(w[i]/k[i]) + +# We can intializate the free surface +x = zeros((nx,ny),dtype=float32) +y = zeros((nx,ny),dtype=float32) +z = zeros((nx,ny),dtype=float32) +gradz = zeros((nx,ny),dtype=float32) +p = zeros((nx,ny),dtype=float32) +gradp = zeros((nx,ny),dtype=float32) +for i in range(0,nx): + for j in range(0,ny): + x[i,j] = -0.5*L + (i+0.5)*drx + y[i,j] = -0.5*B + (j+0.5)*dry + z[i,j] = waves.z(x[i,j],y[i,j],0.0, a,k,w,d) + p[i,j] = waves.phi(x[i,j],y[i,j],z[i,j],0.0, a,k,w,d) + gradp[i,j] = waves.gradphi(x[i,j],y[i,j],z[i,j],0.0, a,k,w,d)[2] + +# We can plot starting data +plot_j = int(ny/2) +fig = figure() +plot(x[:,plot_j], z[:,plot_j], color="blue", linewidth=2.5, linestyle="-", label="z") +plot(x[:,plot_j], gradp[:,plot_j], color="red", linewidth=2.5, linestyle="-", label="vz") +plot(x[:,plot_j], p[:,plot_j], color="green", linewidth=2.5, linestyle="-", label="phi") +legend(loc='best') +grid() +show() +close(fig) + +# Compute the error in an arbitrary point +phi = zeros((nx,ny),dtype=float32) +i = int(nx/2) +j = int(ny/2) +xx = x[i,j] +yy = y[i,j] +zz = z[i,j] +pp = array([xx,yy,zz]) +print('Testing direct method in the point ({0}, {1}, {2})'.format(pp[0],pp[1],pp[2])) +for I in range(0,nx): + for J in range(0,ny): + # Get phi from this point + XX = x[I,J] + YY = y[I,J] + ZZ = z[I,J] + PP = array([XX,YY,ZZ]) + if((I,J) == (i,j)): + # if (I in range(i-1,i+2)) or (J in range(j-1,j+2)): + G,H = GH(PP,I,J,pp,nG,L,B,x,y,z,drx,dry,0.0, a,k,w,d) + else: + G = G_val(PP,pp)*dS + H = H_val(PP,pp)*dS + phi[i,j] = phi[i,j] - (p[I,J]*H[2] - gradp[I,J]*G) + # Get phi from the extended free surface + for II in range(-Nx,Nx+1): + for JJ in range(-Ny,Ny+1): + if (not II) and (not JJ): + # This is the computational domain + continue + XX = x[I,J] + II*L + YY = y[I,J] + JJ*B + ZZ = waves.z(XX,YY,0.0, a,k,w,d) + PP = array([XX,YY,ZZ]) + Phi = waves.phi(XX,YY,ZZ,0.0, a,k,w,d) + gPhi = waves.gradphi(XX,YY,ZZ,0.0, a,k,w,d)[2] + phi[i,j] = phi[i,j] - (Phi*H_val(PP,pp)[2] - gPhi*G_val(PP,pp))*dS +# Correct phi +phi[i,j] = 2.0*phi[i,j] +print('Computed = {0}, analitic = {1}\n'.format(phi[i,j],p[i,j])) + +# Compute the error along all the free surface +phi = zeros((nx,ny),dtype=float32) +error = 0.0 +done = 0 +print('Testing direct method in all the free surface') +for i in range(0,nx): + for j in range(0,ny): + if done != (100*(j + i*ny))/(nx*ny): + done = (100*(j + i*ny))/(nx*ny) + sys.stdout.write("{0}%...".format(done)) + sys.stdout.flush() + xx = x[i,j] + yy = y[i,j] + zz = z[i,j] + pp = array([xx,yy,zz]) + for I in range(0,nx): + for J in range(0,ny): + # Get phi from this point + XX = x[I,J] + YY = y[I,J] + ZZ = z[I,J] + PP = array([XX,YY,ZZ]) + if((I,J) == (i,j)): + # if (I in range(i-1,i+2)) or (J in range(j-1,j+2)): + G,H = GH(PP,I,J,pp,nG,L,B,x,y,z,drx,dry,0.0, a,k,w,d) + else: + G = G_val(PP,pp)*dS + H = H_val(PP,pp)*dS + phi[i,j] = phi[i,j] - (p[I,J]*H[2] - gradp[I,J]*G) + # Get phi from the extended free surface + for II in range(-Nx,Nx+1): + for JJ in range(-Ny,Ny+1): + if (not II) and (not JJ): + # This is the computational domain + continue + XX = x[I,J] + II*L + YY = y[I,J] + JJ*B + ZZ = waves.z(XX,YY,0.0, a,k,w,d) + PP = array([XX,YY,ZZ]) + Phi = waves.phi(XX,YY,ZZ,0.0, a,k,w,d) + gPhi = waves.gradphi(XX,YY,ZZ,0.0, a,k,w,d)[2] + phi[i,j] = phi[i,j] - (Phi*H_val(PP,pp)[2] - gPhi*G_val(PP,pp))*dS + # Correct phi + phi[i,j] = 2.0*phi[i,j] + error = error + (phi[i,j] - p[i,j])**2 +error = sqrt(error / (nx*ny)) +print('\nRoot mean square error = {0}\n'.format(error)) +fig = figure() +plot(x[:,plot_j], p[:,plot_j], color="blue", linewidth=2.5, linestyle="-", label="analitic") +plot(x[:,plot_j], phi[:,plot_j], color="red", linewidth=2.5, linestyle="-", label="interpolated") +legend(loc='best') +grid() +show() +close(fig) + +# Compute the BEM +GG = zeros((nx*ny, nx*ny), dtype=float32) +HH = -0.5 * array(identity(nx*ny),dtype=float32) +BB = zeros((nx*ny), dtype=float32) +error = 0.0 +done = 0 +print('Testing BEM in all the free surface') +for i in range(0,nx): + for j in range(0,ny): + if done != (100*(j + i*ny))/(nx*ny): + done = (100*(j + i*ny))/(nx*ny) + sys.stdout.write("{0}%...".format(done)) + sys.stdout.flush() + xx = x[i,j] + yy = y[i,j] + zz = z[i,j] + pp = array([xx,yy,zz]) + for I in range(0,nx): + for J in range(0,ny): + # Get phi from this point + XX = x[I,J] + YY = y[I,J] + ZZ = z[I,J] + PP = array([XX,YY,ZZ]) + if((I,J) == (i,j)): + # if (I in range(i-1,i+2)) or (J in range(j-1,j+2)): + G,H = GH(PP,I,J,pp,nG,L,B,x,y,z,drx,dry,0.0, a,k,w,d) + else: + G = G_val(PP,pp)*dS + H = H_val(PP,pp)*dS + GG[j + i*ny,J + I*ny] = GG[j + i*ny,J + I*ny] - G + HH[j + i*ny,J + I*ny] = HH[j + i*ny,J + I*ny] - H[2] + # Get phi from the extended free surface + for II in range(-Nx,Nx+1): + for JJ in range(-Ny,Ny+1): + if (not II) and (not JJ): + # This is the computational domain + continue + XX = x[I,J] + II*L + YY = y[I,J] + JJ*B + ZZ = waves.z(XX,YY,0.0, a,k,w,d) + PP = array([XX,YY,ZZ]) + Phi = waves.phi(XX,YY,ZZ,0.0, a,k,w,d) + gPhi = waves.gradphi(XX,YY,ZZ,0.0, a,k,w,d)[2] + BB[j + i*ny] = BB[j + i*ny] - (Phi*H_val(PP,pp)[2] - gPhi*G_val(PP,pp))*dS +[gPhi, residues, rank, s] = la.lstsq(GG, dot(HH,p.reshape(nx*ny)) + BB) +gPhi = gPhi.reshape(nx,ny) +if(rank < nx*ny): + print("Singular matrix G!.\n") + print("\tEffective rank of linear system matrix is %i (N = %i)\n" % (rank, nx*ny)) +for i in range(0,nx): + for j in range(0,ny): + error = error + (gPhi[i,j] - gradp[i,j])**2 +error = sqrt(error / (nx*ny)) +print('\nRoot mean square error = {0}\n'.format(error)) +fig = figure() +plot(x[:,plot_j], gradp[:,plot_j], color="blue", linewidth=2.5, linestyle="-", label="analitic") +plot(x[:,plot_j], gPhi[:,plot_j], color="red", linewidth=2.5, linestyle="-", label="interpolated") +legend(loc='best') +grid() +show() +close(fig) + diff --git a/src/Mod/Ship/simRun/theory/test/waves.py b/src/Mod/Ship/simRun/theory/test/waves.py new file mode 100644 index 000000000..1964be933 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/test/waves.py @@ -0,0 +1,94 @@ +#*************************************************************************** +#* * +#* 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 numpy import * +from green import * + +def z(x,y,t, a,k,w,d): + """ Returns free surface shape + @param x X coordinate + @param y Y coordinate + @param t Time instant + @param a List of waves amplitudes + @param k List of waves k + @param w List of waves omega + @param d List of waves lags. + @return free surface elevation + """ + Z = 0.0 + for i in range(0,len(a)): + Z = Z + a[i]*sin(k[i]*x - w[i]*t + d[i]) + return Z + +def gradz(x,y,t, a,k,w,d): + """ Returns free surface shape gradient + @param x X coordinate + @param y Y coordinate + @param t Time instant + @param a List of waves amplitudes + @param k List of waves k + @param w List of waves omega + @param d List of waves lags. + @return free surface elevation + """ + gradZ = zeros((3), dtype=float32) + gradZ[2] = 1.0 + for i in range(0,len(a)): + gradZ[0] = gradZ[0] + a[i]*k[i]*cos(k[i]*x - w[i]*t + d[i]) + return gradZ + +def phi(x,y,z,t, a,k,w,d): + """ Returns velocity potential + @param x X coordinate + @param y Y coordinate + @param z Free surface elevation + @param t Time instant + @param a List of waves amplitudes + @param k List of waves k + @param w List of waves omega + @param d List of waves lags. + @return Velocity potential + """ + p = 0.0 + for i in range(0,len(a)): + p = p - a[i]*w[i]/k[i]*cos(k[i]*x - w[i]*t + d[i])*exp(k[i]*z) + return p + +def gradphi(x,y,z,t, a,k,w,d): + """ Returns velocity potential gradient + @param x X coordinate + @param y Y coordinate + @param z Free surface elevation + @param t Time instant + @param a List of waves amplitudes + @param k List of waves k + @param w List of waves omega + @param d List of waves lags. + @return velocity potential gradient + """ + gradp = zeros((3), dtype=float32) + for i in range(0,len(a)): + gradp[0] = gradp[0] + a[i]*w[i]*sin(k[i]*x - w[i]*t + d[i])*exp(k[i]*z) + gradp[2] = gradp[2] - a[i]*w[i]*cos(k[i]*x - w[i]*t + d[i])*exp(k[i]*z) + return gradp + From d65a4f004167233954a4f4ca4412de39ec1b5bae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Luis=20Cerc=C3=B3s=20Pita?= Date: Mon, 20 May 2013 09:29:18 -0400 Subject: [PATCH 042/160] Managed situations when no tank volume can be found --- src/Mod/Ship/TankInstance.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Mod/Ship/TankInstance.py b/src/Mod/Ship/TankInstance.py index 8bb084bf9..d85db4856 100644 --- a/src/Mod/Ship/TankInstance.py +++ b/src/Mod/Ship/TankInstance.py @@ -735,9 +735,12 @@ def tankWeight(obj, angles=Vector(0.0,0.0,0.0), cor=Vector(0.0,0.0,0.0)): z = z0 + dz dx = bbox.XMax-bbox.XMin dy = bbox.YMax-bbox.YMin - box = Part.makeBox(3.0*(dx), 3.0*(dy), (z1-z0)+dz, Vector(bbox.XMin-dx, bbox.YMin-dy, bbox.ZMin-(z1-z0))) - fluid = s.common(box) - vol = fluid.Volume + try: + box = Part.makeBox(3.0*(dx), 3.0*(dy), (z1-z0)+dz, Vector(bbox.XMin-dx, bbox.YMin-dy, bbox.ZMin-(z1-z0))) + fluid = s.common(box) + vol = fluid.Volume + except: + vol = 0.0 W[0] = W[0] + vol*obj.Density # Compute fluid solid in rotated position (non linear rotation # are ussually computed as Roll -> Pitch -> Yaw). @@ -755,9 +758,12 @@ def tankWeight(obj, angles=Vector(0.0,0.0,0.0), cor=Vector(0.0,0.0,0.0)): while(abs(vol - v) > Error): z = z + (vol - v) / (dx*dy) dz = z - z0 - box = Part.makeBox(3.0*(dx), 3.0*(dy), (z1-z0)+dz, Vector(bbox.XMin-dx, bbox.YMin-dy, bbox.ZMin-(z1-z0))) - fluid = s.common(box) - v = fluid.Volume + try: + box = Part.makeBox(3.0*(dx), 3.0*(dy), (z1-z0)+dz, Vector(bbox.XMin-dx, bbox.YMin-dy, bbox.ZMin-(z1-z0))) + fluid = s.common(box) + v = fluid.Volume + except: + v = 0.0 if(abs(vol - v) / (dx*dy) <= 0.000001): break # Add fluid moments From 23554515d87776a0e58600532663ea9abba8074d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Luis=20Cerc=C3=B3s=20Pita?= Date: Mon, 20 May 2013 12:09:21 -0400 Subject: [PATCH 043/160] Fixed main frame area coefficient --- src/Mod/Ship/shipHydrostatics/Tools.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Mod/Ship/shipHydrostatics/Tools.py b/src/Mod/Ship/shipHydrostatics/Tools.py index 8e4faab28..0929eeef3 100644 --- a/src/Mod/Ship/shipHydrostatics/Tools.py +++ b/src/Mod/Ship/shipHydrostatics/Tools.py @@ -322,13 +322,13 @@ def mainFrameCoeff(ship, draft): @param draft Draft. @return Main frame coefficient """ - cm = 0.0 - maxY = 0.0 - minY = 0.0 + cm = 0.0 + maxY = 0.0 + minY = 0.0 # We will take a duplicate of ship shape in order to place it shape = ship.Shape.copy() shape.translate(Vector(0.0,0.0,-draft)) - x = 0.0 + x = 0.0 area = 0.0 # Now we need to know the x range of values bbox = shape.BoundBox @@ -339,6 +339,8 @@ def mainFrameCoeff(ship, draft): B = bbox.YMax - bbox.YMin p = Vector(-1.5*L, -1.5*B, bbox.ZMin - 1.0) box = Part.makeBox(1.5*L + x, 3.0*B, - bbox.ZMin + 1.0, p) + maxY = bbox.YMin + minY = bbox.YMax # Compute common part with ship for s in shape.Solids: # Get solids intersection @@ -367,7 +369,7 @@ def mainFrameCoeff(ship, draft): # Valid face, compute area area = area + f.Area maxY = max(maxY, faceBounds.YMax) - minY = max(minY, faceBounds.YMin) + minY = min(minY, faceBounds.YMin) # Destroy last object generated App.ActiveDocument.removeObject(App.ActiveDocument.Objects[-1].Name) dy = maxY - minY From 2e82745242856577fbe4c2912b23bb4f0c483b0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Luis=20Cerc=C3=B3s=20Pita?= Date: Mon, 20 May 2013 12:16:18 -0400 Subject: [PATCH 044/160] Prevented some errors in the floating coefficient computation --- src/Mod/Ship/shipHydrostatics/Tools.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Mod/Ship/shipHydrostatics/Tools.py b/src/Mod/Ship/shipHydrostatics/Tools.py index 0929eeef3..09123204f 100644 --- a/src/Mod/Ship/shipHydrostatics/Tools.py +++ b/src/Mod/Ship/shipHydrostatics/Tools.py @@ -253,6 +253,10 @@ def FloatingArea(ship, draft, trim): p = Vector(-1.5*L, -1.5*B, bbox.ZMin - 1.0) box = Part.makeBox(3.0*L, 3.0*B, - bbox.ZMin + 1.0, p) # Compute common part with ship + maxX = bbox.XMin + minX = bbox.XMax + maxY = bbox.YMin + minY = bbox.YMax for s in shape.Solids: # Get solids intersection try: From 6fd74b77b78b7fc5ac31703c9cac88b9dae661f9 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 21 May 2013 11:56:36 +0200 Subject: [PATCH 045/160] Set default names for widgets in Qt designer plugin --- src/Tools/plugins/widget/plugin.cpp | 121 +++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 2 deletions(-) diff --git a/src/Tools/plugins/widget/plugin.cpp b/src/Tools/plugins/widget/plugin.cpp index 3769f37d4..e8f5a90f4 100644 --- a/src/Tools/plugins/widget/plugin.cpp +++ b/src/Tools/plugins/widget/plugin.cpp @@ -101,7 +101,13 @@ public: return false; } // QString codeTemplate() const; -// QString domXml() const; + QString domXml() const + { + return "\n" + " \n" + " \n" + ""; + } QString name() const { return QLatin1String("Gui::UrlLabel"); @@ -143,6 +149,13 @@ public: { return false; } + QString domXml() const + { + return "\n" + " \n" + " \n" + ""; + } QString name() const { return QLatin1String("Gui::LocationWidget"); @@ -219,7 +232,13 @@ public: return false; } // QString codeTemplate() const; -// QString domXml() const; + QString domXml() const + { + return "\n" + " \n" + " \n" + ""; + } QString name() const { return QLatin1String("Gui::FileChooser"); @@ -261,6 +280,13 @@ public: { return false; } + QString domXml() const + { + return "\n" + " \n" + " \n" + ""; + } QString name() const { return QLatin1String("Gui::PrefFileChooser"); @@ -334,6 +360,13 @@ public: { return false; } + QString domXml() const + { + return "\n" + " \n" + " \n" + ""; + } QString name() const { return QLatin1String("Gui::AccelLineEdit"); @@ -407,6 +440,13 @@ public: { return false; } + QString domXml() const + { + return "\n" + " \n" + " \n" + ""; + } QString name() const { return QLatin1String("Gui::ActionSelector"); @@ -484,6 +524,13 @@ public: { return false; } + QString domXml() const + { + return "\n" + " \n" + " \n" + ""; + } QString name() const { return QLatin1String("Gui::CommandIconView"); @@ -557,6 +604,13 @@ public: { return false; } + QString domXml() const + { + return "\n" + " \n" + " \n" + ""; + } QString name() const { return QLatin1String("Gui::UIntSpinBox"); @@ -598,6 +652,13 @@ public: { return false; } + QString domXml() const + { + return "\n" + " \n" + " \n" + ""; + } QString name() const { return QLatin1String("Gui::PrefSpinBox"); @@ -671,6 +732,13 @@ public: { return false; } + QString domXml() const + { + return "\n" + " \n" + " \n" + ""; + } QString name() const { return QLatin1String("Gui::ColorButton"); @@ -712,6 +780,13 @@ public: { return false; } + QString domXml() const + { + return "\n" + " \n" + " \n" + ""; + } QString name() const { return QLatin1String("Gui::PrefColorButton"); @@ -784,6 +859,13 @@ public: { return false; } + QString domXml() const + { + return "\n" + " \n" + " \n" + ""; + } QString name() const { return QLatin1String("Gui::PrefSlider"); @@ -855,6 +937,13 @@ public: { return false; } + QString domXml() const + { + return "\n" + " \n" + " \n" + ""; + } QString name() const { return QLatin1String("Gui::PrefRadioButton"); @@ -926,6 +1015,13 @@ public: { return false; } + QString domXml() const + { + return "\n" + " \n" + " \n" + ""; + } QString name() const { return QLatin1String("Gui::PrefCheckBox"); @@ -1001,6 +1097,13 @@ public: { return false; } + QString domXml() const + { + return "\n" + " \n" + " \n" + ""; + } QString name() const { return QLatin1String("Gui::PrefComboBox"); @@ -1042,6 +1145,13 @@ public: { return false; } + QString domXml() const + { + return "\n" + " \n" + " \n" + ""; + } QString name() const { return QLatin1String("Gui::PrefLineEdit"); @@ -1083,6 +1193,13 @@ public: { return false; } + QString domXml() const + { + return "\n" + " \n" + " \n" + ""; + } QString name() const { return QLatin1String("Gui::PrefDoubleSpinBox"); From b45c1dbb8462b7dc1f3bb0130cb642987d2b9ce1 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 21 May 2013 13:42:08 +0200 Subject: [PATCH 046/160] Allow to delete sub-elements in either case --- src/Gui/CommandDoc.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/Gui/CommandDoc.cpp b/src/Gui/CommandDoc.cpp index 3588e77d0..db858e01c 100644 --- a/src/Gui/CommandDoc.cpp +++ b/src/Gui/CommandDoc.cpp @@ -1030,19 +1030,23 @@ void StdCmdDelete::activated(int iMsg) // check if we can delete the object for (std::vector::iterator ft = sel.begin(); ft != sel.end(); ++ft) { App::DocumentObject* obj = ft->getObject(); - std::vector links = obj->getInList(); - if (!links.empty()) { - // check if the referenced objects are groups or are selected too - for (std::vector::iterator lt = links.begin(); lt != links.end(); ++lt) { - if (!(*lt)->getTypeId().isDerivedFrom(App::DocumentObjectGroup::getClassTypeId()) && !rSel.isSelected(*lt)) { - doDeletion = false; + Gui::ViewProvider* vp = pGuiDoc->getViewProvider(ft->getObject()); + // if the object is in edit mode we allow to continue because only sub-elements will be removed + if (!vp || !vp->isEditing()) { + std::vector links = obj->getInList(); + if (!links.empty()) { + // check if the referenced objects are groups or are selected too + for (std::vector::iterator lt = links.begin(); lt != links.end(); ++lt) { + if (!(*lt)->getTypeId().isDerivedFrom(App::DocumentObjectGroup::getClassTypeId()) && !rSel.isSelected(*lt)) { + doDeletion = false; + break; + } + } + + if (!doDeletion) { break; } } - - if (!doDeletion) { - break; - } } } From 09ab819fc324e4070eb8d186536d18e514679bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Luis=20Cerc=C3=B3s=20Pita?= Date: Tue, 21 May 2013 08:21:15 -0400 Subject: [PATCH 047/160] Updated the windows installer --- src/WindowsInstaller/FreeCAD.wxs | 1 + src/WindowsInstaller/ModShip.wxi | 31 ++++++++++++++++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/WindowsInstaller/FreeCAD.wxs b/src/WindowsInstaller/FreeCAD.wxs index bd2d427f5..fd8e9e758 100644 --- a/src/WindowsInstaller/FreeCAD.wxs +++ b/src/WindowsInstaller/FreeCAD.wxs @@ -165,6 +165,7 @@ + diff --git a/src/WindowsInstaller/ModShip.wxi b/src/WindowsInstaller/ModShip.wxi index 03386f5e3..9e30d9210 100644 --- a/src/WindowsInstaller/ModShip.wxi +++ b/src/WindowsInstaller/ModShip.wxi @@ -24,12 +24,12 @@ - - - + + + @@ -45,6 +45,14 @@ + + + + + + + + @@ -118,17 +126,26 @@ - - - + + + + + + + + + + + + - + From 293b9263ada629748fb1694f5f165535c60509b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Luis=20Cerc=C3=B3s=20Pita?= Date: Tue, 21 May 2013 08:24:58 -0400 Subject: [PATCH 048/160] Disabled simulations stuff for the master branch --- src/Mod/Ship/InitGui.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Mod/Ship/InitGui.py b/src/Mod/Ship/InitGui.py index 17aa80443..8fdf24c6c 100644 --- a/src/Mod/Ship/InitGui.py +++ b/src/Mod/Ship/InitGui.py @@ -51,6 +51,7 @@ class ShipWorkbench ( Workbench ): # Simulation stuff only if pyOpenCL & numpy are present hasOpenCL = True hasNumpy = True + hasSim = False # In development, activate it only for development purposes try: import pyopencl except ImportError: @@ -65,7 +66,7 @@ class ShipWorkbench ( Workbench ): msg = QtGui.QApplication.translate("ship_console", "numpy not installed, simulations stuff will disabled therefore", None,QtGui.QApplication.UnicodeUTF8) FreeCAD.Console.PrintMessage(msg + '\n') - if hasOpenCL and hasNumpy: + if hasOpenCL and hasNumpy and hasSim: simlist = ["Ship_CreateSim", "Ship_RunSim", "Ship_StopSim", "Ship_TrackSim"] self.appendToolbar(str(QtCore.QT_TRANSLATE_NOOP("Ship", "Simulation")),simlist) self.appendMenu(str(QtCore.QT_TRANSLATE_NOOP("Ship", "Simulation")),simlist) From f9e1c4328587f791ddedc5e487f71f94f757a9dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Luis=20Cerc=C3=B3s=20Pita?= Date: Mon, 20 May 2013 09:08:43 -0400 Subject: [PATCH 049/160] Regenerated branch --- src/Mod/Ship/CMakeLists.txt | 28 +- src/Mod/Ship/Makefile.am | 16 +- src/Mod/Ship/SimInstance.py | 139 ++- src/Mod/Ship/resources/opencl/jacobi.cl | 79 ++ src/Mod/Ship/resources/opencl/lsqr.cl | 186 ++++ src/Mod/Ship/resources/opencl/matrixGen.cl | 326 +++++++ src/Mod/Ship/resources/opencl/minres.cl | 94 ++ src/Mod/Ship/simCreate/TaskPanel.py | 66 +- src/Mod/Ship/simCreate/TaskPanel.ui | 147 ++- src/Mod/Ship/simRun/Sim/BEMsolver.py | 55 ++ src/Mod/Ship/simRun/Sim/__init__.py | 4 +- src/Mod/Ship/simRun/Sim/evolution.py | 304 ++++++ src/Mod/Ship/simRun/Sim/initialization.py | 418 ++++++-- src/Mod/Ship/simRun/Sim/matrixGen.py | 274 ++++-- src/Mod/Ship/simRun/Simulation.py | 137 ++- src/Mod/Ship/simRun/TaskPanel.py | 16 +- src/Mod/Ship/simRun/clSim/BEMsolver.py | 61 ++ src/Mod/Ship/simRun/clSim/__init__.py | 5 +- src/Mod/Ship/simRun/clSim/bem_jacobi_cl.py | 155 +++ src/Mod/Ship/simRun/clSim/bem_lsqr_cl.py | 229 +++++ src/Mod/Ship/simRun/clSim/bem_minres_cl.py | 157 +++ src/Mod/Ship/simRun/clSim/clUtils.py | 58 ++ src/Mod/Ship/simRun/clSim/evolution.py | 258 +++++ src/Mod/Ship/simRun/clSim/initialization.py | 322 +++++-- src/Mod/Ship/simRun/clSim/matrixGen.py | 184 ++++ src/Mod/Ship/simRun/theory/abstract.tex | 56 ++ src/Mod/Ship/simRun/theory/bib.bib | 91 ++ src/Mod/Ship/simRun/theory/deep_water.wxmx | Bin 0 -> 73355 bytes .../Ship/simRun/theory/images/CC_88x31.png | Bin 0 -> 5281 bytes .../Ship/simRun/theory/images/Integral.png | Bin 0 -> 32720 bytes .../Ship/simRun/theory/images/Integral.svg | 911 ++++++++++++++++++ src/Mod/Ship/simRun/theory/images/Omega.png | Bin 0 -> 28285 bytes src/Mod/Ship/simRun/theory/images/Omega.svg | 206 ++++ src/Mod/Ship/simRun/theory/images/Omega2.png | Bin 0 -> 43277 bytes src/Mod/Ship/simRun/theory/images/Omega2.svg | 222 +++++ .../Ship/simRun/theory/images/test_bem.png | Bin 0 -> 49139 bytes .../Ship/simRun/theory/images/test_direct.png | Bin 0 -> 48587 bytes .../Ship/simRun/theory/images/test_wave.png | Bin 0 -> 66196 bytes src/Mod/Ship/simRun/theory/laplace2D.tex | 196 ++++ src/Mod/Ship/simRun/theory/laplace3D.tex | 642 ++++++++++++ src/Mod/Ship/simRun/theory/main.aux | 125 +++ src/Mod/Ship/simRun/theory/main.bbl | 24 + src/Mod/Ship/simRun/theory/main.blg | 48 + src/Mod/Ship/simRun/theory/main.log | 827 ++++++++++++++++ src/Mod/Ship/simRun/theory/main.out | 22 + src/Mod/Ship/simRun/theory/main.pdf | Bin 0 -> 322361 bytes src/Mod/Ship/simRun/theory/main.tex | 90 ++ src/Mod/Ship/simRun/theory/main.toc | 22 + src/Mod/Ship/simRun/theory/test/green.py | 127 +++ src/Mod/Ship/simRun/theory/test/main.py | 285 ++++++ src/Mod/Ship/simRun/theory/test/waves.py | 94 ++ 51 files changed, 7305 insertions(+), 401 deletions(-) create mode 100644 src/Mod/Ship/resources/opencl/jacobi.cl create mode 100644 src/Mod/Ship/resources/opencl/lsqr.cl create mode 100644 src/Mod/Ship/resources/opencl/matrixGen.cl create mode 100644 src/Mod/Ship/resources/opencl/minres.cl create mode 100644 src/Mod/Ship/simRun/Sim/BEMsolver.py create mode 100644 src/Mod/Ship/simRun/Sim/evolution.py create mode 100644 src/Mod/Ship/simRun/clSim/BEMsolver.py create mode 100644 src/Mod/Ship/simRun/clSim/bem_jacobi_cl.py create mode 100644 src/Mod/Ship/simRun/clSim/bem_lsqr_cl.py create mode 100644 src/Mod/Ship/simRun/clSim/bem_minres_cl.py create mode 100644 src/Mod/Ship/simRun/clSim/clUtils.py create mode 100644 src/Mod/Ship/simRun/clSim/evolution.py create mode 100644 src/Mod/Ship/simRun/clSim/matrixGen.py create mode 100644 src/Mod/Ship/simRun/theory/abstract.tex create mode 100644 src/Mod/Ship/simRun/theory/bib.bib create mode 100644 src/Mod/Ship/simRun/theory/deep_water.wxmx create mode 100644 src/Mod/Ship/simRun/theory/images/CC_88x31.png create mode 100644 src/Mod/Ship/simRun/theory/images/Integral.png create mode 100644 src/Mod/Ship/simRun/theory/images/Integral.svg create mode 100644 src/Mod/Ship/simRun/theory/images/Omega.png create mode 100644 src/Mod/Ship/simRun/theory/images/Omega.svg create mode 100644 src/Mod/Ship/simRun/theory/images/Omega2.png create mode 100644 src/Mod/Ship/simRun/theory/images/Omega2.svg create mode 100644 src/Mod/Ship/simRun/theory/images/test_bem.png create mode 100644 src/Mod/Ship/simRun/theory/images/test_direct.png create mode 100644 src/Mod/Ship/simRun/theory/images/test_wave.png create mode 100644 src/Mod/Ship/simRun/theory/laplace2D.tex create mode 100644 src/Mod/Ship/simRun/theory/laplace3D.tex create mode 100644 src/Mod/Ship/simRun/theory/main.aux create mode 100644 src/Mod/Ship/simRun/theory/main.bbl create mode 100644 src/Mod/Ship/simRun/theory/main.blg create mode 100644 src/Mod/Ship/simRun/theory/main.log create mode 100644 src/Mod/Ship/simRun/theory/main.out create mode 100644 src/Mod/Ship/simRun/theory/main.pdf create mode 100644 src/Mod/Ship/simRun/theory/main.tex create mode 100644 src/Mod/Ship/simRun/theory/main.toc create mode 100644 src/Mod/Ship/simRun/theory/test/green.py create mode 100644 src/Mod/Ship/simRun/theory/test/main.py create mode 100644 src/Mod/Ship/simRun/theory/test/waves.py diff --git a/src/Mod/Ship/CMakeLists.txt b/src/Mod/Ship/CMakeLists.txt index 8137d225d..aa87360bd 100644 --- a/src/Mod/Ship/CMakeLists.txt +++ b/src/Mod/Ship/CMakeLists.txt @@ -21,6 +21,14 @@ SET(ShipExamples_SRCS ) SOURCE_GROUP("shipexamples" FILES ${ShipExamples_SRCS}) +SET(ShipOpenCL_SRCS + resources/opencl/matrixGen.cl + resources/opencl/jacobi.cl + resources/opencl/minres.cl + resources/opencl/lsqr.cl +) +SOURCE_GROUP("shipopencl" FILES ${ShipOpenCL_SRCS}) + SET(ShipLoadExample_SRCS shipLoadExample/__init__.py shipLoadExample/TaskPanel.py @@ -107,12 +115,18 @@ SET(SimRun_SRCS simRun/TaskPanel.ui simRun/clSim/__init__.py simRun/clSim/initialization.py - simRun/clSim/Utils.py + simRun/clSim/matrixGen.py + simRun/clSim/BEMsolver.py + simRun/clSim/evolution.py + simRun/clSim/clUtils.py + simRun/clSim/bem_jacobi_cl.py + simRun/clSim/bem_minres_cl.py + simRun/clSim/bem_lsqr_cl.py simRun/Sim/__init__.py simRun/Sim/initialization.py simRun/Sim/matrixGen.py - simRun/Sim/computeSources.py - simRun/Sim/fsEvolution.py + simRun/Sim/BEMsolver.py + simRun/Sim/evolution.py ) SOURCE_GROUP("simrun" FILES ${SimRun_SRCS}) @@ -123,7 +137,7 @@ SET(SimPost_SRCS ) 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}) +SET(all_files ${ShipMain_SRCS} ${ShipIcons_SRCS} ${ShipExamples_SRCS} ${ShipOpenCL_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} @@ -143,6 +157,12 @@ INSTALL( DESTINATION Mod/Ship/resources/examples ) +INSTALL( + FILES + ${ShipOpenCL_SRCS} + DESTINATION + Mod/Ship/resources/opencl +) INSTALL( FILES ${ShipLoadExample_SRCS} diff --git a/src/Mod/Ship/Makefile.am b/src/Mod/Ship/Makefile.am index fd24beac6..c71bc97b5 100644 --- a/src/Mod/Ship/Makefile.am +++ b/src/Mod/Ship/Makefile.am @@ -15,6 +15,10 @@ nobase_data_DATA = \ resources/examples/wigley.fcstd \ resources/examples/wigley_katamaran.fcstd \ resources/icons/Ico.xpm \ + resources/opencl/matrixGen.cl \ + resources/opencl/jacobi.cl \ + resources/opencl/minres.cl \ + resources/opencl/lsqr.cl \ shipLoadExample/__init__.py \ shipLoadExample/TaskPanel.py \ shipLoadExample/TaskPanel.ui \ @@ -60,12 +64,18 @@ nobase_data_DATA = \ simRun/TaskPanel.ui \ simRun/clSim/__init__.py \ simRun/clSim/initialization.py \ - simRun/clSim/Utils.py \ + simRun/clSim/matrixGen.py \ + simRun/clSim/BEMsolver.py \ + simRun/clSim/evolution.py \ + simRun/clSim/clUtils.py \ + simRun/clSim/bem_jacobi_cl.py \ + simRun/clSim/bem_minres_cl.py \ + simRun/clSim/bem_lsqr_cl.py \ simRun/Sim/__init__.py \ simRun/Sim/initialization.py \ simRun/Sim/matrixGen.py \ - simRun/Sim/computeSources.py \ - simRun/Sim/fsEvolution.py \ + simRun/Sim/BEMsolver.py \ + simRun/Sim/evolution.py \ simPost/__init__.py \ simPost/TaskPanel.py \ simPost/TaskPanel.ui diff --git a/src/Mod/Ship/SimInstance.py b/src/Mod/Ship/SimInstance.py index 0e8f6db2a..638c17612 100644 --- a/src/Mod/Ship/SimInstance.py +++ b/src/Mod/Ship/SimInstance.py @@ -62,19 +62,38 @@ class FreeSurfaceFace: self.area = area class ShipSimulation: - def __init__(self, obj, fsMeshData, waves): + def __init__(self, obj, fsMeshData, waves, error): """ Creates a new simulation instance on active document. @param obj Created Part::FeaturePython object. + @param h Sea water level. @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 + @param waves [[A,T,phi,heading],] Waves involved. + @param error Relation between the minimum and the maximum Green's function values. """ # Add uniqueness property to identify Tank instances tooltip = str(QtGui.QApplication.translate("Ship","True if is a valid ship simulation instance", None,QtGui.QApplication.UnicodeUTF8)) obj.addProperty("App::PropertyBool","IsShipSimulation","ShipSimulation", tooltip).IsShipSimulation=True + # Store general data + tooltip = str(QtGui.QApplication.translate("Ship","Free surface length in the x direction", + None,QtGui.QApplication.UnicodeUTF8)) + obj.addProperty("App::PropertyFloat","L","ShipSimulation", tooltip).L=fsMeshData[0] + tooltip = str(QtGui.QApplication.translate("Ship","Free surface length in the y direction", + None,QtGui.QApplication.UnicodeUTF8)) + obj.addProperty("App::PropertyFloat","B","ShipSimulation", tooltip).B=fsMeshData[1] + tooltip = str(QtGui.QApplication.translate("Ship","Free surface number of elements at x direction", + None,QtGui.QApplication.UnicodeUTF8)) + obj.addProperty("App::PropertyInteger","FS_Nx","ShipSimulation", tooltip).FS_Nx=fsMeshData[2] + tooltip = str(QtGui.QApplication.translate("Ship","Free surface number of elements at y direction", + None,QtGui.QApplication.UnicodeUTF8)) + obj.addProperty("App::PropertyInteger","FS_Ny","ShipSimulation", tooltip).FS_Ny=fsMeshData[3] + tooltip = str(QtGui.QApplication.translate("Ship","Relative error of the Green's function", + None,QtGui.QApplication.UnicodeUTF8)) + obj.addProperty("App::PropertyFloat","error","ShipSimulation", tooltip).error=error # Compute free surface mesh self.createFSMesh(obj,fsMeshData) + self.createVirtualFS(obj,fsMeshData,error) self.computeWaves(obj,waves) # Store waves tooltip = str(QtGui.QApplication.translate("Ship","Waves (Amplitude,period,phase)", @@ -112,8 +131,8 @@ class ShipSimulation: 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. + @param fsMeshData [L,B,Nx,Ny] Free surface mesh data, with lenght + (x), Breath (y) and desired number of points at each direction. """ # Study input object try: @@ -130,29 +149,17 @@ class ShipSimulation: FreeCAD.Console.PrintError(msg + '\n') return # Get areas and number of elements per direction - L = fsMeshData[0] - B = fsMeshData[1] - N = fsMeshData[2] - A = L*B + L = fsMeshData[0] + B = fsMeshData[1] + nx = fsMeshData[2] + ny = fsMeshData[3] + N = nx*ny + A = L*B area = A/N - l = sqrt(area) - b = sqrt(area) - nx = int(round(L / l)) - ny = int(round(B / b)) + l = L/nx + b = B/ny # Start data fields if not already exist props = obj.PropertiesList - try: - props.index("FS_Nx") - except ValueError: - tooltip = str(QtGui.QApplication.translate("Ship","Free surface number of elements at x direction", - None,QtGui.QApplication.UnicodeUTF8)) - obj.addProperty("App::PropertyInteger","FS_Nx","ShipSimulation", tooltip).FS_Nx=0 - try: - props.index("FS_Ny") - except ValueError: - tooltip = str(QtGui.QApplication.translate("Ship","Free surface number of elements at y direction", - None,QtGui.QApplication.UnicodeUTF8)) - obj.addProperty("App::PropertyInteger","FS_Ny","ShipSimulation", tooltip).FS_Ny=0 try: props.index("FS_Position") except ValueError: @@ -172,6 +179,8 @@ class ShipSimulation: None,QtGui.QApplication.UnicodeUTF8)) obj.addProperty("App::PropertyVectorList","FS_Normal","ShipSimulation", tooltip).FS_Normal=[] # Fill data + obj.L = L + obj.B = B obj.FS_Nx = nx obj.FS_Ny = ny pos = [] @@ -186,6 +195,68 @@ class ShipSimulation: obj.FS_Area = areas[:] obj.FS_Normal = normal[:] + def createVirtualFS(self, obj, fsMeshData, error): + """ Computes the number of required extended free surfaces. + @param obj Created Part::FeaturePython object. + @param fsMeshData [L,B,Nx,Ny] Free surface mesh data, with lenght + (x), Breath (y) and desired number of points at each direction. + @param error Relation between the minimum and the maximum Green's function values. + """ + # Study input object + try: + props = obj.PropertiesList + props.index("IsShipSimulation") + if not obj.IsShipSimulation: + msg = QtGui.QApplication.translate("ship_console", "Object is not a valid ship simulation", + None,QtGui.QApplication.UnicodeUTF8) + FreeCAD.Console.PrintError(msg + '\n') + return + except ValueError: + msg = QtGui.QApplication.translate("ship_console", "Object is not a ship simulation", + None,QtGui.QApplication.UnicodeUTF8) + FreeCAD.Console.PrintError(msg + '\n') + return + # Get dimensions of the elements + L = fsMeshData[0] + B = fsMeshData[1] + nx = fsMeshData[2] + ny = fsMeshData[3] + dx = L / nx + dy = B / ny + # Compute maximum Green's function considering flat free surface + Gmax = dx*asinh(dy/dx) + dy*asinh(dx/dy) + # Locate the distance (number of free surface) to get the minimum required value + Gmin = error*Gmax + x = (L-dx)/2.0 + Nx = 0 + G = Gmin + 1.0 + while(G > Gmin): + x = x + L + Nx = Nx + 1 + G = 1.0 / (4.0*pi * x) + y = (B-dy)/2.0 + Ny = 0 + G = Gmin + 1.0 + while(G > Gmin): + y = y + L + Ny = Ny + 1 + G = 1.0 / (4.0*pi * y) + # Register computed data + try: + props.index("Sea_Nx") + except ValueError: + tooltip = str(QtGui.QApplication.translate("Ship","Number of repetitions of the free surface at x direction", + None,QtGui.QApplication.UnicodeUTF8)) + obj.addProperty("App::PropertyInteger","Sea_Nx","ShipSimulation", tooltip).Sea_Nx=0 + try: + props.index("Sea_Ny") + except ValueError: + tooltip = str(QtGui.QApplication.translate("Ship","Number of repetitions of the free surface at y direction", + None,QtGui.QApplication.UnicodeUTF8)) + obj.addProperty("App::PropertyInteger","Sea_Ny","ShipSimulation", tooltip).Sea_Ny=0 + obj.Sea_Nx = Nx + obj.Sea_Ny = Ny + def computeWaves(self, obj, waves): """ Add waves effect to free surface mesh positions. @param obj Created Part::FeaturePython object. @@ -215,21 +286,14 @@ class ShipSimulation: """ 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) + mesh = FSMesh(obj) + surf = Part.BSplineSurface() + pos = [] for i in range(0,nx): + pos.append([]) 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) + pos[i].append(mesh[i][j].pos) + surf.interpolate(pos) return surf.toShape() class ViewProviderShipSimulation: @@ -694,3 +758,4 @@ def FSMesh(obj, recompute=False): 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/resources/opencl/jacobi.cl b/src/Mod/Ship/resources/opencl/jacobi.cl new file mode 100644 index 000000000..88eadc992 --- /dev/null +++ b/src/Mod/Ship/resources/opencl/jacobi.cl @@ -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 * + */ + +/** Compute residuals of the solution stimator for a linear system. + * @param A Linear system matrix. + * @param B Linear system independent term. + * @param X Solution estimation. + * @param R Residuals. + * @param n Linear system dimension. + */ +__kernel void r(__global float* A, + __global float* B, + __global float* X, + __global float* R, + unsigned int n) +{ + // find position in global arrays + unsigned int i = get_global_id(0); + unsigned int j; + if(i >= n) + return; + // Evaluate the row + R[i] = B[i]; + for(j=0;j= n) + return; + // Evaluate the row + X[i] = B[i]; + for(j=0;j * + * * + * 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 * + */ + +/** Get matrix column. + * @param A Linear system matrix. + * @param v Column vector (output). + * @param col Column index. + * @param n Linear system dimension. + */ +__kernel void column(__global float* A, + __global float* v, + unsigned int col, + unsigned int n) +{ + // find position in global arrays + unsigned int i = get_global_id(0); + if(i >= n) + return; + v[i] = A[i + col*n]; +} + +/** Performs matrix column product by a constant. + * @param A Linear system matrix. + * @param c Constant. + * @param col Column index. + * @param n Linear system dimension. + */ +__kernel void prod_c_column(__global float* A, + float c, + unsigned int col, + unsigned int n) +{ + // find position in global arrays + unsigned int i = get_global_id(0); + if(i >= n) + return; + A[i + col*n] *= c; +} + +/** Compute residuals of the solution stimator for a linear system. + * @param A Linear system matrix. + * @param B Linear system independent term. + * @param X Solution estimation. + * @param R Residuals. + * @param n Linear system dimension. + */ +__kernel void r(__global float* A, + __global float* B, + __global float* X, + __global float* R, + unsigned int n) +{ + // find position in global arrays + unsigned int i = get_global_id(0); + unsigned int j; + if(i >= n) + return; + // Evaluate the row + R[i] = B[i]; + for(j=0;j= n) + return; + // Evaluate the row + Y[i] = 0.f; + for(j=0;j= n) + return; + // Evaluate the row + Y[i] = 0.f; + for(j=0;j= n) + return; + // Evaluate the row + u[i] = - alpha * u0[i]; + for(j=0;j= n) + return; + // Evaluate the row + v[i] = - beta * v0[i]; + for(j=0;j * + * * + * 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 * + */ + +#ifndef M_PI + #define M_PI 3.14159265f +#endif + +#ifndef _NG_ + #define _NG_ 16 +#endif + +/** Compute \$G_{ab}\$ effect: \n + * \$ G_{ab} = \frac{1}{4 \pi \vert \mathbf{r} \vert } \$ + * @param r Union vector \$ \mathbf{r}_{ab} \$ + */ +float G_val(float4 r) +{ + return 1.f / ( 4.f*M_PI * length(r) ); +} + +/** Compute \$H_{ab}\$ effect: \n + * \$ H_{ab} = \frac{\mathbf{r}}{4 \pi \vert \mathbf{r} \vert^3} \cdot n_b \$ + * @param r Union vector \$ \mathbf{r}_{ab} \$ + * @param n Element normal \$ n_b \$ + */ +float H_val(float4 r, + float4 n) +{ + return - dot(r,n) / (4.f*M_PI * pow(dot(r,r),1.5f)); +} + +/** Computes z coordinate due to the waves superposition + * for a desired position. + * @param w Array of waves. + * @param p Point to compute. + * @param t Simulation time. + * @param nW Number of waves. + * @return z coordinate. + */ +float waves_z(__global float4* w, float4 p, float t, unsigned int nW) +{ + /* + return 0.f; + */ + + unsigned int i; + float z = 0.f; + for(i=0;i -0.5*L) && + (P[i*3+j].x < 0.5*L) && + (P[i*3+j].y > -0.5*B) && + (P[i*3+j].y < 0.5*B)) + P[i*3+j].z = positions[(I-1+i)*ny + (J-1+j)].z; + else + P[i*3+j].z = waves_z(w, P[i*3+j], t, nW); + P[i*3+j].w = 0.f; + } + } + // Get SPline surface coeffs + K[0] = P[0].z; // k_{0} + K[1] = 4*P[3].z - P[6].z - 3*P[0].z; // k_{u} + K[2] = 4*P[1].z - P[2].z - 3*P[0].z; // k_{v} + K[3] = P[8].z - 4*P[7].z + 3*P[6].z + + 3*P[2].z - 12*P[1].z + 9*P[0].z + + -4*P[5].z + 16*P[4].z - 12*P[3].z; // k_{uv} + K[4] = 2*P[6].z + 2*P[0].z - 4*P[3].z; // k_{uu} + K[5] = 2*P[2].z + 2*P[0].z - 4*P[1].z; // k_{vv} + K[6] = -2*P[8].z + 8*P[7].z - 6*P[6].z + + -2*P[2].z + 8*P[1].z - 6*P[0].z + + 4*P[5].z - 16*P[4].z + 12*P[3].z; // k_{uuv} + K[7] = -2*P[8].z + 4*P[7].z - 2*P[6].z + + -6*P[2].z + 12*P[1].z - 6*P[0].z + + 8*P[5].z - 16*P[4].z + 8*P[3].z; // k_{uuv} + K[8] = 4*P[8].z - 8*P[7].z + 4*P[6].z + + 4*P[2].z - 8*P[1].z + 4*P[0].z + + -8*P[5].z + 16*P[4].z - 8*P[3].z; // k_{uuvv} + // Loop around the point p collecting the integral + float2 gh; + gh.x = 0.0f; + gh.y = -0.5f; + for(i=0;i<_NG_;i++){ + for(j=0;j<_NG_;j++){ + float4 p_a; + float u,v; + p_a.x = positions[I*ny + J].x - 0.5f*dx + (i+0.5f)*Dx; + p_a.y = positions[I*ny + J].y - 0.5f*dy + (j+0.5f)*Dy; + u = (p_a.x - P[0].x) / (P[6].x - P[0].x); + v = (p_a.y - P[0].y) / (P[2].y - P[0].y); + p_a.z = K[0] + K[1]*u + K[2]*v + K[3]*u*v + + K[4]*u*u + K[5]*v*v + K[6]*u*u*v + + K[7]*u*v*v + K[8]*u*u*v*v; + p_a.w = 1.f; + gh.x += G_val(p_a - p)*Dx*Dy; + // For some reason H is not well integrated + // gh.y += H_val(p_a - p, n)*Dx*Dy; + } + } + return gh; +} + +/** Compute Linear system matrix. Desingularized sources must taken into account. + * @param A Linear system matrix. + * @param B Independent term for velocity potentials. + * @param positions Elements points. + * @param areas Elements area. + * @param normals Elements normals. + * @param p Velocity potentials. + * @param dp Acceleration potentials. + * @param waves Array of waves data (Amplitude,period,phase,heading) + * @param l Free surface length in the x direction. + * @param b Free surface length in the y direction. + * @param dx Distance between element centers in the x direction. + * @param dy Distance between element centers in the x direction. + * @param t Simulation time. + * @param nx Free surface points in the x direction. + * @param ny Free surface points in the y direction. + * @param nFS Number of points in the free surface. + * @param nB Number of points in the body (ignored yet, should be 0). + * @param n Total number of points. + * @param nSeax Number of repetitions of the free surface in the x direction. + * @param nSeay Number of repetitions of the free surface in the y direction. + * @param nW Number of waves. + */ +__kernel void matrixGen(__global float* A, + __global float* B, + __global float4* positions, + __global float* areas, + __global float4* normals, + __global float* p, + __global float* dp, + __global float4* waves, + float l, + float b, + float dx, + float dy, + float t, + unsigned int nx, + unsigned int ny, + unsigned int nFS, + unsigned int nB, + unsigned int n, + int nSeax, + int nSeay, + unsigned int nW) +{ + // find position in global arrays + unsigned int i = get_global_id(0); + unsigned int j; + int I,J; + if(i >= n) + return; + // Get the point where we want to evaluate + float4 p_a = positions[i]; + // Evaluate the row + B[i] = 0.f; + for(j=0;j * + * * + * 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 * + */ + +/** Compute residuals of the solution stimator for a linear system. + * @param A Linear system matrix. + * @param B Linear system independent term. + * @param X Solution estimation. + * @param R Residuals. + * @param n Linear system dimension. + */ +__kernel void r(__global float* A, + __global float* B, + __global float* X, + __global float* R, + unsigned int n) +{ + // find position in global arrays + unsigned int i = get_global_id(0); + unsigned int j; + if(i >= n) + return; + // Evaluate the row + R[i] = B[i]; + for(j=0;j= n) + return; + // Evaluate the row + Y[i] = 0.f; + for(j=0;j= n) + return; + // Evaluate the row + x[i] = x0[i] + Ar_r / Ar_Ar * r[i]; +} + diff --git a/src/Mod/Ship/simCreate/TaskPanel.py b/src/Mod/Ship/simCreate/TaskPanel.py index 7e200532b..1f3592709 100644 --- a/src/Mod/Ship/simCreate/TaskPanel.py +++ b/src/Mod/Ship/simCreate/TaskPanel.py @@ -49,9 +49,10 @@ class TaskPanel: 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) + sim = SimInstance.ShipSimulation(obj, + [form.fsL.value(), form.fsB.value(), form.fsNx.value(), form.fsNy.value()], + w, + form.error.value()) SimInstance.ViewProviderShipSimulation(obj.ViewObject) return True @@ -80,21 +81,25 @@ class TaskPanel: 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") + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.fsL = form.findChild(QtGui.QDoubleSpinBox, "Length") + form.fsB = form.findChild(QtGui.QDoubleSpinBox, "Beam") + form.fsNx = form.findChild(QtGui.QSpinBox, "Nx") + form.fsNy = form.findChild(QtGui.QSpinBox, "Ny") + form.error = form.findChild(QtGui.QDoubleSpinBox, "Error") + 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.fsL, QtCore.SIGNAL("valueChanged(double)"), self.onFS) + QtCore.QObject.connect(form.fsB, QtCore.SIGNAL("valueChanged(double)"), self.onFS) + QtCore.QObject.connect(form.fsNx, QtCore.SIGNAL("valueChanged(int)"), self.onFS) + QtCore.QObject.connect(form.fsNy, QtCore.SIGNAL("valueChanged(int)"), self.onFS) + QtCore.QObject.connect(form.error, QtCore.SIGNAL("valueChanged(double)"), self.onError) QtCore.QObject.connect(form.waves,QtCore.SIGNAL("cellChanged(int,int)"),self.onWaves); def getMainWindow(self): @@ -120,14 +125,12 @@ class TaskPanel: None,QtGui.QApplication.UnicodeUTF8)) self.form.findChild(QtGui.QGroupBox, "FSDataBox").setTitle(QtGui.QApplication.translate("shipsim_create","Free surface", None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "LengthLabel").setText(QtGui.QApplication.translate("shipsim_create","Length", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "BeamLabel").setText(QtGui.QApplication.translate("shipsim_create","Breadth", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "NLabel").setText(QtGui.QApplication.translate("shipsim_create","Number of points", - None,QtGui.QApplication.UnicodeUTF8)) self.form.findChild(QtGui.QGroupBox, "WavesDataBox").setTitle(QtGui.QApplication.translate("shipsim_create","Waves", None,QtGui.QApplication.UnicodeUTF8)) + self.form.findChild(QtGui.QGroupBox, "OtherBox").setTitle(QtGui.QApplication.translate("shipsim_create","Other", + None,QtGui.QApplication.UnicodeUTF8)) + self.form.findChild(QtGui.QLabel, "ErrorLabel").setText(QtGui.QApplication.translate("shipsim_create","Relative error", + None,QtGui.QApplication.UnicodeUTF8)) labels = [] labels.append(QtGui.QApplication.translate("shipsim_create","Amplitude", None,QtGui.QApplication.UnicodeUTF8) + " [m]") @@ -138,6 +141,27 @@ class TaskPanel: labels.append(QtGui.QApplication.translate("shipsim_create","Heading", None,QtGui.QApplication.UnicodeUTF8) + " [deg]") self.form.waves.setHorizontalHeaderLabels(labels) + # Set some tooltips + tooltip = QtGui.QApplication.translate("shipsim_create","Free surface length on x direction", + None,QtGui.QApplication.UnicodeUTF8) + self.form.findChild(QtGui.QLabel, "LengthLabel").setToolTip(tooltip) + self.form.findChild(QtGui.QDoubleSpinBox, "Length").setToolTip(tooltip) + tooltip = QtGui.QApplication.translate("shipsim_create","Free surface length on y direction", + None,QtGui.QApplication.UnicodeUTF8) + self.form.findChild(QtGui.QLabel, "BeamLabel").setToolTip(tooltip) + self.form.findChild(QtGui.QDoubleSpinBox, "Beam").setToolTip(tooltip) + tooltip = QtGui.QApplication.translate("shipsim_create","Number of nodes on x direction. Take into acount the following considerations:\n1.\tNodes must have an aspect ratio as near to 1,0 as possible, so this values must\n\taccomplish approximately that Nx/Ny = L/B\n3.\tThe linear system matrix generated will be of dimensions NxN, where\n\tN = Nx*Ny\n\tSo be mindful with the values selected and computer capabilities.", + None,QtGui.QApplication.UnicodeUTF8) + self.form.findChild(QtGui.QLabel, "NxLabel").setToolTip(tooltip) + self.form.findChild(QtGui.QSpinBox, "Nx").setToolTip(tooltip) + tooltip = QtGui.QApplication.translate("shipsim_create","Number of nodes on y direction. Take into acount the following considerations:\n1.\tNodes must have an aspect ratio as near to 1,0 as possible, so this values must\n\taccomplish approximately that Nx/Ny = L/B\n3.\tThe linear system matrix generated will be of dimensions NxN, where\n\tN = Nx*Ny\n\tSo be mindful with the values selected and computer capabilities.", + None,QtGui.QApplication.UnicodeUTF8) + self.form.findChild(QtGui.QLabel, "NyLabel").setToolTip(tooltip) + self.form.findChild(QtGui.QSpinBox, "Ny").setToolTip(tooltip) + tooltip = QtGui.QApplication.translate("shipsim_create","Relation between the minimum value of the Green's function (fartest point) and the maximum one.\nThis variable set the number of times that the Free surface will be virtually repeated.\nLower values may imply too much repeated free surfaces with a significant cost.", + None,QtGui.QApplication.UnicodeUTF8) + self.form.findChild(QtGui.QLabel, "ErrorLabel").setToolTip(tooltip) + self.form.findChild(QtGui.QDoubleSpinBox, "Error").setToolTip(tooltip) def onFS(self, value): """ Method called when free surface data is changed. @@ -145,6 +169,12 @@ class TaskPanel: """ pass + def onError(self, value): + """ Method called when sea data is changed. + @param value Changed value. + """ + pass + def onWaves(self, row, column): """ Method called when waves data is changed. @param row Affected row. diff --git a/src/Mod/Ship/simCreate/TaskPanel.ui b/src/Mod/Ship/simCreate/TaskPanel.ui index 107d2a16d..6dcc376a5 100644 --- a/src/Mod/Ship/simCreate/TaskPanel.ui +++ b/src/Mod/Ship/simCreate/TaskPanel.ui @@ -6,7 +6,7 @@ 0 0 - 269 + 386 384 @@ -42,7 +42,7 @@ 0 - 128 + 0 @@ -55,11 +55,11 @@ false - - QLayout::SetDefaultConstraint - + + 2 + QLayout::SetMinimumSize @@ -78,15 +78,27 @@ - Length + L + + + 0 + 0 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + 1 + + 1.000000000000000 + 1000000.000000000000000 @@ -98,37 +110,30 @@ - - - - - - QLayout::SetMinimumSize - - - 10 - - - 0 - - - 10 - - - 0 - - Beam + B + + + 0 + 0 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + 1 + + 1.000000000000000 + 1000000.000000000000000 @@ -160,22 +165,60 @@ 0 - + - Number of points + Nx - + + + + 0 + 0 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 3 + + + 10000000 + + + 25 + + + + + + + Ny + + + + + + + + 0 + 0 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + 1 - 1000000000 + 1000000 - 1000 + 25 @@ -260,6 +303,48 @@ + + + + Other + + + + + + + + Relative error + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + 0.000100000000000 + + + 1.000000000000000 + + + 0.001000000000000 + + + 0.001000000000000 + + + + + + + + diff --git a/src/Mod/Ship/simRun/Sim/BEMsolver.py b/src/Mod/Ship/simRun/Sim/BEMsolver.py new file mode 100644 index 000000000..da6932483 --- /dev/null +++ b/src/Mod/Ship/simRun/Sim/BEMsolver.py @@ -0,0 +1,55 @@ +#*************************************************************************** +#* * +#* 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 +import scipy.linalg as la +import FreeCAD + +grav=9.81 + +class simBEMSolver: + 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, bem): + """ Compute potential unknow data (gradients for free surface, and + potentials for the other ones). + @param bem Boundary Element Method instance. + """ + [bem['Ap'], residues, rank, s] = la.lstsq(bem['A'], bem['B']) + if(rank < bem['N']): + FreeCAD.Console.PrintError("\t\t[Sim]: Solving velocity potentials.\n") + FreeCAD.Console.PrintError("\t\t\tEffective rank of linear system matrix is %i (N = %i)\n" % (rank, bem['N'])) + [bem['Adp'], residues, rank, s] = la.lstsq(bem['A'], bem['dB']) + if(rank < bem['N']): + FreeCAD.Console.PrintError("\t\t[Sim]: Solving acceleration potentials.\n") + FreeCAD.Console.PrintError("\t\t\tEffective rank of linear system matrix is %i (N = %i)\n" % (rank, bem['N'])) + diff --git a/src/Mod/Ship/simRun/Sim/__init__.py b/src/Mod/Ship/simRun/Sim/__init__.py index aabf4a621..6a185fde4 100644 --- a/src/Mod/Ship/simRun/Sim/__init__.py +++ b/src/Mod/Ship/simRun/Sim/__init__.py @@ -23,5 +23,5 @@ from initialization import * from matrixGen import * -from computeSources import * -from fsEvolution import * +from BEMsolver import * +from evolution import * diff --git a/src/Mod/Ship/simRun/Sim/evolution.py b/src/Mod/Ship/simRun/Sim/evolution.py new file mode 100644 index 000000000..1108cefe1 --- /dev/null +++ b/src/Mod/Ship/simRun/Sim/evolution.py @@ -0,0 +1,304 @@ +#*************************************************************************** +#* * +#* 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 simEvolution: + 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 executeRK4(self, x, dx, p, dp, pos, vel, phi, dphi, fs, sea, body, waves, dt, t, stage): + """ Compute free surface RK4 stage evolution process (valid for stages 1,2 and 3). + @param x Output free surface z coordinates. + @param dx Output free surface z coordinates variation (dz/dt). + @param p Output potentials. + @param dp Output potentials variation (dphi/dt). + @param pos Input free surface positions. + @param vel Input free surface velocities. + @param phi Input potentials. + @param dphi Input potentials variation (dphi/dt). + @param fs Free surface instance. + @param sea Sea instance. + @param body Body instance. + @param waves Waves instance. + @param dt Time step. + @param t Actual time (without adding dt). + @param stage Runge-Kutta4 stage. + @return Input variables evoluted one time step. + """ + # -------------------------------------------- + # Only free surface + # -------------------------------------------- + h = fs['h'] + nx = fs['Nx'] + ny = fs['Ny'] + nF = nx*ny + factor = 0.5 + if stage > 2: + factor = 1. + for i in range(0,nx): + for j in range(0,ny): + x[i,j] = np.copy(pos[i,j][2]) + dx[i,j] = np.copy(vel[i,j][2]) + x[i,j] = x[i,j] + factor*dt*dx[i,j] + p[i*ny+j] = np.copy(phi[i*ny+j]) + dp[i*ny+j] = np.copy(dphi[i*ny+j]) + p[i*ny+j] = p[i*ny+j] + factor*dt*dp[i*ny+j] + # Impose values at beach (far free surface) + nbx = fs['Beachx'] + nby = fs['Beachy'] + for i in range(0,nx): + for j in range(0,nby) + range(ny-nby,ny): + [x[i,j],dx[i,j],p[i*ny+j],dp[i*ny+j]] = self.beach(pos[i,j], waves, factor*dt, t) + for j in range(0,ny): + for i in range(0,nbx) + range(nx-nbx,nx): + [x[i,j],dx[i,j],p[i*ny+j],dp[i*ny+j]] = self.beach(pos[i,j], waves, factor*dt, t) + # -------------------------------------------- + # Sea boundaries, where potentials are fixed. + # We use the gradient projected over normal, + # see initialization for more details about + # this. + # -------------------------------------------- + ids = ['front','back','left','right','bottom'] + i0 = fs['N'] + for index in ids: + s = sea[index] + nx = s['Nx'] + ny = s['Ny'] + for i in range(0,nx): + for j in range(0,ny): + p[i0 + i*ny+j] = 0. + dp[i0 + i*ny+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 + pos = s['pos'][i,j] + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + normal = s['normal'][i,j] + hfact = np.cosh(k*(pos[2]+h)) / np.cosh(k*h) + factor = np.dot(normal,np.array([np.cos(heading), np.sin(heading), 0.])) + amp = frec*A*np.sin(k*l - frec*(t+factor*dt) + phase)*hfact + p[i0 + i*ny+j] = p[i0 + i*ny+j] + factor*amp + amp = - grav*A*k*np.cos(k*l - frec*(t+factor*dt) + phase)*hfact + dp[i0 + i*ny+j] = dp[i0 + i*ny+j] + factor*amp + i0 = i0 + s['N'] + + def execute(self, dx1, dx2, dx3, dp1, dp2, dp3, fs, sea, body, waves, bem, dt, t): + """ Compute free surface evolution process (execute it on RK4 last stage). + @param dx1 Input free surface positions variation on stage 1. + @param dx2 Input free surface positions variation on stage 2. + @param dx3 Input free surface positions variation on stage 3. + @param dp1 Input free surface potentials variation on stage 1. + @param dp2 Input free surface potentials variation on stage 2. + @param dp3 Input free surface potentials variation on stage 3. + @param fs Free surface instance. + @param sea Sea instance. + @param body Body instance. + @param waves Waves instance. + @param bem Boundary Element Method instance. + @param dt Time step. + @param t Actual time (without adding dt). + @param stage Runge-Kutta4 stage. + @return Input variables evoluted one time step. + """ + h = fs['h'] + nx = fs['Nx'] + ny = fs['Ny'] + nF = nx*ny + for i in range(0,nx): + for j in range(0,ny): + # In this stage dx4 and dp4 are directly known from the previous + # stage. + dx4 = fs['vel'][i,j][2] + dp4 = bem['dp4'][i*ny+j] + # And we only need to apply the integration scheme + fs['pos'][i,j][2] = fs['pos'][i,j][2] + dt/6. * (dx1[i,j] + 2.*dx2[i,j] + 2.*dx3[i,j] + dx4) + bem['p4'][i*ny+j] = bem['p4'][i*ny+j] + dt/6. * (dp1[i*ny+j] + 2.*dp2[i*ny+j] + 2.*dp3[i*ny+j] + dp4) + # In order to can apply the boundary condition at the free surface + # at the end of this RK4 stage, we need to store eta in a variable. + # x1 is safe because will be over written at the start of next + # time step. + fs['x1'][i,j] = fs['pos'][i,j][2] + # Impose values at beach (far free surface) + nbx = fs['Beachx'] + nby = fs['Beachy'] + for i in range(0,nx): + for j in range(0,nby) + range(ny-nby,ny): + [x,dummy,p,dummy] = self.beach(fs['pos'][i,j], waves, dt, t) + fs['pos'][i,j][2] = x + bem['p4'][i*ny+j] = p + fs['x1'][i,j] = fs['pos'][i,j][2] + for j in range(0,ny): + for i in range(0,nbx) + range(nx-nbx,nx): + [x,dummy,p,dummy] = self.beach(fs['pos'][i,j], waves, dt, t) + fs['pos'][i,j][2] = x + bem['p4'][i*ny+j] = p + fs['x1'][i,j] = fs['pos'][i,j][2] + # -------------------------------------------- + # Sea boundaries, where potentials are fixed. + # We use the gradient projected over normal, + # see initialization for more details about + # this. + # -------------------------------------------- + ids = ['front','back','left','right','bottom'] + i0 = fs['N'] + p = bem['p4'] + dp = bem['dp4'] + for index in ids: + s = sea[index] + nx = s['Nx'] + ny = s['Ny'] + for i in range(0,nx): + for j in range(0,ny): + p[i0 + i*ny+j] = 0. + dp[i0 + i*ny+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 + pos = s['pos'][i,j] + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + normal = s['normal'][i,j] + hfact = np.cosh(k*(pos[2]+h)) / np.cosh(k*h) + factor = np.dot(normal,np.array([np.cos(heading), np.sin(heading), 0.])) + amp = frec*A*np.sin(k*l - frec*(t+factor*dt) + phase)*hfact + p[i0 + i*ny+j] = p[i0 + i*ny+j] + factor*amp + amp = - grav*A*k*np.cos(k*l - frec*(t+factor*dt) + phase)*hfact + dp[i0 + i*ny+j] = dp[i0 + i*ny+j] + factor*amp + i0 = i0 + s['N'] + + def executeFSBC(self, x, fs, sea, body, waves, bem, dt, t, stage): + """ Compute free surface boundary conditions in order to get + free surface points velocity and potentials acceleration for + the next RK4 stage. + @param x Free surface z coordinates. + @param fs Free surface instance. + @param sea Sea boundaries instance. + @param body Body instance. + @param waves Waves instance. + @param bem Boundary Element Method instance. + @param dt Time step. + @param t Actual time (without adding dt). + """ + nx = fs['Nx'] + ny = fs['Ny'] + nF = nx*ny + factor = 0.5 + if stage > 2: + factor = 1. + for i in range(0,nx): + for j in range(0,ny): + pos = np.copy(fs['pos'][i,j]) + pos[2] = x[i,j] + gradVal = bem['Ap'][i*ny+j] + normal = fs['normal'][i,j] + # v_z = dphi/dz - grad(phi)*grad(z) - U*dz/dx + dzdt = gradVal*normal[2] + # dphi/dt = - rho*g*z - 0.5*grad(phi)^2 + v_z*dphi/dz - p_0 - U*dphi/dx - dU/dt*x + dphidt = -grav*pos[2] - 0.5*np.dot(gradVal,gradVal) # + dzdt*gradVal*normal[2] + # We need to preserve data on free surface global + # velocity and potential values in order to use as + # input of the next RK4 stage + fs['vel'][i,j][2] = dzdt + bem['dp4'][i*ny+j] = dphidt + # Impose values at beach (far free surface) + nbx = fs['Beachx'] + nby = fs['Beachy'] + for i in range(0,nx): + for j in range(0,nby) + range(ny-nby,ny): + [dummy,dx,dummy,dp] = self.beach(fs['pos'][i,j], waves, factor*dt, t) + fs['vel'][i,j][2] = dx + bem['dp4'][i*ny+j] = dp + for j in range(0,ny): + for i in range(0,nbx) + range(nx-nbx,nx): + [dummy,dx,dummy,dp] = self.beach(fs['pos'][i,j], waves, factor*dt, t) + fs['vel'][i,j][2] = dx + bem['dp4'][i*ny+j] = dp + + def beach(self, pos, waves, dt, t): + """ Compute far free surface where only + incident waves can be taken into account. + @param pos Free surface position. + @param waves Waves instance. + @param dt Time step. + @param t Actual time (without adding dt). + @return Position, velocity, potential and potential acceleration + """ + h = waves['h'] + x = 0. + dx = 0. + p = 0. + dp = 0. + # Since values of the potencial, and this acceleration, + # depends on z, we need to compute first the positions. + 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) + # hfact = np.sinh(k*(pos[2]+h)) / np.cosh(k*h) + hfact = 1.0 + amp = A*np.sin(k*l - frec*(t+dt) + phase)*hfact + x = x + amp + amp = - A*frec*np.cos(k*l - frec*(t+dt) + phase)*hfact + dx = dx + amp + # And now we can compute 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) + hfact = np.cosh(k*(x+h)) / np.cosh(k*h) + amp = - grav/frec*A*np.sin(k*l - frec*(t+dt) + phase)*hfact + p = p + amp + amp = grav*A*np.cos(k*l - frec*(t+dt) + phase)*hfact + dp = dp + amp + return [x,dx,p,dp] + diff --git a/src/Mod/Ship/simRun/Sim/initialization.py b/src/Mod/Ship/simRun/Sim/initialization.py index e89192c14..f7c58ad90 100644 --- a/src/Mod/Ship/simRun/Sim/initialization.py +++ b/src/Mod/Ship/simRun/Sim/initialization.py @@ -1,119 +1,327 @@ #*************************************************************************** -#* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * -#* * +#* * +#* 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 * +#* 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 * -#* * +#* USA * +#* * #*************************************************************************** # numpy import numpy as np +import FreeCAD grav=9.81 class simInitialization: - def __init__(self, FSmesh, waves, context=None, queue=None): - """ 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, - must be None. - @param queue OpenCL command queue. Only for compatibility, - must be None. - """ - self.context = context - 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 __init__(self, h, FSMesh, SeaMesh, waves, context=None, queue=None): + """ Constructor. + @param h Water height. + @param FSMesh Initial free surface mesh. + @param waves Considered simulation waves (A,T,phi,heading). + @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 + self.loadData(h, FSMesh, SeaMesh, 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. - @param FSmesh Initial free surface mesh. - @param waves Considered simulation waves (A,T,phi,heading). - """ - nx = len(FSmesh) - ny = len(FSmesh[0]) - nW = len(waves) - # Mesh data - p = np.ndarray((nx,ny, 3), dtype=np.float32) - n = np.ndarray((nx,ny, 3), 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 - normal = FSmesh[i][j].normal - area = FSmesh[i][j].area - p[i,j,0] = pos.x - p[i,j,1] = pos.y - p[i,j,2] = pos.z - n[i,j,0] = normal.x - n[i,j,1] = normal.y - n[i,j,2] = normal.z - a[i,j] = area - 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): - w[i,0] = waves[i][0] - w[i,1] = waves[i][1] - 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 loadData(self, h, FSMesh, SeaMesh, waves): + """ Convert data to numpy format. + @param FSMesh Initial free surface mesh. + @param waves Considered simulation waves (A,T,phi,heading). + """ + # Data will classified in four groups: + # Free surface: + # Is a key part of the simulation, so is + # separated from the rest of water involved + # elements. + # Sea: + # BEM method required a closed domain, so + # water floor and sides must be append, but + # are not a key objective of the simulation. + # Body: + # Is the main objective of the simulation. + # Waves: + # Data that is append as boundary condition. + # BEM: + # Used to solve the BEM problem and evolution. + + # -------------------------------------------- + # Free surface data + # N, Nx, Ny = Number of points in each + # direction + # pos = Positions + # vel = Velocities + # n = Normals + # area = Areas + # -------------------------------------------- + nx = len(FSMesh) + ny = len(FSMesh[0]) + p = np.ndarray((nx,ny, 3), dtype=np.float32) + V = np.zeros((nx,ny, 3), dtype=np.float32) + n = np.ndarray((nx,ny, 3), dtype=np.float32) + a = np.ndarray((nx,ny), dtype=np.float32) + x1 = np.zeros((nx,ny), dtype=np.float32) + x2 = np.zeros((nx,ny), dtype=np.float32) + x3 = np.zeros((nx,ny), dtype=np.float32) + dx1 = np.zeros((nx,ny), dtype=np.float32) + dx2 = np.zeros((nx,ny), dtype=np.float32) + dx3 = np.zeros((nx,ny), dtype=np.float32) + for i in range(0, nx): + for j in range(0, ny): + pos = FSMesh[i][j].pos + normal = FSMesh[i][j].normal + area = FSMesh[i][j].area + p[i,j,0] = pos.x + p[i,j,1] = pos.y + p[i,j,2] = pos.z + n[i,j,0] = normal.x + n[i,j,1] = normal.y + n[i,j,2] = normal.z + a[i,j] = area + self.fs = {'h': h, 'N':nx*ny, 'Nx':nx, 'Ny':ny, \ + 'pos':p, 'vel':V, 'normal':n, 'area':a, \ + 'x1':x1, 'x2':x2, 'x3':x3,\ + 'dx1':dx1, 'dx2':dx2, 'dx3':dx3} + # -------------------------------------------- + # Sea data (dictionary with components + # ['front','back','left','right','bottom']) + # N, Nx, Ny = Number of points in each + # direction + # pos = Positions + # vel = Velocities + # n = Normals + # area = Areas + # -------------------------------------------- + self.sea = {'ids':['front','back','left','right','bottom']} + N = 0 + for index in self.sea['ids']: + mesh = SeaMesh[index] + nx = len(mesh) + ny = len(mesh[0]) + p = np.ndarray((nx,ny, 3), dtype=np.float32) + V = np.zeros((nx,ny, 3), dtype=np.float32) + n = np.ndarray((nx,ny, 3), dtype=np.float32) + a = np.ndarray((nx,ny), dtype=np.float32) + for i in range(0, nx): + for j in range(0, ny): + pos = mesh[i][j].pos + normal = mesh[i][j].normal + area = mesh[i][j].area + p[i,j,0] = pos.x + p[i,j,1] = pos.y + p[i,j,2] = pos.z + n[i,j,0] = normal.x + n[i,j,1] = normal.y + n[i,j,2] = normal.z + a[i,j] = area + d = {'N':nx*ny, 'Nx':nx, 'Ny':ny, 'pos':p, 'vel':V, 'normal':n, 'area':a} + self.sea[index] = d + N = N + nx*ny + self.sea['N'] = N + self.sea['h'] = h + # -------------------------------------------- + # Body data + # N, Nx, Ny = Number of points in each + # direction + # pos = Positions + # vel = Velocities + # n = Normals + # area = Areas + # -------------------------------------------- + self.b = {'N':0, 'pos':None, 'vel':None, 'normal':None, 'area':None} + # -------------------------------------------- + # Waves data + # N = Number of waves + # data = Waves data + # -------------------------------------------- + nW = len(waves) + w = np.ndarray((nW, 4), dtype=np.float32) + for i in range(0,nW): + w[i,0] = waves[i][0] + w[i,1] = waves[i][1] + w[i,2] = waves[i][2] + w[i,3] = waves[i][3] + self.waves = {'h':h, 'N':nW, 'data':w} + # -------------------------------------------- + # BEM data + # N = nFS + nSea + nB + # A,B,dB = Linear system matrix and vectors + # p1,... = Velocity potentials (phi) for + # each RK4 step. In reallity are + # the independent term of the + # BEM linear system, so is the + # potential for the free surface, + # and the gradient projected over + # the normal along all other terms. + # dp1,... = Acceleration potentials + # (dphi/dt) for each RK4 step. + # In reallity are the + # independent term of the BEM + # linear system, so is the + # potential for the free surface, + # and the gradient projected over + # the normal along all other terms. + # Ap,Adp = BEM solution vectors, that + # contains the potential gradients + # on free surface, and the potential + # along all toher surfaces. + # -------------------------------------------- + nFS = self.fs['N'] + nSea = self.sea['N'] + nB = self.b['N'] + N = nFS + nSea + nB + A = np.zeros((N, N), dtype=np.float32) + B = np.zeros((N), dtype=np.float32) + dB = np.zeros((N), dtype=np.float32) + p1 = np.zeros((N), dtype=np.float32) + p2 = np.zeros((N), dtype=np.float32) + p3 = np.zeros((N), dtype=np.float32) + p4 = np.zeros((N), dtype=np.float32) + Ap = np.zeros((N), dtype=np.float32) + dp1 = np.zeros((N), dtype=np.float32) + dp2 = np.zeros((N), dtype=np.float32) + dp3 = np.zeros((N), dtype=np.float32) + dp4 = np.zeros((N), dtype=np.float32) + Adp = np.zeros((N), dtype=np.float32) + self.bem = {'N':N, 'A':A, 'B':B, 'dB':dB, \ + 'p1':p1, 'p2':p2, 'p3':p3, 'p4':p4, 'Ap':Ap, \ + 'dp1':dp1, 'dp2':dp2, 'dp3':dp3, 'dp4':dp4, 'Adp':Adp } + + def execute(self): + """ Compute initial conditions. """ + # -------------------------------------------- + # Free surface beach nodes. + # Beach nodes are the nodes of the free + # surface where the waves are imposed. All + # the other nodes are computed allowing non + # linear waves due to the ship interaction. + # The beach will have enough dimension to + # control at least half wave length + # -------------------------------------------- + # Get maximum wave length + wl = 0.0 + for w in self.waves['data']: + T = w[1] + wl = max(wl, 0.5 * grav / np.pi * T*T) + # Get nodes dimensions + nx = self.fs['Nx'] + ny = self.fs['Ny'] + lx = self.fs['pos'][nx-1,0][0] - self.fs['pos'][0,0][0] + ly = self.fs['pos'][0,ny-1][1] - self.fs['pos'][0,0][1] + dx = lx / nx + dy = ly / ny + # Get number of nodes involved + wnx = max(1, int(round(0.5*wl / dx))) + wny = max(1, int(round(0.5*wl / dy))) + wnx = min(wnx, nx) + wny = min(wny, ny) + self.fs['Beachx'] = wnx + self.fs['Beachy'] = wny + # -------------------------------------------- + # Free surface initial condition. + # Since RK4 scheme starts on the end of + # previous step, we only write on last + # stage value (p4 and dp4) + # -------------------------------------------- + nx = self.fs['Nx'] + ny = self.fs['Ny'] + h = self.fs['h'] + for i in range(0,nx): + for j in range(0,ny): + # Since initial values of the potencial, and this acceleration, + # depends on z, we need to compute first the positions. + self.fs['pos'][i,j][2] = 0. + for w in self.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 + pos = self.fs['pos'][i,j] + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + # hfact = np.sinh(k*(pos[2]+h)) / np.cosh(k*h) + hfact = 1.0 + amp = A*np.sin(k*l + phase)*hfact + self.fs['pos'][i,j][2] = self.fs['pos'][i,j][2] + amp + amp = - A*frec*np.cos(k*l + phase)*hfact + self.fs['vel'][i,j][2] = self.fs['vel'][i,j][2] + amp + # And now we can compute potentials. + for w in self.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 + pos = self.fs['pos'][i,j] + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + hfact = np.cosh(k*(pos[2]+h)) / np.cosh(k*h) + amp = - grav/frec*A*np.cos(k*l + phase)*hfact + self.bem['p4'][i*ny+j] = self.bem['p4'][i*ny+j] + amp + amp = - grav*A*np.sin(k*l + phase)*hfact + self.bem['dp4'][i*ny+j] = self.bem['dp4'][i*ny+j] + amp + # -------------------------------------------- + # Sea initial condition on sides. + # 1. Since RK4 scheme starts on the end of + # previous step, we only write on last + # stage value (p4 and dp4) + # 2. In the sea boundaries we are + # interested on the gradient of the + # potentials projected over the normal, + # so we really store this value. + # 3. In the floor this value is ever null. + # -------------------------------------------- + ids = ['front','back','left','right','bottom'] + i0 = self.fs['N'] + for index in ids: + sea = self.sea[index] + nx = sea['Nx'] + ny = sea['Ny'] + for i in range(0,nx): + for j in range(0,ny): + for w in self.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 + pos = sea['pos'][i,j] + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + normal = sea['normal'][i,j] + hfact = np.cosh(k*(pos[2]+h)) / np.cosh(k*h) + factor = np.dot(normal,np.array([np.cos(heading), np.sin(heading), 0.])) + amp = frec*A*np.sin(k*l + phase)*hfact + self.bem['p4'][i0 + i*ny+j] = self.bem['p4'][i*ny+j] + factor*amp + amp = - grav*A*k*np.cos(k*l + phase)*hfact + self.bem['dp4'][i0 + i*ny+j] = self.bem['dp4'][i*ny+j] + factor*amp + i0 = i0 + sea['N'] - def execute(self): - """ Compute initial conditions. """ - nx = self.fs['Nx'] - 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] - 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 - pos = self.fs['pos'][i,j] - 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 = - 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 index 4eab537bc..43ea6ed51 100644 --- a/src/Mod/Ship/simRun/Sim/matrixGen.py +++ b/src/Mod/Ship/simRun/Sim/matrixGen.py @@ -1,24 +1,24 @@ #*************************************************************************** -#* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * -#* * +#* * +#* 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 * +#* 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 * -#* * +#* USA * +#* * #*************************************************************************** # numpy @@ -27,53 +27,197 @@ 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 __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 execute(self, x, p, dp, fs, sea, bem, body): + """ Compute system matrix. + @param x Free surface z coordinates. + @param fs Free surface instance. + @param sea Sea boundary instance. + @param bem Boundary Element Method instance. + @param body Body instance. + """ + nFS = fs['N'] + nSea = sea['N'] + nB = body['N'] + n = nFS + nSea + nB + A = bem['A'] + B = bem['B'] + dB = bem['dB'] + # Free surface sources rows + nx = fs['Nx'] + ny = fs['Ny'] + for i in range(0,nx): + for j in range(0,ny): + pos = np.copy(fs['pos'][i,j]) + pos[2] = x[i,j] + # Compute G terms + fsG = self.fsG(x, pos, fs) + seaG = self.seaG(pos, sea) + # Compute H terms + fsH = self.fsH(i*ny+j, x, pos, fs) + seaH = self.seaH(i*ny+j, pos, fs, sea) + # Append terms to linear system matrix + A[i*ny+j,0:nFS] = fsG + A[i*ny+j,nFS:n] = seaH + # Set independent terms + B[i*ny+j] = np.dot(fsH, p[0:nFS]) + np.dot(seaG, p[nFS:nFS+nSea]) + dB[i*ny+j] = np.dot(fsH, dp[0:nFS]) + np.dot(seaG, dp[nFS:nFS+nSea]) + # Append body effect + # ... + # Sea sources rows + ids = ['front','back','left','right','bottom'] + count = 0 + for index in ids: + s = sea[index] + nx = s['Nx'] + ny = s['Ny'] + for i in range(0,nx): + for j in range(0,ny): + pos = np.copy(s['pos'][i,j]) + # Compute G terms + fsG = self.fsG(x, pos, fs) + seaG = self.seaG(pos, sea) + # Compute H terms + fsH = self.fsH(nFS+count, x, pos, fs) + seaH = self.seaH(nFS+count, pos, fs, sea) + # Append terms to linear system matrix + A[nFS+count, 0:nFS] = fsG + A[nFS+count, nFS:n] = seaH + # Set independent terms + B[nFS+count] = np.dot(fsH, p[0:nFS]) + np.dot(seaG, p[nFS:nFS+nSea]) + dB[nFS+count] = np.dot(fsH, dp[0:nFS]) + np.dot(seaG, dp[nFS:nFS+nSea]) + # Append body effect + # ... + count = count + 1 + # Solid sources rows + # ... + + def fsG(self, x, pos, fs): + r""" Compute free surface terms potential effect over desired position. Desingularized + sources must taken into account. + \$ G_{ij} = \sum_{j=0}^{n_{FS}-1} \log(\mathbf{r}_{ij}) \$ + @param x Free surface z coordinates. + @param pos Point to evaluate. + @param fs Free surface instance. + @return Free surface effect row. + """ + nx = fs['Nx'] + ny = 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(fs['pos'][i,j]) + source[2] = x[i,j] + area = fs['area'][i,j] + normal = fs['normal'][i,j] + source = source + np.sqrt(area)*normal + # Get union vector between points + r = pos-source + row[i*ny+j] = area * 0.5*np.log(np.dot(r,r)) + return row + + def fsH(self, index, x, pos, fs): + r""" Compute free surface terms potential gradient effect over desired position. Desingularized + sources must taken into account. + \$ H_{ij} = \sum_{j=0}^{n_{FS}-1} \frac{\mathbf{r}_{ij}}{\vert \mathbf{r}_{ij} \vert^2} \$ + When the point effect over himself is considered, -1/2 must be append. + @param index Potential point index. + @param x Free surface z coordinates. + @param pos Point to evaluate. + @param fs Free surface instance. + @return Free surface effect row. + """ + nx = fs['Nx'] + ny = 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(fs['pos'][i,j]) + source[2] = x[i,j] + area = fs['area'][i,j] + normal = fs['normal'][i,j] + source = source + np.sqrt(area)*normal + # Get union vector between points + r = pos-source + row[i*ny+j] = area * np.dot(r,normal) / np.dot(r,r) + # If effect over himslef is considered, apply the correction + if(index == i*ny+j): + row[i*ny+j] = row[i*ny+j] - 0.5 + return row + + def seaG(self, pos, sea): + r""" Compute sea boundary terms potential effect over desired position. Desingularized + sources must taken into account. + \$ G_{ij} = \sum_{j=0}^{n_{FS}-1} \log(\mathbf{r}_{ij}) \$ + @param pos Point to evaluate. + @param sea Sea boundaries instance. + @return Sea boundaries effect row. + """ + ids = ['front','back','left','right','bottom'] + count = 0 + row = np.ndarray(sea['N'], dtype=np.float32) + for index in ids: + s = sea[index] + nx = s['Nx'] + ny = s['Ny'] + for i in range(0,nx): + for j in range(0,ny): + # Get source position (desingularized) + source = np.copy(s['pos'][i,j]) + area = s['area'][i,j] + normal = s['normal'][i,j] + source = source + np.sqrt(area)*normal + # Get distance between points + r = pos-source + row[count] = area * 0.5*np.log(np.dot(r,r)) + count = count + 1 + return row + + def seaH(self, index, pos, fs, sea): + r""" Compute sea boundary terms potential gradient effect over desired position. Desingularized + sources must taken into account. + \$ H_{ij} = \sum_{j=0}^{n_{FS}-1} \frac{\mathbf{r}_{ij}}{\vert \mathbf{r}_{ij} \vert^2} \$ + When the point effect over himself is considered, -1/2 must be append. + @param index Potential point index. + @param pos Point to evaluate. + @param fs Free surface instance. + @param sea Sea boundaries instance. + @return Sea boundaries effect row. + """ + nF = fs['N'] + ids = ['front','back','left','right','bottom'] + count = 0 + row = np.ndarray(sea['N'], dtype=np.float32) + for index in ids: + s = sea[index] + nx = s['Nx'] + ny = s['Ny'] + for i in range(0,nx): + for j in range(0,ny): + # Get source position (desingularized) + source = np.copy(s['pos'][i,j]) + area = s['area'][i,j] + normal = s['normal'][i,j] + source = source + np.sqrt(area)*normal + # Get distance between points + r = pos-source + row[count] = area * np.dot(r,normal) / np.dot(r,r) + # If effect over himslef is considered, apply the correction + if(index == count+nF): + row[count] = row[count] - 0.5 + count = count + 1 + return row - 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 06773fc4e..713d196d0 100644 --- a/src/Mod/Ship/simRun/Simulation.py +++ b/src/Mod/Ship/simRun/Simulation.py @@ -51,14 +51,17 @@ class Singleton(type): class FreeCADShipSimulation(threading.Thread): __metaclass__ = Singleton - def __init__ (self, device, endTime, output, simInstance, FSmesh, waves): + def __init__ (self, device, endTime, output, simInstance, FSMesh, FSData, waves, Sea_Nx, Sea_Ny): """ 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 FSMesh Free surface mesh faces. + @param FSData Free surface data (Length, Breath, Nx, Ny). @param waves Waves parameters (A,T,phi,heading) + @param Sea_Nx Times that the free surface is virtually repeated in the x direction + @param Sea_Ny Times that the free surface is virtually repeated in the y direction """ threading.Thread.__init__(self) # Setup as stopped @@ -75,9 +78,11 @@ class FreeCADShipSimulation(threading.Thread): self.endTime = endTime self.output = output self.sim = simInstance - self.FSmesh = FSmesh + self.FSMesh = FSMesh + self.FSData = FSData self.waves = waves - + self.Sea = (Sea_Nx, Sea_Ny) + def run(self): """ Runs the simulation. """ @@ -90,36 +95,116 @@ class FreeCADShipSimulation(threading.Thread): msg = QtGui.QApplication.translate("ship_console","Initializating", None,QtGui.QApplication.UnicodeUTF8) FreeCAD.Console.PrintMessage("\t[Sim]: " + msg + "...\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 + if self.device == None: # Can't use OpenCL + init = simInitialization(self.FSMesh,self.FSData,self.waves,self.Sea,self.context,self.queue) + matGen = simMatrixGen(self.context,self.queue) + solver = simBEMSolver(self.context,self.queue) + evol = simEvolution(self.context,self.queue) + else: + init = simInitialization_cl(self.FSMesh,self.FSData,self.waves,self.Sea,self.context,self.queue) + matGen = simMatrixGen_cl(self.context,self.queue) + solver = simBEMSolver_cl(self.context,self.queue) + evol = simEvolution_cl(self.context,self.queue) + FS = init.fs + sea = init.sea + body = init.b + waves = init.waves + BEM = init.bem + dt = init.dt self.t = 0.0 self.FS = FS - nx = FS['Nx'] - ny = FS['Ny'] + nx = FS['Nx'] + ny = FS['Ny'] msg = QtGui.QApplication.translate("ship_console","Iterating", None,QtGui.QApplication.UnicodeUTF8) FreeCAD.Console.PrintMessage("\t[Sim]: " + msg + "...\n") while self.active and self.t < self.endTime: - msg = QtGui.QApplication.translate("ship_console","Generating linear system matrix", - None,QtGui.QApplication.UnicodeUTF8) - FreeCAD.Console.PrintMessage("\t\t[Sim]: " + msg + "...\n") - matGen.execute(FS, A) - msg = QtGui.QApplication.translate("ship_console","Solving linear systems", - None,QtGui.QApplication.UnicodeUTF8) - FreeCAD.Console.PrintMessage("\t\t[Sim]: " + msg + "...\n") - solver.execute(FS, A) - msg = QtGui.QApplication.translate("ship_console","Time integrating", - None,QtGui.QApplication.UnicodeUTF8) - FreeCAD.Console.PrintMessage("\t\t[Sim]: " + msg + "...\n") - fsEvol.execute(FS, waves, dt, self.t) + # Simple Euler method + FreeCAD.Console.PrintMessage("\t\t\t[Sim]: Generating matrix...\n") + matGen.execute(FS, waves, sea, BEM, body, self.t) + FreeCAD.Console.PrintMessage("\t\t\t[Sim]: Solving linear system matrix...\n") + solver.execute(BEM) + FreeCAD.Console.PrintMessage("\t\t\t[Sim]: Integrating...\n") + # evol.execute(FS, BEM, waves, self.t, dt) + + + # -------------------------------------------------------- + # Debugging + # -------------------------------------------------------- + evol.BC(FS, BEM, waves, self.t) + f = open("%.4f.dat" % (self.t), 'w') + for i in range(0,FS['Nx']): + for j in range(0, FS['Ny']): + # Compute analitical solution + z = 0.0 + vz = 0.0 + p = 0.0 + vp = 0.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 + pos = FS['pos'][i,j] + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + amp = A*np.sin(k*l - frec*self.t + phase) + z = z + amp + amp = - A*frec*np.cos(k*l - frec*self.t + phase) + vz = vz + amp + 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 + pos = FS['pos'][i,j] + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + amp = - A*frec/k*np.cos(k*l - frec*self.t + phase)*np.exp(k*z) + p = p + amp + amp = - A*9.81*np.sin(k*l - frec*self.t + phase)*np.exp(k*z) + vp = vp + amp + + """ + z = 0. + vz = 0. + p = 0. + vp = 0. + # We can do phi = Green's function + dx = FS['pos'][i,j][0] + dy = FS['pos'][i,j][1] + dz = 15.0 # An arbitrary value > 0 + p = 1. / (4. * np.pi * np.sqrt(dx*dx + dy*dy + dz*dz)) + vz = - dz / (4. * np.pi * (dx*dx + dy*dy + dz*dz)**(1.5)) + """ + + # write coordinates + f.write("%g %g " % (FS['pos'][i,j,0],FS['pos'][i,j,1])) + # write computed wave and velocity + f.write("%g %g " % (FS['pos'][i,j,2],FS['vel'][i,j,2])) + # write computed potential and time variation rate + # f.write("%g %g " % (BEM['p'][i*FS['Ny']+j],BEM['dpdt'][i*FS['Ny']+j])) + f.write("%g %g " % (BEM['p'][i*FS['Ny']+j],0.)) + # write analytic wave and velocity + f.write("%g %g " % (z,vz)) + # write analytic potential and time variation rate + # f.write("%g %g\n" % (p,vp)) + f.write("%g %g\n" % (p,0.)) + f.write("\n") + f.close() + evol.Integrate(FS, BEM, waves, self.t, dt) + # -------------------------------------------------------- + # Debugging + # -------------------------------------------------------- + + self.t = self.t + dt FreeCAD.Console.PrintMessage('\t[Sim]: 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 628347458..bf9996484 100644 --- a/src/Mod/Ship/simRun/TaskPanel.py +++ b/src/Mod/Ship/simRun/TaskPanel.py @@ -61,18 +61,22 @@ class TaskPanel: device = d count = count + 1 # Get free surfaces data - FSMesh = SimInstance.FSMesh(self.sim) - wData = self.sim.Waves - wDir = self.sim.Waves_Dir - waves = [] + FSMesh = SimInstance.FSMesh(self.sim) + FSData = (self.sim.L,self.sim.B,self.sim.FS_Nx,self.sim.FS_Ny) + wData = self.sim.Waves + wDir = self.sim.Waves_Dir + waves = [] for i in range(0,len(wData)): waves.append([wData[i].x, wData[i].y, wData[i].z, wDir[i]]) + SeaNx = self.sim.Sea_Nx + SeaNy = self.sim.Sea_Ny msg = QtGui.QApplication.translate("ship_console","Launching simulation", None,QtGui.QApplication.UnicodeUTF8) App.Console.PrintMessage(msg + "...\n") # Build simulation thread - simulator = Sim(device, endTime, output, self.sim, FSMesh, waves) - simulator.start() + simulator = Sim(device, endTime, output, self.sim, FSMesh, FSData, waves, SeaNx, SeaNy) + simulator.start() # Activate me for final release + # simulator.run() # Activate me for development (i will show python fails) msg = QtGui.QApplication.translate("ship_console","Done", None,QtGui.QApplication.UnicodeUTF8) App.Console.PrintMessage(msg + "!\n") diff --git a/src/Mod/Ship/simRun/clSim/BEMsolver.py b/src/Mod/Ship/simRun/clSim/BEMsolver.py new file mode 100644 index 000000000..42e54a89a --- /dev/null +++ b/src/Mod/Ship/simRun/clSim/BEMsolver.py @@ -0,0 +1,61 @@ +#*************************************************************************** +#* * +#* 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 +from bem_jacobi_cl import jacobi +from bem_minres_cl import minres +from bem_lsqr_cl import lsqr +import FreeCAD + +grav=9.81 + +class simBEMSolver_cl: + def __init__(self, context=None, queue=None): + """ Constructor. + @param context OpenCL context where apply. + @param queue OpenCL command queue. + """ + self.context = context + self.queue = queue + self.solver = lsqr(context, queue) + + def execute(self, bem): + """ Compute potential unknow data (gradients for free surface, and + potentials for the other ones). + @param bem Boundary Element Method instance. + """ + """ + [bem['gradp'], r, iters] = self.solver.solve(bem['A'], bem['B'], bem['gradp']) + if(iters >= 300): + FreeCAD.Console.PrintError("\t\t[Sim]: Solving velocity potentials.\n") + FreeCAD.Console.PrintError("\t\t\tSolutions seems don't convergs after 300 iterations (%g residual)\n" % (r)) + FreeCAD.Console.PrintMessage((r,iters)) + FreeCAD.Console.PrintMessage("\n") + """ + import scipy.linalg as la + [bem['gradp'], residues, rank, s] = la.lstsq(bem['A'], bem['B']) + if(rank < bem['N']): + FreeCAD.Console.PrintError("\t\t[Sim]: Solving velocity potentials.\n") + FreeCAD.Console.PrintError("\t\t\tEffective rank of linear system matrix is {0} (N = {1})\n".format(rank, bem['N'])) + diff --git a/src/Mod/Ship/simRun/clSim/__init__.py b/src/Mod/Ship/simRun/clSim/__init__.py index 2fcb8e495..6a185fde4 100644 --- a/src/Mod/Ship/simRun/clSim/__init__.py +++ b/src/Mod/Ship/simRun/clSim/__init__.py @@ -21,4 +21,7 @@ #* * #*************************************************************************** -import initialization, Utils \ No newline at end of file +from initialization import * +from matrixGen import * +from BEMsolver import * +from evolution import * diff --git a/src/Mod/Ship/simRun/clSim/bem_jacobi_cl.py b/src/Mod/Ship/simRun/clSim/bem_jacobi_cl.py new file mode 100644 index 000000000..368574f22 --- /dev/null +++ b/src/Mod/Ship/simRun/clSim/bem_jacobi_cl.py @@ -0,0 +1,155 @@ +#*************************************************************************** +#* * +#* 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 + +# pyOpenCL +import pyopencl as cl +from pyopencl.reduction import ReductionKernel +import pyopencl.array as cl_array +import clUtils + +import FreeCAD +grav=9.81 + +class jacobi: + def __init__(self, context, queue): + """ Constructor. + @param context OpenCL context where apply. + @param queue OpenCL command queue. + """ + self.context = context + self.queue = queue + self.program = clUtils.loadProgram(context, clUtils.path() + "/jacobi.cl") + # Create OpenCL objects as null objects, that we will generate + # at the first iteration + self.A = None + self.B = None + self.X0 = None + self.X = None + self.x = None + # Create dot operator + self.dot = ReductionKernel(context, np.float32, neutral="0", + reduce_expr="a+b", map_expr="x[i]*y[i]", + arguments="__global float *x, __global float *y") + + def solve(self, A, B, x0=None, tol=10e-6, iters=300, w=1.0): + r""" Solve linear system of equations by a Jacobi + iterative method. + @param A Linear system matrix. + @param B Linear system independent term. + @param x0 Initial aproximation of the solution. + @param tol Relative error tolerance: \n + \$ \vert\vert B - A \, x \vert \vert_\infty / + \vert\vert B \vert \vert_\infty \$ + @param iters Maximum number of iterations. + @param w Relaxation factor + """ + # Create/set OpenCL buffers + w = np.float32(w) + self.setBuffers(A,B,x0) + # Get dimensions for OpenCL execution + n = np.uint32(len(B)) + gSize = (clUtils.globalSize(n),) + # Get a norm to can compare later for valid result + B_cl = cl_array.to_device(self.context,self.queue,B) + bnorm2 = self.dot(B_cl,B_cl).get() + w = w / bnorm2 + FreeCAD.Console.PrintMessage(bnorm2) + FreeCAD.Console.PrintMessage("\n") + rnorm2 = 0. + # Iterate while the result converges or maximum number + # of iterations is reached. + for i in range(0,iters): + kernelargs = (self.A, + self.B, + self.X0, + self.X, + n) + # Test if the final result has been reached + self.program.r(self.queue, gSize, None, *(kernelargs)) + cl.enqueue_read_buffer(self.queue, self.X, self.x).wait() + x_cl = cl_array.to_device(self.context,self.queue,self.x) + rnorm2 = self.dot(x_cl,x_cl).get() + FreeCAD.Console.PrintMessage("\t") + FreeCAD.Console.PrintMessage(rnorm2) + FreeCAD.Console.PrintMessage("\n") + if np.sqrt(rnorm2 / bnorm2) <= tol: + break + # Iterate + kernelargs = (self.A, + self.B, + self.X0, + self.X, + w, + n) + self.program.jacobi(self.queue, gSize, None, *(kernelargs)) + kernelargs = (self.A, + self.B, + self.X, + self.X0, + w, + n) + self.program.jacobi(self.queue, gSize, None, *(kernelargs)) + # Return result computed + cl.enqueue_read_buffer(self.queue, self.X0, self.x).wait() + return (np.copy(self.x), np.sqrt(rnorm2 / bnorm2), i) + + def setBuffers(self, A,B,x0): + """ Create/set OpenCL required buffers. + @param A Linear system matrix. + @param B Independent linear term. + @param x0 Initial solution estimator. + """ + # Get dimensions + shape = np.shape(A) + if len(shape) != 2: + raise ValueError, 'Matrix A must be 2 dimensional array' + if shape[0] != shape[1]: + raise ValueError, 'Square linear system matrix expected' + if len(B) != shape[0]: + raise ValueError, 'Matrix and independet term dimensions does not match' + n = len(B) + # Set x0 if not provided + if x0 != None: + if len(x0) != n: + raise ValueError, 'Initial solution estimator length does not match with linear system dimensions' + if x0 == None: + x0 = B + # Create OpenCL objects if not already generated + if not self.A: + mf = cl.mem_flags + self.A = cl.Buffer( self.context, mf.READ_ONLY, size = n*n * np.dtype('float32').itemsize ) + self.B = cl.Buffer( self.context, mf.READ_ONLY, size = n * np.dtype('float32').itemsize ) + self.X0 = cl.Buffer( self.context, mf.READ_WRITE, size = n * np.dtype('float32').itemsize ) + self.X = cl.Buffer( self.context, mf.READ_WRITE, size = n * np.dtype('float32').itemsize ) + self.x = np.zeros((n), dtype=np.float32) + # Transfer data to buffers + events = [] + events.append(cl.enqueue_write_buffer(self.queue, self.A, A.reshape((n*n)) )) + events.append(cl.enqueue_write_buffer(self.queue, self.B, B)) + events.append(cl.enqueue_write_buffer(self.queue, self.X0, x0)) + for e in events: + e.wait() + diff --git a/src/Mod/Ship/simRun/clSim/bem_lsqr_cl.py b/src/Mod/Ship/simRun/clSim/bem_lsqr_cl.py new file mode 100644 index 000000000..39811a390 --- /dev/null +++ b/src/Mod/Ship/simRun/clSim/bem_lsqr_cl.py @@ -0,0 +1,229 @@ +#*************************************************************************** +#* * +#* 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 + +# pyOpenCL +import pyopencl as cl +from pyopencl.reduction import ReductionKernel +from pyopencl.elementwise import ElementwiseKernel +import pyopencl.array as cl_array +import clUtils + +import FreeCAD +grav=9.81 + +class lsqr: + def __init__(self, context, queue): + """ Constructor. + @param context OpenCL context where apply. + @param queue OpenCL command queue. + """ + self.context = context + self.queue = queue + self.program = clUtils.loadProgram(context, clUtils.path() + "/lsqr.cl") + # Create OpenCL objects as null objects, that we will generate + # at the first iteration + self.A = None + self.B = None + self.X0 = None + self.X = None + self.R = None + # Create dot operator + self.dot = ReductionKernel(context, np.float32, neutral="0", + reduce_expr="a+b", map_expr="x[i]*y[i]", + arguments="__global float *x, __global float *y") + self.dot_c_vec = ElementwiseKernel(context, + "float c, float *v", + "v[i] *= c") + self.copy_vec = ElementwiseKernel(context, + "float* out, float *in", + "out[i] = in[i]") + self.linear_comb = ElementwiseKernel(context, + "float* z," + "float a, float *x, " + "float b, float *y", + "z[i] = a*x[i] + b*y[i]") + self.prod = ElementwiseKernel(context, + "float* z," + "float *x, float *y", + "z[i] = x[i]*y[i]") + + def solve(self, A, B, x0=None, tol=10e-6, iters=300): + r""" Solve linear system of equations by a Jacobi + iterative method. + @param A Linear system matrix. + @param B Linear system independent term. + @param x0 Initial aproximation of the solution. + @param tol Relative error tolerance: \n + \$ \vert\vert B - A \, x \vert \vert_\infty / + \vert\vert B \vert \vert_\infty \$ + @param iters Maximum number of iterations. + """ + # Create/set OpenCL buffers + self.setBuffers(A,B,x0) + # Get dimensions for OpenCL execution + n = np.uint32(len(B)) + gSize = (clUtils.globalSize(n),) + # Preconditionate matrix + self.precondition(n) + # Get a norm to can compare later for valid result + bnorm = np.sqrt(self.dot(self.b,self.b).get()) + FreeCAD.Console.PrintMessage(bnorm) + FreeCAD.Console.PrintMessage("\n") + # Initialize the problem + beta = bnorm + self.dot_c_vec(1.0/beta, self.u) + kernelargs = (self.A,self.u.data,self.v.data,n) + self.program.dot_matT_vec(self.queue, gSize, None, *(kernelargs)) + alpha = np.sqrt(self.dot(self.v,self.v).get()) + self.dot_c_vec(1.0/alpha, self.v) + self.copy_vec(self.w, self.v) + rhobar = alpha + phibar = beta + # Iterate while the result converges or maximum number + # of iterations is reached. + for i in range(0,iters): + # Compute residues + kernelargs = (self.A, + self.b.data, + self.x.data, + self.r.data, + n) + self.program.r(self.queue, gSize, None, *(kernelargs)) + rnorm = np.sqrt(self.dot(self.r,self.r).get()) + FreeCAD.Console.PrintMessage("\t") + FreeCAD.Console.PrintMessage(rnorm) + FreeCAD.Console.PrintMessage("\n") + # Test if the final result has been reached + if rnorm / bnorm <= tol: + break + # Compute next alpha, beta, u, v + kernelargs = (self.A,self.u.data,self.v.data,self.u.data,alpha,n) + self.program.u(self.queue, gSize, None, *(kernelargs)) + beta = np.sqrt(self.dot(self.u,self.u).get()) + FreeCAD.Console.PrintMessage("\t beta=") + FreeCAD.Console.PrintMessage(beta) + FreeCAD.Console.PrintMessage("\n") + self.dot_c_vec(1.0/beta, self.u) + kernelargs = (self.A,self.u.data,self.v.data,self.v.data,beta,n) + self.program.v(self.queue, gSize, None, *(kernelargs)) + alpha = np.sqrt(self.dot(self.v,self.v).get()) + FreeCAD.Console.PrintMessage("\t alpha=") + FreeCAD.Console.PrintMessage(alpha) + FreeCAD.Console.PrintMessage("\n") + self.dot_c_vec(1.0/alpha, self.v) + # Apply the orthogonal transformation + rho = np.sqrt(rhobar*rhobar + beta*beta) + c = rhobar/rho + s = beta*rho + theta = s*alpha + rhobar = -c*alpha + phi = c*phibar + phibar = s*phibar + # Update x and w + self.linear_comb(self.x, 1, self.x, phi/rho, self.w) + self.linear_comb(self.w, 1, self.v, theta/rho, self.w) + # Correct returned result due to the precoditioning + self.prod(self.x, self.xf, self.x) + # Return result computed + x = np.zeros((n), dtype=np.float32) + cl.enqueue_read_buffer(self.queue, self.x.data, x).wait() + return (x, rnorm / bnorm, i) + + def setBuffers(self, A,B,x0): + """ Create/set OpenCL required buffers. + @param A Linear system matrix. + @param B Independent linear term. + @param x0 Initial solution estimator. + """ + # Get dimensions + shape = np.shape(A) + if len(shape) != 2: + raise ValueError, 'Matrix A must be 2 dimensional array' + if shape[0] != shape[1]: + raise ValueError, 'Square linear system matrix expected' + if len(B) != shape[0]: + raise ValueError, 'Matrix and independet term dimensions does not match' + n = len(B) + # Set x0 if not provided + if x0 != None: + if len(x0) != n: + raise ValueError, 'Initial solution estimator length does not match with linear system dimensions' + if x0 == None: + x0 = B + # Create OpenCL objects if not already generated + if not self.A: + mf = cl.mem_flags + self.A = cl.Buffer( self.context, mf.READ_WRITE, size = n*n * np.dtype('float32').itemsize ) + self.b = cl_array.zeros(self.context,self.queue, (n), np.float32) + self.x = cl_array.zeros(self.context,self.queue, (n), np.float32) + self.xf = cl_array.zeros(self.context,self.queue, (n), np.float32) + self.r = cl_array.zeros(self.context,self.queue, (n), np.float32) + self.u = cl_array.zeros(self.context,self.queue, (n), np.float32) + self.v = cl_array.zeros(self.context,self.queue, (n), np.float32) + self.w = cl_array.zeros(self.context,self.queue, (n), np.float32) + # Transfer data to buffers + events = [] + events.append(cl.enqueue_write_buffer(self.queue, self.A, A.reshape((n*n)) )) + self.b.set(B) + self.x.set(x0) + self.u.set(B) + for e in events: + e.wait() + + def precondition(self, n): + """ Preconditionate matrix, ensuring that all linear system + matrix columns has an acceptable norm. Of course, final + solution vector must be corrected conveniently. + @param n Linear system dimension. + """ + gSize = (clUtils.globalSize(n),) + xf = np.ones((n), dtype=np.float32) + for i in range(0,n): + col = np.uint32(i) + # Compute column norm + # We can use v as column vector because has not been used yet + kernelargs = (self.A, + self.v.data, + col, + n) + self.program.column(self.queue, gSize, None, *(kernelargs)) + norm = np.sqrt(self.dot(self.v,self.v).get()) + FreeCAD.Console.PrintMessage("col ") + FreeCAD.Console.PrintMessage(i) + FreeCAD.Console.PrintMessage(", norm=") + FreeCAD.Console.PrintMessage(norm) + FreeCAD.Console.PrintMessage("\n") + if norm < 1.0: + continue + fact = np.float32(1.0/norm) + xf[i] = fact + kernelargs = (self.A, + fact, + col, + n) + self.program.prod_c_column(self.queue, gSize, None, *(kernelargs)) + self.x.set(xf) + diff --git a/src/Mod/Ship/simRun/clSim/bem_minres_cl.py b/src/Mod/Ship/simRun/clSim/bem_minres_cl.py new file mode 100644 index 000000000..51e82d585 --- /dev/null +++ b/src/Mod/Ship/simRun/clSim/bem_minres_cl.py @@ -0,0 +1,157 @@ +#*************************************************************************** +#* * +#* 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 + +# pyOpenCL +import pyopencl as cl +from pyopencl.reduction import ReductionKernel +import pyopencl.array as cl_array +import clUtils + +import FreeCAD +grav=9.81 + +class minres: + def __init__(self, context, queue): + """ Constructor. + @param context OpenCL context where apply. + @param queue OpenCL command queue. + """ + self.context = context + self.queue = queue + self.program = clUtils.loadProgram(context, clUtils.path() + "/minres.cl") + # Create OpenCL objects as null objects, that we will generate + # at the first iteration + self.A = None + self.B = None + self.X0 = None + self.X = None + self.R = None + # Create dot operator + self.dot = ReductionKernel(context, np.float32, neutral="0", + reduce_expr="a+b", map_expr="x[i]*y[i]", + arguments="__global float *x, __global float *y") + + def solve(self, A, B, x0=None, tol=10e-6, iters=300): + r""" Solve linear system of equations by a Jacobi + iterative method. + @param A Linear system matrix. + @param B Linear system independent term. + @param x0 Initial aproximation of the solution. + @param tol Relative error tolerance: \n + \$ \vert\vert B - A \, x \vert \vert_\infty / + \vert\vert B \vert \vert_\infty \$ + @param iters Maximum number of iterations. + """ + # Create/set OpenCL buffers + self.setBuffers(A,B,x0) + # Get dimensions for OpenCL execution + n = np.uint32(len(B)) + gSize = (clUtils.globalSize(n),) + # Get a norm to can compare later for valid result + B_cl = cl_array.to_device(self.context,self.queue,B) + bnorm2 = self.dot(B_cl,B_cl).get() + FreeCAD.Console.PrintMessage(bnorm2) + FreeCAD.Console.PrintMessage("\n") + # Iterate while the result converges or maximum number + # of iterations is reached. + for i in range(0,iters): + # Compute residues + kernelargs = (self.A, + self.B, + self.X0, + self.R.data, + n) + # Test if the final result has been reached + self.program.r(self.queue, gSize, None, *(kernelargs)) + rnorm2 = self.dot(self.R,self.R).get() + FreeCAD.Console.PrintMessage("\t") + FreeCAD.Console.PrintMessage(rnorm2) + FreeCAD.Console.PrintMessage("\n") + if np.sqrt(rnorm2 / bnorm2) <= tol: + break + # Iterate + kernelargs = (self.A, + self.R.data, + self.AR.data, + n) + self.program.dot_mat_vec(self.queue, gSize, None, *(kernelargs)) + AR_R = self.dot(self.AR,self.R).get() + AR_AR = self.dot(self.AR,self.AR).get() + kernelargs = (self.A, + self.R.data, + self.X, + self.X0, + AR_R, + AR_AR, + n) + self.program.minres(self.queue, gSize, None, *(kernelargs)) + # Swap variables + swap = self.X + self.X = self.X0 + self.X0 = swap + # Return result computed + x = np.zeros((n), dtype=np.float32) + cl.enqueue_read_buffer(self.queue, self.X0, x).wait() + return (x, np.sqrt(rnorm2 / bnorm2), i) + + def setBuffers(self, A,B,x0): + """ Create/set OpenCL required buffers. + @param A Linear system matrix. + @param B Independent linear term. + @param x0 Initial solution estimator. + """ + # Get dimensions + shape = np.shape(A) + if len(shape) != 2: + raise ValueError, 'Matrix A must be 2 dimensional array' + if shape[0] != shape[1]: + raise ValueError, 'Square linear system matrix expected' + if len(B) != shape[0]: + raise ValueError, 'Matrix and independet term dimensions does not match' + n = len(B) + # Set x0 if not provided + if x0 != None: + if len(x0) != n: + raise ValueError, 'Initial solution estimator length does not match with linear system dimensions' + if x0 == None: + x0 = B + # Create OpenCL objects if not already generated + if not self.A: + mf = cl.mem_flags + self.A = cl.Buffer( self.context, mf.READ_ONLY, size = n*n * np.dtype('float32').itemsize ) + self.B = cl.Buffer( self.context, mf.READ_ONLY, size = n * np.dtype('float32').itemsize ) + self.X0 = cl.Buffer( self.context, mf.READ_WRITE, size = n * np.dtype('float32').itemsize ) + self.X = cl.Buffer( self.context, mf.READ_WRITE, size = n * np.dtype('float32').itemsize ) + self.R = cl_array.zeros(self.context,self.queue, (n), np.float32) + self.AR = cl_array.zeros(self.context,self.queue, (n), np.float32) + # Transfer data to buffers + events = [] + events.append(cl.enqueue_write_buffer(self.queue, self.A, A.reshape((n*n)) )) + events.append(cl.enqueue_write_buffer(self.queue, self.B, B)) + events.append(cl.enqueue_write_buffer(self.queue, self.X0, x0)) + for e in events: + e.wait() + diff --git a/src/Mod/Ship/simRun/clSim/clUtils.py b/src/Mod/Ship/simRun/clSim/clUtils.py new file mode 100644 index 000000000..676a23019 --- /dev/null +++ b/src/Mod/Ship/simRun/clSim/clUtils.py @@ -0,0 +1,58 @@ +#*************************************************************************** +#* * +#* 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 +from shipUtils import Paths + +# pyOpenCL +import pyopencl as cl +import numpy as np + +# Standard +import math + +def loadProgram(context, file): + """ Loads a file and comnpile it. + @param context OpenCL context where apply. + @param file File to load and compile. + @return Ready to use OpenCL program. + """ + f = open(file, 'r') + str = "".join(f.readlines()) + return cl.Program(context, str).build() + +def path(): + """ Gets the OpenCL kernels path + @return OpenCL kernels path + """ + path = Paths.modulePath() + "/resources/opencl" + return path + +def globalSize(n): + """ Compute global size from amount of data. + @param n Amount of data. + @return global size. + """ + localSize = 256.0 + return int(math.ceil(n/localSize)*localSize) + diff --git a/src/Mod/Ship/simRun/clSim/evolution.py b/src/Mod/Ship/simRun/clSim/evolution.py new file mode 100644 index 000000000..4f62ba6fc --- /dev/null +++ b/src/Mod/Ship/simRun/clSim/evolution.py @@ -0,0 +1,258 @@ +#*************************************************************************** +#* * +#* 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 +import FreeCAD + +grav=9.81 + +class simEvolution_cl: + 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, bem, waves, t, dt): + """ Compute the variables unknow for the next time step. + @param fs Free surface instance. + @param bem Boundary elements method instance. + @param waves Waves instance. + @param t Simulation time. + @param dt Time step. + """ + self.BC(fs,bem,waves, t) + self.Integrate(fs,bem,waves, t,dt) + + def BC(self, fs, bem, waves, t): + """ Apply the boundary conditions to compute time variation rate + of the unknow variables. + @param fs Free surface instance. + @param bem Boundary elements method instance. + @param waves Waves instance. + @param t Simulation time. + """ + nx = fs['Nx'] + ny = fs['Ny'] + nFS = nx*ny + for i in range(0,nx): + for j in range(0,ny): + gradp = np.copy(bem['gradp'][i*ny+j]) + z = fs['pos'][i,j,2] + bem['dpdt'][i*ny+j] = - 0.5 * gradp**2.0 - 9.81*z + fs['vel'][i,j,2] = gradp + # Since the inverse method returns significant errors near + # to the free surface borders, we will modify 3 area + # elements of the border such that the last one will be + # exactly the analytic solution. Also we will use it as + # numerical beach in order to disipate waves generated + # inside the domain (that will be refelceted otherwise) + # 1.- Corners + for i in range(0,4)+range(nx-4,nx): + if i in range(0,4): + fx = 1. - i/4. + else: + fx = (i - nx + 5) / 4. + for j in range(0,4)+range(ny-4,ny): + if j in range(0,4): + fy = 1. - j/4. + else: + fy = (j - ny + 5) / 4. + factor = max(fx,fy) + pos = fs['pos'][i,j] + dpdt = 0. + vel = 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*9.81*np.sin(k*l - frec*t + phase)*np.exp(k*pos[2]) + dpdt = dpdt + amp + amp = - A*frec*np.cos(k*l - frec*t + phase) + vel = vel + amp + bem['dpdt'][i*ny+j] = factor*dpdt + (1.-factor)*bem['dpdt'][i*ny+j] + fs['vel'][i,j,2] = factor*vel + (1.-factor)*fs['vel'][i,j,2] + # 2.- rows + for i in range(0,4)+range(nx-4,nx): + if i in range(0,4): + factor = 1. - i/4. + else: + factor = (i - nx + 5) / 4. + for j in range(4, ny-4): + pos = fs['pos'][i,j] + dpdt = 0. + vel = 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*9.81*np.sin(k*l - frec*t + phase)*np.exp(k*pos[2]) + dpdt = dpdt + amp + amp = - A*frec*np.cos(k*l - frec*t + phase) + vel = vel + amp + bem['dpdt'][i*ny+j] = factor*dpdt + (1.-factor)*bem['dpdt'][i*ny+j] + fs['vel'][i,j,2] = factor*vel + (1.-factor)*fs['vel'][i,j,2] + # 3.- columns + for j in range(0,4)+range(ny-4,ny): + if j in range(0,4): + factor = 1. - j/4. + else: + factor = (j - ny + 5) / 4. + for i in range(4, nx-4): + pos = fs['pos'][i,j] + dpdt = 0. + vel = 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*9.81*np.sin(k*l - frec*t + phase)*np.exp(k*pos[2]) + dpdt = dpdt + amp + amp = - A*frec*np.cos(k*l - frec*t + phase) + vel = vel + amp + bem['dpdt'][i*ny+j] = factor*dpdt + (1.-factor)*bem['dpdt'][i*ny+j] + fs['vel'][i,j,2] = factor*vel + (1.-factor)*fs['vel'][i,j,2] + + def Integrate(self, fs, bem, waves, t, dt): + """ Perform time integration of the unknow variables. + @param fs Free surface instance. + @param bem Boundary elements method instance. + @param waves Waves instance. + @param t Simulation time. + @param dt Time step. + """ + nx = fs['Nx'] + ny = fs['Ny'] + nFS = nx*ny + for i in range(0,nx): + for j in range(0,ny): + bem['p'][i*ny+j] = bem['p'][i*ny+j] + dt * bem['dpdt'][i*ny+j] + fs['pos'][i,j,2] = fs['pos'][i,j,2] + dt * fs['vel'][i,j,2] + # Since the inverse method returns significant errors near + # to the free surface borders, we will modify 3 area + # elements of the border such that the last one will be + # exactly the analytic solution. Also we will use it as + # numerical beach in order to disipate waves generated + # inside the domain (that will be refelceted otherwise) + # 1.- Corners + for i in range(0,4)+range(nx-4,nx): + if i in range(0,4): + fx = 1. - i/4. + else: + fx = (i - nx + 5) / 4. + for j in range(0,4)+range(ny-4,ny): + if j in range(0,4): + fy = 1. - j/4. + else: + fy = (j - ny + 5) / 4. + factor = max(fx,fy) + pos = fs['pos'][i,j] + phi = 0. + z = 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*frec/k*np.cos(k*l - frec*(t+dt) + phase)*np.exp(k*pos[2]) + phi = phi + amp + amp = A*np.sin(k*l - frec*(t+dt) + phase) + z = z + amp + bem['p'][i*ny+j] = factor*phi + (1.-factor)*bem['p'][i*ny+j] + fs['pos'][i,j,2] = factor*z + (1.-factor)*fs['pos'][i,j,2] + # 2.- rows + for i in range(0,4)+range(nx-4,nx): + if i in range(0,4): + factor = 1. - i/4. + else: + factor = (i - nx + 5) / 4. + for j in range(4, ny-4): + pos = fs['pos'][i,j] + phi = 0. + z = 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*frec/k*np.cos(k*l - frec*(t+dt) + phase)*np.exp(k*pos[2]) + phi = phi + amp + amp = A*np.sin(k*l - frec*(t+dt) + phase) + z = z + amp + bem['p'][i*ny+j] = factor*phi + (1.-factor)*bem['p'][i*ny+j] + fs['pos'][i,j,2] = factor*z + (1.-factor)*fs['pos'][i,j,2] + # 3.- columns + for j in range(0,4)+range(ny-4,ny): + if j in range(0,4): + factor = 1. - j/4. + else: + factor = (j - ny + 5) / 4. + for i in range(4, nx-4): + pos = fs['pos'][i,j] + phi = 0. + z = 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*frec/k*np.cos(k*l - frec*(t+dt) + phase)*np.exp(k*pos[2]) + phi = phi + amp + amp = A*np.sin(k*l - frec*(t+dt) + phase) + z = z + amp + bem['p'][i*ny+j] = factor*phi + (1.-factor)*bem['p'][i*ny+j] + fs['pos'][i,j,2] = factor*z + (1.-factor)*fs['pos'][i,j,2] + + diff --git a/src/Mod/Ship/simRun/clSim/initialization.py b/src/Mod/Ship/simRun/clSim/initialization.py index 5e4f30417..02b1c1661 100644 --- a/src/Mod/Ship/simRun/clSim/initialization.py +++ b/src/Mod/Ship/simRun/clSim/initialization.py @@ -1,113 +1,229 @@ #*************************************************************************** -#* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * -#* * +#* * +#* 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 * +#* 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 * -#* * +#* USA * +#* * #*************************************************************************** -# Simulation stuff -from Utils import * - -# pyOpenCL -import pyopencl as cl +# numpy import numpy as np +import FreeCAD -class perform: - def __init__(self, FSmesh, waves, context, queue): - """ Constructor, includes program loading. - @param FSmesh Initial free surface mesh. - @param waves Considered simulation waves (A,T,phi,heading). - @param context OpenCL context where apply. - @param queue OpenCL command queue. - """ - self.context = context - self.queue = queue - self.program = loadProgram(context, clPath() + "/simInit.cl") - self.loadData(FSmesh, waves) - self.execute() +grav=9.81 + +class simInitialization_cl: + def __init__(self, FSMesh, FSData, waves, Sea, context=None, queue=None): + """ Constructor. + @param FSMesh Initial free surface mesh. + @param FSData Dimensions data of the free surface mesh (L,B,Nx,Ny) + @param waves Considered simulation waves (A,T,phi,heading). + @param Sea Tuple with the number of free surfaces that must be repeated in each direction. + @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 + self.loadData(FSMesh, FSData, waves, Sea) + 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, FSData, waves, Sea): + """ Convert data to numpy format. + @param FSMesh Initial free surface mesh. + @param FSData Dimensions data of the free surface mesh (L,B,Nx,Ny) + @param waves Considered simulation waves (A,T,phi,heading). + @param Sea Tuple with the number of free surfaces that must be repeated in each direction. + """ + # Data will classified in four groups: + # Free surface: + # Is a key part of the simulation, so is + # separated from the rest of water involved + # elements. + # Sea: + # BEM method requires to artificially extend + # the free surface in order to send the bounds + # Inlet, Outlet, Left and Side to the infinite. + # Here is specified how many time must be + # repeated the free surface in order to get + # virtually infinite far bounds. + # Body: + # Is the main objective of the simulation. + # Waves: + # Data that is append as boundary condition. + # BEM: + # Used to solve the BEM problem and evolution. + + # -------------------------------------------- + # Free surface data + # N, Nx, Ny = Number of points in each + # direction + # pos = Positions + # vel = Velocities + # n = Normals + # area = Areas + # -------------------------------------------- + nx = len(FSMesh) + ny = len(FSMesh[0]) + L = FSData[0] + B = FSData[1] + dx = L/nx + dy = B/ny + p = np.zeros((nx,ny, 4), dtype=np.float32) + V = np.zeros((nx,ny, 4), dtype=np.float32) + n = np.zeros((nx,ny, 4), dtype=np.float32) + a = np.ndarray((nx,ny), dtype=np.float32) + for i in range(0, nx): + for j in range(0, ny): + pos = FSMesh[i][j].pos + normal = FSMesh[i][j].normal + area = FSMesh[i][j].area + p[i,j,0] = pos.x + p[i,j,1] = pos.y + p[i,j,2] = pos.z + p[i,j,3] = 1.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 = {'N':nx*ny, 'Nx':nx, 'Ny':ny, \ + 'L':L, 'B':B, 'dx':dx, 'dy':dy, \ + 'pos':p, 'vel':V, 'normal':n, 'area':a} + # -------------------------------------------- + # Sea data + # N, Nx, Ny = Number of free surfaces + # repetitions in each direction + # -------------------------------------------- + self.sea = {'N':Sea[0]*Sea[1], 'Nx':Sea[0], 'Ny':Sea[1]} + # -------------------------------------------- + # Body data + # N, Nx, Ny = Number of points in each + # direction + # pos = Positions + # vel = Velocities + # n = Normals + # area = Areas + # -------------------------------------------- + self.b = {'N':0, 'pos':None, 'vel':None, 'normal':None, 'area':None} + # -------------------------------------------- + # Waves data + # N = Number of waves + # data = Waves data + # -------------------------------------------- + nW = len(waves) + w = np.ndarray((nW, 4), dtype=np.float32) + for i in range(0,nW): + w[i,0] = waves[i][0] + w[i,1] = waves[i][1] + w[i,2] = waves[i][2] + w[i,3] = waves[i][3] + self.waves = {'N':nW, 'data':w} + # -------------------------------------------- + # BEM data + # N = nFS + nB + # A,B = Linear system matrix and vectors + # p = Velocity potentials (phi). + # gradp = Velocity potentials gradient + # (grad(phi)) projected over the + # normal + # dpdt = Velocity potentials time + # variation rate + # -------------------------------------------- + nFS = self.fs['N'] + nB = self.b['N'] + N = nFS + nB + A = np.zeros((N, N), dtype=np.float32) + B = np.zeros((N), dtype=np.float32) + p = np.zeros((N), dtype=np.float32) + gp = np.zeros((N), dtype=np.float32) + dpdt = np.zeros((N), dtype=np.float32) + self.bem = {'N':N, 'A':A, 'B':B, \ + 'p':p, 'gradp':gp, 'dpdt':dpdt } + + def execute(self): + """ Compute initial conditions. """ + # -------------------------------------------- + # Free surface initial condition. + # Since RK4 scheme starts on the end of + # previous step, we only write on last + # stage value (p4 and dp4) + # -------------------------------------------- + nx = self.fs['Nx'] + ny = self.fs['Ny'] + for i in range(0,nx): + for j in range(0,ny): + # Since initial values of the potencial, and this acceleration, + # depends on z, we need to compute first the positions. + self.fs['pos'][i,j][2] = 0. + self.bem['p'][i*ny+j] = 0. + self.bem['gradp'][i*ny+j] = 0. + for w in self.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 + pos = self.fs['pos'][i,j] + 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 = - A*frec*np.cos(k*l + phase) + self.fs['vel'][i,j][2] = self.fs['vel'][i,j][2] + amp + # And now we can compute potentials. + for w in self.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 + pos = self.fs['pos'][i,j] + l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading) + amp = - A*frec/k*np.cos(k*l + phase)*np.exp(k*pos[2]) + self.bem['p'][i*ny+j] = self.bem['p'][i*ny+j] + amp + amp = - A*frec*np.cos(k*l + phase)*np.exp(k*pos[2]) + self.bem['gradp'][i*ny+j] = self.bem['gradp'][i*ny+j] + amp + + # -------------------------------------------------------- + # Debugging + # -------------------------------------------------------- + """ + self.fs['pos'][i,j][2] = 0. + self.bem['p'][i*ny+j] = 0. + self.bem['gradp'][i*ny+j] = 0. + # We can do phi = Green's function + dx = self.fs['pos'][i,j][0] + dy = self.fs['pos'][i,j][1] + dz = 15.0 # An arbitrary value > 0 + self.bem['p'][i*ny+j] = 1. / (4. * np.pi * np.sqrt(dx*dx + dy*dy + dz*dz)) + self.bem['gradp'][i*ny+j] = - dz / (4. * np.pi * (dx*dx + dy*dy + dz*dz)**(1.5)) + """ + # -------------------------------------------------------- + # Debugging + # -------------------------------------------------------- - def loadData(self, FSmesh, waves): - """ Convert data to numpy format, and create OpenCL - buffers. - @param FSmesh Initial free surface mesh. - @param waves Considered simulation waves (A,T,phi,heading). - """ - mf = cl.mem_flags - nx = len(FSmesh) - ny = len(FSmesh[0]) - nW = len(waves) - # Mesh data - p = np.ndarray((nx*ny, 4), dtype=np.float32) - n = np.ndarray((nx*ny, 4), dtype=np.float32) - a = np.ndarray((nx*ny, 1), dtype=np.float32) - for i in range(0, nx): - for j in range(0, ny): - id = i*ny + j - pos = FSmesh[i][j].pos - normal = FSmesh[i][j].normal - area = FSmesh[i][j].area - p[id,0] = pos.x - p[id,1] = pos.y - p[id,2] = pos.z - p[id,3] = 1. - n[id,0] = normal.x - n[id,1] = normal.y - n[id,2] = normal.z - n[id,3] = 0. - a[id,0] = area - p_cl = cl.Buffer(self.context, mf.READ_WRITE | mf.COPY_HOST_PTR, hostbuf=p) - n_cl = cl.Buffer(self.context, mf.READ_WRITE | mf.COPY_HOST_PTR, hostbuf=n) - a_cl = cl.Buffer(self.context, mf.READ_WRITE | mf.COPY_HOST_PTR, hostbuf=a) - v_cl = cl.Buffer(self.context, mf.READ_WRITE, size = nx*ny*4 * np.dtype('float32').itemsize) - f_cl = cl.Buffer(self.context, mf.READ_WRITE, size = nx*ny*4 * np.dtype('float32').itemsize) - phi = cl.Buffer(self.context, mf.READ_WRITE, size = nx*ny * np.dtype('float32').itemsize) - Phi = cl.Buffer(self.context, mf.READ_WRITE, size = nx*ny * np.dtype('float32').itemsize) - self.fs = {'Nx':nx, 'Ny':ny, 'pos':p_cl, 'vel':v_cl, 'acc':f_cl, \ - 'normal':n_cl, 'area':a_cl, 'velPot':phi, 'accPot':Phi} - # Waves data - w = np.ndarray((nW, 4), dtype=np.float32) - for i in range(0,nW): - w[i,0] = waves[i][0] - w[i,1] = waves[i][1] - w[i,2] = waves[i][2] - w[i,3] = waves[i][3] - w_cl = cl.Buffer(self.context, mf.READ_WRITE | mf.COPY_HOST_PTR, hostbuf=w) - self.waves = {'N':nW, 'data':w_cl} - # Ensure that all data has been written - self.queue.finish() - def execute(self): - """ Compute initial conditions. """ - # Global size computation - N = np.ndarray((2, 1), dtype=np.uint32) - N[0] = self.fs['Nx'] - N[1] = self.fs['Ny'] - n = np.uint32(self.waves['N']) - gSize = (globalSize(N[0]),globalSize(N[1]),) - # Kernel arguments - kernelargs = (self.fs['pos'], - self.fs['vel'], - self.fs['acc'], - self.waves['data'], - self.fs['velPot'], - self.fs['accPot'], - N, n) - # Kernel launch - self.program.FS(self.queue, gSize, None, *(kernelargs)) - self.queue.finish() diff --git a/src/Mod/Ship/simRun/clSim/matrixGen.py b/src/Mod/Ship/simRun/clSim/matrixGen.py new file mode 100644 index 000000000..69430d9be --- /dev/null +++ b/src/Mod/Ship/simRun/clSim/matrixGen.py @@ -0,0 +1,184 @@ +#*************************************************************************** +#* * +#* 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 + +# pyOpenCL +import pyopencl as cl +import clUtils + +import FreeCAD +grav=9.81 + +class simMatrixGen_cl: + def __init__(self, context=None, queue=None): + """ Constructor. + @param context OpenCL context where apply. + @param queue OpenCL command queue. + """ + self.context = context + self.queue = queue + self.program = clUtils.loadProgram(context, clUtils.path() + "/matrixGen.cl") + # Create OpenCL objects as null objects, that we will generate + # at the first iteration + self.A = None + self.B = None + self.dB = None + self.pos = None + self.area = None + self.normal = None + self.p = None + self.gradp = None + + def execute(self, fs, waves, sea, bem, body, t): + """ Compute system matrix. + @param fs Free surface instance. + @param waves Waves instance. + @param sea Sea boundary instance. + @param bem Boundary Element Method instance. + @param body Body instance. + @param t Simulation time. + """ + # Create/set OpenCL buffers + self.setBuffers(fs,waves,sea,bem,body) + # Convert constant parameters + L = np.float32(fs['L']) + B = np.float32(fs['B']) + dx = np.float32(fs['dx']) + dy = np.float32(fs['dy']) + T = np.float32(t) + # Get dimensions for OpenCL execution + nx = np.uint32(fs['Nx']) + ny = np.uint32(fs['Ny']) + nFS = np.uint32(fs['N']) + nB = np.uint32(body['N']) + n = np.uint32(nFS + nB) + nSeax = np.int32(sea['Nx']) + nSeay = np.int32(sea['Ny']) + nW = np.uint32(waves['N']) + # Call OpenCL to work + gSize = (clUtils.globalSize(n),) + kernelargs = (self.A, + self.B, + self.pos, + self.area, + self.normal, + self.bem_p, + self.bem_dp, + self.waves, + L, + B, + dx, + dy, + T, + nx, + ny, + nFS, + nB, + n, + nSeax, + nSeay, + nW) + self.program.matrixGen(self.queue, gSize, None, *(kernelargs)) + self.queue.finish() + # Read output data + events = [] + events.append(cl.enqueue_read_buffer(self.queue, self.A, bem['A'].reshape((n*n)))) + events.append(cl.enqueue_read_buffer(self.queue, self.B, bem['B'])) + # events.append(cl.enqueue_read_buffer(self.queue, self.dB, bem['dB'])) + for e in events: + e.wait() + + + # -------------------------------------------------------- + # Debugging + # -------------------------------------------------------- + """ + for i in range(0,fs['Nx']): + for j in range(0,fs['Ny']): + x = fs['pos'][i,j,0] + y = fs['pos'][i,j,1] + FreeCAD.Console.PrintMessage("pos = {0},{1}\n".format(x,y)) + A = np.dot(bem['A'][i*fs['Ny'] + j,:], bem['gradp'][:]) + B = bem['B'][i*fs['Ny'] + j] + phi = 2.0 * (B - A) + bem['p'][i*fs['Ny'] + j] = phi + """ + + # -------------------------------------------------------- + # Debugging + # -------------------------------------------------------- + return + + def setBuffers(self, fs, waves, sea, bem, body): + """ Create/set OpenCL required buffers. + @param fs Free surface instance. + @param waves Waves instance. + @param sea Sea boundary instance. + @param bem Boundary Element Method instance. + @param body Body instance. + """ + # Get dimensions + nFS = fs['N'] + nB = body['N'] + n = nFS + nB + nW = waves['N'] + # Generate arrays for positions, areas and normals + pos = np.zeros((n, 4), dtype=np.float32) + area = np.zeros((n ), dtype=np.float32) + normal = np.zeros((n, 4), dtype=np.float32) + p = np.zeros((n ), dtype=np.float32) + dp = np.zeros((n ), dtype=np.float32) + w = np.zeros((nW,4), dtype=np.float32) + pos[0:nFS] = fs['pos'].reshape((nFS,4)) + area[0:nFS] = fs['area'].reshape((nFS)) + normal[0:nFS] = fs['normal'].reshape((nFS,4)) + nx = fs['Nx'] + ny = fs['Ny'] + p[0:n] = bem['p'] + dp[0:n] = bem['gradp'] + w[0:nW] = waves['data'] + # Create OpenCL objects if not already generated + if not self.A: + mf = cl.mem_flags + self.A = cl.Buffer( self.context, mf.WRITE_ONLY, size = n*n * np.dtype('float32').itemsize ) + self.B = cl.Buffer( self.context, mf.WRITE_ONLY, size = n * np.dtype('float32').itemsize ) + self.dB = cl.Buffer( self.context, mf.WRITE_ONLY, size = n * np.dtype('float32').itemsize ) + self.pos = cl.Buffer( self.context, mf.READ_ONLY, size = n*4 * np.dtype('float32').itemsize ) + self.area = cl.Buffer( self.context, mf.READ_ONLY, size = n * np.dtype('float32').itemsize ) + self.normal = cl.Buffer( self.context, mf.READ_ONLY, size = n*4 * np.dtype('float32').itemsize ) + self.bem_p = cl.Buffer( self.context, mf.READ_ONLY, size = n * np.dtype('float32').itemsize ) + self.bem_dp = cl.Buffer( self.context, mf.READ_ONLY, size = n * np.dtype('float32').itemsize ) + self.waves = cl.Buffer( self.context, mf.READ_ONLY, size = nW*4 * np.dtype('float32').itemsize ) + # Transfer data to buffers + events = [] + events.append(cl.enqueue_write_buffer(self.queue, self.pos, pos)) + events.append(cl.enqueue_write_buffer(self.queue, self.area, area)) + events.append(cl.enqueue_write_buffer(self.queue, self.normal, normal)) + events.append(cl.enqueue_write_buffer(self.queue, self.bem_p, p)) + events.append(cl.enqueue_write_buffer(self.queue, self.bem_dp, dp)) + events.append(cl.enqueue_write_buffer(self.queue, self.waves, w)) + for e in events: + e.wait() + diff --git a/src/Mod/Ship/simRun/theory/abstract.tex b/src/Mod/Ship/simRun/theory/abstract.tex new file mode 100644 index 000000000..3aa57fbb2 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/abstract.tex @@ -0,0 +1,56 @@ +\chapter{Introduction} +\label{s:introduction} +% +\section{Objective} +% +The objective of this document is introduce briefly how the waves of the +seakeeping simulator are propagated.\rc +% +In the seakeeping simulator Boundary Elements Method (BEM) will be used, +that is detailed described in several books, like \citet{bem_2007}. +\citet{vinayan2007} gives a detailed description of the propagation +of waves in a 2D case, and is a good starting point.\rc +% +We will start briefly describing the governing equations in order to can +start working with the 2D problem. First the incident waves over our +computational domain will be described, introducing also the potential, +discussing then the BEM applied to this case. As we will see the Laplace +problem in the 2D case will not be really useful for us.\rc +% +After that we can start working in the 3D case, that is our real objective. +The incident waves will be rewritten, and the Laplace problem and the BEM +application purposed again. +% +\chapter{Governing equations} +\label{s:governing_equations} +% +Assuming no viscous fluid (that allows to transform Navier-Stokes +equations into Euler ones), and imposing an initial condition such +that\footnote{With no viscous fluid this condition is preserved along the +time}: +% +\begin{eqnarray} + \rotational \bs{u} = 0 +\end{eqnarray} +% +The fluid velocity derives from a scalar function potential $\phi$ +% +\begin{eqnarray} + \label{eq:governing_equations:v_potential} + \gradient \phi = \bs{u} +\end{eqnarray} +% +Then the Navier-Stokes equations can be rewriten as a Laplacian problem +and Bernoulli equation: +% +\begin{eqnarray} + \label{eq:governing_equations:laplace} + \laplacian \phi = & 0 + \\ + \label{eq:governing_equations:bernoulli} + p = & - \rho \left( \vert \bs{u} \vert^2 + g \bs{z} \right) +\end{eqnarray} +% +And in order to solve the Laplace problem \ref{eq:governing_equations:laplace} +we will use the BEM as described by \citet{bem_2007}. +% \ No newline at end of file diff --git a/src/Mod/Ship/simRun/theory/bib.bib b/src/Mod/Ship/simRun/theory/bib.bib new file mode 100644 index 000000000..ed2200659 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/bib.bib @@ -0,0 +1,91 @@ +@Comment{THE COMMENTS IN BIBTEX ARE IMPLEMENTED THIS WAY!} +@STRING(OE="Ocean Engineering") +@STRING{AA = "Astron. Astrophys."} +@STRING{ACA = "Extraits des comptes rendus des s\'eances de l'Acad\'emie des Sciences"} +@STRING{AG = "Adv. Geophys."} +@STRING{AIAAJ = "AIAA J."} +@STRING{AIAAP = "AIAA Pap."} +@STRING{AMR = "Appl. Mech. Rev."} +@STRING{ARFM = "Annu. Rev. Fluid Mech."} +@STRING{ARAA = "Annu. Rev. Astron. Astrophy."} +@STRING{AMCFD = "Advanced Methods for Computational Fluid Dynamics"} +@STRING{AMC = "Applied Mathematics and Computations"} +@STRING{ANM = "Applied Numerical Mathematics"} +@STRING{BAPS = "Bull. Am. Phys. Soc."} +@STRING{CUP = "Cambridge University Press"} +@STRING{CMAME = "Comput. Methods Appl. Mech. Engrg."} +@STRING{DI = "Dantec Information"} +@STRING{EF = "Expts. Fluids"} +@STRING{EJMF = "Eur. J. Mech. B/Fluids"} +@STRING{IJHFF = "Int. J. Heat and Fluid Flow"} +@STRING{IJHMT = "Int. J. Heat and Mass Transfer"} +@STRING{IJIE = "Int. J. Impact Engng."} +@STRING{IJNMF = "Int. J. Numer. Methods Fluids"} +@STRING{INPG = "Institut National Polytechnique Grenoble"} +@STRING{JA = "J. Aircraft"} +@STRING{JAM = "J. Applied Mech."} +@STRING{JAMTP = "J. Appl. Mech. Tech. Phys."} +@STRING{JAP = "J. App. Phys."} +@STRING{JAS = "J. Atmos. Sci."} +@STRING{JCP = "J. Comp. Phys."} +@STRING{JCAM = "J. Computational and Applied Mathematics"} +@STRING{JFE = "J. Fluids Engine."} +@STRING{JFM = "J. Fluid Mech."} +@STRING{JHE = "J. Hydraulic Engineering"} +@STRING{JM = "Journal de M\'ecanique"} +@STRING{JOT = "Journal of Turbulence"} +@STRING{JRNBS = "J. Res. Nat. Bur. Standards"} +@STRING{JTAM = "J. Theo. and Appl. Mech."} +@STRING{JWEIA = "J. Wind Engng. Indust. Aerodyn."} +@STRING{MC = "Math. Comp."} +@STRING{ME = "Meccanica"} +@STRING{MRP = "Mathematics Reports and Preprints"} +@STRING{MWR = "Mon. Weather Rev."} +@STRING{NACA = "NACA"} +@STRING{PFA = "Phys. Fluids A"} +@STRING{PFL = "Phys. Fluids Lett."} +@STRING{PFO = "Phys. Fluids"} +@STRING{PRA = "Phys. Review A"} +@STRING{PRE = "Phys. Review E"} +@STRING{PRL = "Phys. Review Lett."} +@STRING{PTRS = "Phil. Trans. Roy. Soc."} +@STRING{QJRMS = "Q. J. R. Meteorol. Soc."} +@STRING{RA = "Rech. Aeros."} +@STRING{RF = "Rapport Final"} +@STRING{SJAP = "Sov. J. Appl. Phys."} +@STRING{SSSR = "Dokl. Akad. Nauk. SSSR"} +@STRING{SV = "Springer-Verlag"} +@STRING{TAM = "Theoret. and Applied Mech."} +@STRING{TAJ = "The Astrophysical Journal"} +@STRING{TCFD = "Theoret. Comput. Fluid Dynamics"} +@STRING{EJBE = "Electronic Journal of Boundary Elements"} + + +@BOOK{bem_2007, + AUTHOR = {Whye-Teong Ang}, + EDITOR = {Universal Publishers}, + TITLE = {A Beginner’s Course in Boundary Element Methods}, + PUBLISHER = {Cambridge University Press, New York}, + YEAR = {2007}, + VOLUME = {}, + SERIES = {}, + ADDRESS = {}, + EDITION = {}, + MONTH = {} +} + +@ARTICLE{vinayan2007, + AUTHOR="Vinayan, V. and Kinnas, S. A. ", + TITLE="A BEM for the Propagation of Nonlinear Planar Free-surface Waves", + JOURNAL=EJBE, + VOLUME=5, + PAGES="17-40", + YEAR=2007, +} + +@PHDTHESIS{yang2004, + AUTHOR="Jinghai Yang", + TITLE="Time domain, nonlinear theories on ship motions", + SCHOOL="University of Hawaii", + YEAR=2004, +} diff --git a/src/Mod/Ship/simRun/theory/deep_water.wxmx b/src/Mod/Ship/simRun/theory/deep_water.wxmx new file mode 100644 index 0000000000000000000000000000000000000000..7677b0dc57a4444328b766fe21e41ba95b6a3b87 GIT binary patch literal 73355 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 literal 0 HcmV?d00001 diff --git a/src/Mod/Ship/simRun/theory/images/CC_88x31.png b/src/Mod/Ship/simRun/theory/images/CC_88x31.png new file mode 100644 index 0000000000000000000000000000000000000000..49f272f828c17c9f52b64c27fa6a3c399bee9344 GIT binary patch literal 5281 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 literal 0 HcmV?d00001 diff --git a/src/Mod/Ship/simRun/theory/images/Integral.png b/src/Mod/Ship/simRun/theory/images/Integral.png new file mode 100644 index 0000000000000000000000000000000000000000..2e53f03a45c51c85f3e3037d72ea2500f004f84a GIT binary patch literal 32720 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 WX)e!Oi>Tmll9UwGPEh17-2M-Z4 + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + dx + Dx + Z(xa,ya) + + + + + + + + + Z(xa-Dx,ya+Dy) + + + + + + + + + Z(xa-Dx,ya) + + + + + + + + + Z(xa-Dx,ya-Dy) + + + + + Z(xa-Dx,ya+Dy) + Z(xa-Dx,ya) + + + + + + + + + Z(xa-Dx,ya-Dy) + + + + + Z(xa-Dx,ya+Dy) + + + + + Z(xa-Dx,ya-Dy) + + + + + dy + Dy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Ship/simRun/theory/images/Omega.png b/src/Mod/Ship/simRun/theory/images/Omega.png new file mode 100644 index 0000000000000000000000000000000000000000..e9ed7117132542afdc9a7549d85443693b4f0756 GIT binary patch literal 28285 zcmeFZX*`u}{5`rQNg3LPP=?x+qB4|1rfQpogvt=gm@>;eG#C>RnWrLzRFcdJA*3i$ zGE0&%kxXaZ&+q^Hob%$mKW~obg{Rv4-uHc7-(h{%TGtNM(NbaBv~3fKL}F4?rRtJM zv;rg&P4C7H_?r;Lk0SWB;ev(=m9$3umtL8Dmqgk@QllQz^GN>n&D%%&4{gItmwo(_ z@o|^i#xB)G`^@d@TP*by;$nJ63`EFE8+Yz?ch)}Oa{KLmL1kV0D8Yq`sj0}* zru*aKucS>Z`6}>7%DKLK_in*N+}poxbnrq^_vMiPelqj-KYqv-5+Ydg*ra@La4`Bu zvU7IIN=i??{#+`%I-%a0DA{yZh$S^OHB&n+wWrkObg8qY%++6woTffeIZL-f zLZsHYchFF&JZhIO@4LJEAkMxheY6V() z=DONifj~CAHU5DFg~D9uI@a!Vi;H*qxZm1}`#M_M?jq~96C>q5 zixM|BFkKjH&stAUfBK2ptKffLWOCH=w@NO`)H?2blk$6UrhW=ty{FK*} zaL_usXRYQM?ID}@0l!Dvgrw4ry4x?Wtjx^J>@=1L^OXr;(lD#RTyk-2{Ty2p4y$>iet-4x38g+BkZrxzPow{N#oFuhM@xH{E)vNQi2 z|K7Ne5LMx9hF_FHS?AGrtzjG@@kiYcoIig)S<2~pqNJUK+s}_GWe&I^D|^)3SO*&q zPsEb|VXq+ELfW% zV?cGaLdV0C0`8MNEN*EIRf`)G6sp&cZryjbX0vF;w9Z0;_{9x{RsSwsck!P8mEk<{ zmc@-9%X)~ajmIusUjE%SH}N&@-=Fa!`)@K!i~ap(Z)5ge7gkziJrI`Mn#wY>)fASOx#WplGJS60FNO<`0pDt7De{*AX4Gnz@U(THO3`9h5 zX=}GFoyUDiS5#Imj+T5#^IuJPX4$-3cnGnWbLv6Rij?oaIbz}WoqHzu(+`)-O(rfm zRDN}0+n=AGF8=(O%MjLhS6g09QIRz9rTD?6Pmi#tq|Q6J*=c@>9ogD_3svJ?h1xpQ zOI?pseo)rwRC>7y>p!wkhzJY2F!bhjXjK|E;!^g1LFh92&S!09VSebo(kAf&GG*mlPz2?`pH2Jke^p#Vk*B?IV@uD{Qq<)XJ z)s;veZ7ktObxY)gAtFm7?m#g==K2{UxQtzKH{&6wECZXf@v%^hy`=w-Mm!qckA~Xzhv2wL#jsxqC zUj6lizbp6jXoR_r`(1?5dOC~Ao>JV#Y{d9#<*Ley%iVlC3+kJjMPAMLpM1edCaX0Q zNnpNG6hf-_J9vv_x!9lO)4IGZ%Pu)xeXAzKZu3bDq};!Me{yLX{t!VW9=-F!0~I!& zu1EUg*Qz_eeogXOob8T0as2q?%ZJDxh6qv9s^vQjQ*%=prfYsoWHMRhKCutuZ(~Im zBGyvrXVX`u{fF$?n${|h{>wNK%=dHE-R1A}z*1EZikHACZZbLe&y@LT?t@l7IfZR8 zd+)BK6`EH2HH@N$UG7U-pMP>Q|0jjC8V@h8UbhI1rx)rSot!-TS^WLij!ruL{J3`m z3!i53rB971M~|Sc2srdse9S+0*St1p2IWeAwi*Sh(f|K^&f?at$0pu6g=?dKP^4ZC z{q~$4&QQC%dwxjLu5$}7@5-IM4!1%>%~3Arhfq>hM-NPgid(*ASC85AYI>lSfq`M? zzJ1~G@mvRtU)HcFEZ4lxII$Ozjf$y0+qIQUUKIMTj7B#rjQRu=YfjbvqH{)iEGdk( zB>aBdwVsad>D39t8p9y>-U?4w{0rIE{KI{v`3y^YdwWJMvHq&ABM!aG3We8hcAt4{ zthO-u?P>RAcG2_6XH0!#H*pBx*`=}db!{yQD$D7IngbtmPtQ$$OS;_s>;poFy0U~- zUFIa>?5yOakE)Ipmd*F*4+scpCGXg`uf-3UI8%OpbZF?r*B4jLRd|S#kOK18u3fWu zm%NzqOqog*yZl*f$q663*Q9LDw|Y0$^Y7okvLDAQmL|(TUp{>4W6rCGCzB>UW(P+{ zRq(pp^OZ6xk$k)M>gm zo~U_d-Db~!-wliA_je#zunj@FPFR34Sku$f!^)U|cE-i;zdYmbXJTWs2U+)=-`msk z11hff`7{9)W`oDZwrLL}+$W7UF!TJak?!*tVzO#WWjgy?=lYEs{9eyiZiL*vUA*?Y zHR;HdcR^vHC{d2Q7baO&VpOQq;bTPhoft<&x*qxqRrsNAM8h}ZDj#lte}9C7nL-!p z^)rhm=f197os4zkodp6Y$E0xHqxU)sjM(`2{Q9~sbwAsMrJ%_-Khx*)`{c8U{n2vX zSJh*M>4-?0(7rIa8})LZ@yk0{A3INTr0wAYhm%^ZWNwD2Iw$^5oqx3QxwZ8+7OXw* zjA+=_{hQ97h`+br=uQ8t8`5q+V^+Qx7GHYm`P-^JOCzp7wZ#70g^{uYLjZxAi-c;KdQPHl&;eChw` zwN&}wLVcLi@?WR(-V>4!H4|oa*7h3|p1+OGgg*STv~*x}w85oKE*PtZPt|&&_Y^f* z;ww=Mv<3=FddtRT8AU}!B`n|8E&d*5W4yR7M>lJeU1z@9lf{8Ptu*c6%ei#9M*&uRL^ zs&yNX(Cfg>oKLzh54R-TMK9N__VYdOHMR@AaLPOF*`vHc&pZXpy8**1jd-i*h!z@0G zBn@I5xhs^k2vt56TF;qLzZ2b8La=ixJUz3bv-6T2rpDc z0k2aF=Muj@Kk-#zIw zjHn=Fp%2A&XRszAp`jVJ9S^bM!>L{NJujoq6qU~i93I_bcH14M&FqkM{WyL@>2F7=pn?KJs^5Af7CbkPHxDCo#< z5Y;8UUboQgi!OIdAf&H$+1a7q4A$RjLbz|r#s*twAfyH@yyku!17O(9dB9@j-yfc% zSHqt?5kpIFN;)E{pJ$MTja|QfegEL#1)0ZyQ(_Ybaku!{ZIgy4!;kn0tN`&7u7l4f zegx1TiJ!WS#KYr9{P_RA_{Pq+f~9TeLBsKkv`$eeB;{r(}Y}wY=>w%M`!2xL0fIu^U%0 z#=Y);%dxSN)DT&l(6NQzze}_!N`T(a&+qTjQb+!|gR*jRY%`{cSVP?qd{WU-r@{3` zFD{$^{@(hlr}XYnL!?We!)9)Y0C&GVIyL_!{b?H4x(cOTj+MDKZI_bSwkk!V!d&}` zwzFZXVQSAFgjp8$()HKpC_q6O&x647suyy?L!^?B9bcLo5Ft|N;FY59R=8pgFlDKq zXlmEV=Nf*S;%v^Z=ON`&&HKWaUcrZDEip|uS9cc>uu9V5E7Q}{V(hxO%T*;yYTbwW zH*cO@`Fhx(z_1|<_uJg97BvmB)G+JTed)DSeGI9~b5IIHgZd}U9_U2X4 zpZU`WgqD<}aloKlj2N5-^^gJWVHoCckb%`c4(){?mPP=!0XRXZf4>F?6`n#(dW-+iKTdM+wu9iE!)gmkA}cSoMaq4tqbiJmc%5$$>;k;K`MQG0ZEn1?t-S<_a*5xD}ad_sx=6Arfss%$L zjZI%w<$xYVP1%wvC@Br30TgeEh3$FiG&C?)1UvzXF=h{<6!j|cq8%d`R3 zsh&X?wy8cy!hds zrz-6DVe{ zBRv~gWufi$ObNoK&#AY$c|2nL`0?ZMvYrxERaNX5UZMn4cKe*r5aj5%OD5j{jG|W# z=X&*}*iLO)<*6&T$Bh4UOHo7#+1zjo2i=Y9W=rm*nEgigZf`#ljrvym3h828>Kq7k z{nWN&H>ybRSB0w4hK7cNHt%-`pLwi_CPdT(z*C{$)%R@E2*gr3Z+P7^5Y5LNfNJmj z)Xr#C^ymw(F(Psy;7oo0e44oX__0oNgYZrck%Y}c_g+eI$um|xTa^$!^Oy&NfFPi7 z(2dX#0W{l|RJo+|^c@GzS8S}okY@uRdw zjQXyohP7tom5D(M`X)aX#hfTlKXLx%@xa@bcgsT}gBOCoY*s@eelBwpLDi8=(xA3i z;OP!J^vW(d0da6kUSda1duJ|vxqO)58d7B3_$2SEs=rSrN5wpG=#x+NU-f*XpLex9 zA}-u`_KL&dVNhj$Xw9+uq)m^aJ^PPvobm%3P6wZxlC#e`(yp$i`1T}`V+r@-#C z$uI50qSd0?M#}#S>8-8CN!A?XGiPi*Z`|r@Tlw`dCHm^i(pMoLI$y7=X-PQ9ee`Pn zfDR?v0As`b)i1R_(h?8ZMpGQx%SuZ>JhRk5gHtg!=0OiNuL+=GIMU7`F4+CH5#)pI z#~d=Y?*clTaiv!*KJ%NC35IZO`9(nhLG{ObD0_DwK73DGVI@W=%_kaR?Tn^8&i2W! zrYBJB@_P1t7KbwhBeI3UlSq+9yCg820OoKp@1ocq!$d(q#-~r8DxdGGuMZ^fpxd|s zW^LNDcSlZ~IB|QJyqImV{h{06X>;|s1Gj^N>9O}jTmJj+-)!~TN}JzF+&3nx5p>X( zWn~gpEnMg=aXe1c=x@m6AD{9#gPD2Dd}o^m-xo#dE7yth9NlDcKFFwKdUo~#pdYxY z7FS`iS{A0)7F>kJW9aq~E;+B~A7nAX(1X=khZgq`pj){pXYY&b*3bsYFbRf39SN@+;`V#>4{l{L?B48T)AZ-R27w^ zh#gwOAGDPppRWwVi~-P0mkz#xN8X3a-F<;dC+#u4!=ZZRu*>%rM5)NBg)M4(@uDnD zYYf2_i}JLE3&B2-+naao-Lrec`EkZzW)P#Vk)IxurK6hJtWkOvxZSz&u1E}fzw6kv z<0D+OGcqy`UHKA&`E+(5m_IQ>;N32#+ULYAq^0qrfRJKDO;f?O=wOHz)ZP=F2(Q2J$A=+>F96u)naija2ieIZ?@S@ul7wc8%qL+A zw}fIz>XYfs9AxW}6n?J-x_)HZw#U0D?y3_?>&=$`&J4dx*&cw}I$O)4z@;VlPVfUB z!le8SI+e$0iaXGc>Q7_R^6JtQhSvlzX@bowN_=%=9ob`;dXQ_CzOxBsVmmfEk4SK8 z>PB{Xzh*g#2td(i0ts8=N+FAzP4!mlJvQ!k4X1XaDI>Q8k&f%=HaY(KEWWh8jncGd zhV65aRqI=f-_ZpjEy>b%5f2@xN(4haB1v6sCZ;-YXbzm<2F>4Z;gVKXqS|lgTF)(E zR@D8YyD0mxGl$c0RR2s+f<)!K#VMK?@%w$M@BFzpx3{Zc{)(6Lei0Uu84reI?@HV_ zx=yLn&<2II<%0*U-)Vm6+A8fn$%D>Hi~|7O=khKr($~z!PW!kNMDJo)sf;=32ynin zn@Snv!4fHtzDohyl5bj_ijR$th}nawT-lu{EPBfGzq(JL$#uWDV&pvf zbi0@t2}qEX&vaw*g?G8C^Iyb6jzPgTl-wdMi-qe^{Kwz#7;g$`{Pz43ZB{c$%xRFy z%p+wcbtfb<1~ZNG?66wRzu#$zanmcJ{tm@EqIFk`!l}y2?HMQNQL~k>=%tPW$JK{l zcXZr6^+1`XGunl1x29@T7sn_EnS8A9e5DO0$ZYMj7h0Y3Pv;puzn?<{{&8^&JT`T` z{3yyCXeDCP)Myk|{|W$$)7G@LMdI4rS~1TrA5NOz5oPfw&2l)!z4z%&4YZb+|61P|RqHCNCK9$aaO-}W z&)9C0BR4q64FulqEHu?FbsmX7Xw7_p`B3-*Fd$Yk5-Xh;L1F$?g|a5=aR=izD;wL1 z+uI~RSNR?V4YoHS5)3fA|4Ao4kP8(Hz23wO3m7{7AAY&wKyEhx)~r^n1X$ zieC(h(oM$*I|9_de!~U{5MOyAFUyWMyb~Kc$U#=C*mrIqiy=fCU(Zdx6QjdDcxv_U0*!4f;wRmcxY`ylSM#b1FN zS*IqcR0jwS((uBC3z{lXhkkWvE7W&&EnFq%>Tmxps!NW_ynBGxb)4aBb4(=f(N4!5 zWHogH=bDsXJ^570SM%rRrviX~9^T%k!JKzE)zR$oqMwhsipV#7Zu1JPP`rY_ylBQuf{nwpG2 z$D`rnY(i}?3vK6< zT`Hm!Qg3gsFeUo(E_Lwj({m7v|97Egt~45N@G6g5U)EXxJQ5}TbMdF4K@5V!eX)xV}HOwG|T`js1E_R-aV z$9w7d`{95hCHgF2-v~4sv)4Bno?q^6cjXa4Pf-SeZqxCQsd{BTX-sO6#HwlLKT+Hj zfB4EaWF8Mt26(@OmaAvJtUtBdOlZKnte2w*Py#t=pV5mJS3$L}tXgKGx|thMBGa9Q-sC4u{4es;7EYwyTFI&w7MZwxO6X~DNCcZkLJq$JA?bjvbaUS~ zv7Mj4Emq`AW5U7gTun+SD@3(hqE)I?>P@%%o}0O*9~R#%46)r_eeGB$TNKp8FGt91 zWHmcNhy>57QOIZiY4+^He#;()FD~1z_&K@-`q2&) zxa&~`|Ku34%*rvRhyJ42s^aa)rIvW{8$W*7bU5h-3Z;5n2ZKHRR-{nO_n&Krli+QQ zgGqd=UxBNMsR29s9lP-UUze8f?%hFM=e=*EO&JM2v$)10fAi6&mJMvBN%fn}UrUh= zU;Z4BmX?O6pEdpdE=2!PWY>X&96=6&CVubABi;{o`T33cdn+Ijs$#AJT*?1rRdtt2xACoMzVqCe!PQO=#Y5N{L+K$w=^F$+WkstN#=yjs z1sH)mI4ktX;0D9p9o|=qUQzj|iXx6~^;ShQW7%nmS^|`XrvT(6!0JYk!io!0Cx2QN zb)T*DlEkGXc$M0BbQKttd~s*H(w-SQAjL8|l{Erz(J(XAz?2;oGmUW7&DP@eTb@xF zuRGZGT7_-mgeg_Gavfd9Jr)um<4#%G9+b(_xPjW>-zcZzZa?*$ha1ghv>sU$b$k39 z%eL*z=O!qA)?z#{TKk>ow}hUt4-nuAn$NRRg7?8tl zyRd&qB)U_tV1rUB$qYkG<_9GvB`S%SLAVbZ3b3P#TT0!|lzfaS^G#P*9E9n_cNAw# z$bUGn@0hPX3G=V?1+2Lp;?)@bAlt_ifI?ezv4I&ii^@6$MsldQ>pX2g3ix;Ma1zO? z?W|q(w>XQiN9|c1I-F|0kX9hy)=acA(pNAP(4K5y^>n?R^!dn0GL+2$G0Lnqzt1$y zQTNG1yaFf3U>_h-5WFn_b+0Rr+6f-3@MZ{&+_D~Gm`o4yDn&P5r`v1;u>@o19eFt) zsdt87j`eoD35^EBVQHp{n2Sj(&Wk-(1xYvV6qB!J+f9384z0b&B(< zv~LOCBLEpG9l9kWzkD)e#`p*UH8be66#xx&_4VK$#V#@a{V2|>A!sYt#Td}os0y;n z3_C=Wc&4P*pu9Yh0>d#Tv8dtiTPy_;KeB7fzey-@;b{alH7XfqXe$u2|RMpp9I8MGx@C?PwZq*bTdMyNk5&f71WV=1vvPFMD?s9 z&%>D~5qGVyG`Aqryoa{baY~TMFT4w3RLWIa8~^2gF(#;@L32Gqcgwn9GRescvW=8gZC2?vN2d}SH{xd2P%=eCH5xcYf*V36-#^{ z^BiREg-Ev@q0gT(LGXwtDb+O*G-m^!cR1G3mbP6`x5(-w(Llj`DuJmy*$}1Iva`7n zW3uP+Oha+l31K(r1;|`w8=D-r`*tigpFdyTL+((I4SL;~x&bQ4As*$rQg|$GVhSd+ zvR;piiyM=oXw~B?Xg8?4me2ruDm*(}c@~3F!#})qy6Cs^=gfHBX3=9y5y}TcGq>GN zTIV?3e{6oLkEl;BFFj`N`znNQ-ET<9C{j@&E>4XS?O>W~w$YZE*KVk_9dOTgHC{ew!YxHVNkT@=&J zBs4V1WaXM|^nDnRAU8V0?$Q7S~Ze2}_CX>VlHZ(VwdN-l5YM z_LMgsImZf!+CRoHwEK9k&%=wMnSQtPvmO^> z=Erg}29wF2hfw?<0&ZF~-nj-k0o+Dz_}dV{TZGG~%*}4x#DtU6?wMDUF7a-rVxO80 zuV+h;9=VtW2IIAorCtF+e6IFafE4Y@6I^2RfkGG{P!KSY=)Dr^A*C2>rUY$q;$ceB91yeEeX1iXF&NYk{A>oPr1Mz)Te1F=Mc1h9 zk1l;GP~s0jb=rm}K5PH2to~ifQJNgn>Z*Z5ly|LoLPFin&K5G0i;f*G0y6_*lxcj& z!o}&;jgIa|uw4btZh>WgNCbxr9^oL5YMm2dMWQMx(dZPOm#ei+*6{F)9`?Rv-S66-p7g20fY5$1i&UYD%zO(Q4(VwK?&W|mfY)OThRxyTn3Pt1Umt$}d=6}^tQPD~3wd*Vb* zt?EL^U_+lkod}EMX$|u7>&!GFtH~&(1`O`%|4~R-D=_gUY6(U^tZ!)OczRLAPRNmy zGclZ7O7|^7d`{LxxIfTS)cmpk|AZc^e62|tYNll6a`FK0(glIr}liHi`|;> zBt_67z$%c!2Dq*d4^M8l3teO6Hv7mm-C~0l z)Zy|-qP@b?rDyHSO$S(|03J-hi&=sXCoDv0o+t~0JlhUIHm|>R`OEVrN3N*nK;<8@ zG&uiDWz4pzdoCT02_b12C`0V7hg)v*+2#+IatsDzAroO-{L-8fB3NWSZZ!3M9YS4_ zM_KR+xA=wiA_n>Y1&du})b40QDSd7lJ72paM~+}5t4D3pY(S9`<34zNKYxv3lIiy1 zP}z9gn>aX`@qQ-n}f#sggW=6d_!mCmzU0Pmyu(P5B zT=YE{5I|Mv7IvBXrvOrQ%WSl3y zKospnn3OOJ8w9O7#4`y}7KWc&!U%dDbXznEk$F+KW`o+N7xv#SnW{fWdj~7f=13t6 z8NA>bZryA{ON}Z&hZc)lc;R+OgtOuZPft%v5NnjT^A`yTOmttK+t$YHJ&n{9=M~Zi z|nIt;)on4!KmUD}3b3!r= zwTzSvOYCodHJyt2@vVL-36vi0dK3zH$FP6Y$A12cebvz4ZXBcPMq=MTpsC>A=^j5u z!##YMU5z&RML5ii!H_O!pP+q=o3NLPu&}TYo>TmtwMcd$xFgaBU5ET5Wf5=uKuzf0rQ693uXC>O2o)6SNjKq*EXn73!DVPetvZA;b7v+C3-Ahc$1 zyub^(ov5BfG0DFnbgNeAG$IB#&(lU&z&RLYFd4Xc-TNYI?WIQ-Dba8B3at8EEPzjl zz)gmNIMZq5aE?CGyY_G7P8TaInBXZr<<$YaQ&3p=tt;aL7*n_~WRakC-bXbFVhe4Q zD=j--`-b$Zw=xNH-*#rf=w)J@i{z8b*B^dndBcfq#~FK|d%-9@}TCVp1w3T-Ku?6)O$U7n8q8>z5DM;%A%HjQioae=ORj8{P*RJbiZ8KwfS^-dx z_-qmo6ugORvT<|U76>j3oZVyc#&sXrlPWBrhz_`M<3^Gh_!1}^-HwzZIBc6?wz}PH zI`twt7y~ds0ux0)hY6f8zrm~dJV>x=@kKE_$WrU^Mr`aY)L~t?c2FTLWwgS= zA|p$BudqfvZ)#;)XSnW(UDpAK@{IJXYTF2MsM|V?V4ypvelI919`q+xnjtrQ84W)$ z<*2)Je+^A`lE}>BXxiy#7HZIrE+AC|4T`q*575*gtpV>mU6Is-rK71usUgcI)NO|_ z$Wx=^-!>`?znk#Upbdgdg}`uvMvh3XMf1>9VU4P5Okhi$r!xbboY$YBw%;d=%~Mm_ zfB?le|D^BKDZGX@9L=bwoZN#oYy~zV#fzD*ODMLDQT@X4ep3KJnZm}5uw@-BpQ?HQ zOwu`Re&&qFf}G84GVx|jy!kVz*E-l#X$YADPE#W01afsb!s1B%4NgbAHi<><@sI+=i%H3fe6WJo32fe zq+Gr;Hpht`;ZYubg-wkB-h+?1<{NKN6-%+NChEV%LkVY2R4i*a-!XjE$lq)t6SxOV zBC*78@9nokD-oot4(ePc=L2@wzQQR9hc>d4d+>q+EGa}2VNb_J{HLTLSJYx!XbDoI zfs;*)_ZT%gOhsnnbA$Da3=D+Z3HYbSR7YnEuZ-)C-McqPSYD4*05&9Ug#A9QLCDD- zGlK!ezY1Ed!0l0ocOLp3%*aiOmvXv~TI6nB)XfEH38Ul-EsNGoZ1UICV_P?{MX_h$ z-LTVD{QH?lN|y7!hd#7jE5?=JND)LQ8@5CZ$HcDPa{H-k7B+}{GJ{v8 zGqhp0CWc$*MKai_=s~P+1~7~ds#UVQZzAO8gowL>m~cG73EO}J14nZZX&8OFe{=s& zb(AmUrdWz{-6Vz*;y?yyAS0no96`24{h{~442N(F3oP6bIdcI1yaBN#dno^9u4BjH zawEyh8)i`JGB|`S`U<>&z6s3+>r?{{F4wSF7`#uB*2jD%m+!}VE39sWhKLIbXkEZ= z2B257ZrNgnAylwDLiB4|#OH>QTU>-d>f`Gx?KBAPw~F6KYOCzQM5f&o<=k+o zP&w~;l1{oJjr_{oY0LqFO6;DmtIT^~+3c?NuO3hw%$HyNOB_F_#Y4QRr}LV-J|Ix= zsgGKhn;R}002kLm@b+*Xnail(Z-ss-?ebmBf7Pd=q5^0oDrUB;gA8gF9Qes>vJe|5 zrwV`+L{t`{)P3JTd!yf<_oND2l-}!at^v=}fzo-T90Ra!NHU<{TVtxBgvQrFrV3_p z2s7SJs`(;G4DdkW;L*)wVx_LZIt4bm2}YCxwo>O;jpByl8dTQzccbX17j}n$vbcai z3hIDgGn2U_ErN0T;TG3zPV4XwgCJ5tuZP72aJ%Tiy~->sz(Np4AQb5Wz>{v*`faxQ zcZdZvvmG!{<_5aW=d@JH1j?SF{#prt` zkaP&QHy4*GhP{_%hD*Vkshgx-67i(AH~n#RUI-^K+EhEqcnVV>os~5fi)f@}*SA zsmb>RMn~SpcFcwXP5ROYloMM0f8=IeUA&f{?M*0?a0L*DB0wE}k~x8w67HFAMov?Z2~w61`DaAao1NZ8*$8LqH6i#8P&K`&IYp1*M@tRcd=W z@>Yn;AI^Qy|6I(1x%%+XpuiC(7q~+^WX?U=(h|>fZQ{^A4JuzKZY)zHE&@G;rt{_u z0_&ki5SWX0@K%Imh(lGM!7zkbZ;3k8(#q89Mc?x+^!DwMPiIVbp`*A8t674!xCZ0K zv17*|ryJHkNKj}=rQfAa>;$u-rC<~>ae|qodFeW)8^#<5uN@B#Yz;uMUEdFPEx7U{ z_2*5gJk%N1_Ze)YrG=@{8!Yl-JgU04FwE`NPSwN^2TS5zHwkS%E(L~OKE?!z1g1R{ z<`b5~WX;4wp@20{apDSRBGN7t9`&5HAUHmfjO&jY^uyw(86kpN*=O=~*ZEApqW{%h z)Zn;7{0d>LC_JA+SOcIHj1T{AHGjpLbE@OA6xm5?@*!=eC1isK@UQP(EhElu;7AhT zjHy`sp0s!MA7xOn=bQPojz_5+xLH^xgNTz(BO{hF37Jo@e6#P4PKjB*jrl5~^u3Ap z*o}0nD-ay&%*UEkw++J~gZt8lZ_-xwT#q3KgIz=oA+7oNR1D}u>q6*EkaD7E%g(Ha zHwnHA6&a-CzH=D>l}+lFf}tmqrJ_(agt}MWrOGt}n@ma-rhHNoRHJ)--Flq1Q(hg+ z#UZTUYdoFD_XKMXsH#}QFt=xyJ>%s#&wDcII&ORxA|=Gsp?*BgXO;n3P!F3Lv=^{c z<0@r+aM=^SCOCBnHzTBtU8f*`mvbFjAHjd)t`H$0fct(f`f+E(2;N1QmT*UXew*$| zip>4E(#rB-`*}+A@wsoi8Q^3HW8{_q^U{omY{aYC+|rPkp&((&TwIO+W9^5F_dsYz zSje)*L(S;{kH%=aq*i4lX?MAM;h0|ZP1Lg{U>}W8)?LILp-=7U$rrk)aSs+iVVJ=0 z&+!T|pcO~L`Z+K*rUt#-q|9|7$)U>g$I>zi$$S?3@8PD}3eVqv{|-gog;~8ZWfRBs z1qITXGgwy}U>%r)4yLI8r?nG&0&oLii2%uQHf`E-+g2YMhYGsxVw-CrnX<7_f(8(& zsusU*#~}m;M#juzH#WFe9*~hqM4Nw#48L&kBAd@7J~$ibloSFfcIxzvmI>FLH8nqHe$)ZxlAnK`uR!^uqDarj|tWzCcJ~w=o$u zxJr1EFbbdr0mr|FAYkuLaghJfjw6X59QTpcIObCJB*5F0lz*f_K(wzHbo1rC8(%?co-ND_@Q&YBV~J>X_pYBTUP<2hA=% zo%9_()AHCE0=vQ5c>`0MO{&o*obM!#4?^#nc(-Dz9{VEbB0O}H|MEb?6Yt2z$FVS9t(4a$9<+fOV6^jE^71pjBRo2^S}H45_!hrV~qi@(p6 zx$Y$n(0Lr2VeRK9F>OEbP}Ax-MkjG%LDiBq6Z&s_cp}X8CbIUb$aTU zh>}iQzy29JJtnx3WfTKf7U6oc`EZ>$$%tbh30k%-c>Chdyh0+PaaMFco&%=>+yaI5 z3)T%9aY|SpW`kWJ5OP+CYCHb^`~Lm}Yx6JGcuFHpVm`8l(FR1u2S|I{j@XCi-6&jk z9js%hTADlxdg(3f#)O7GRngeN_Na@LCZqF}zQQ@vM~6(VC2msC*0LG6Hr-b!{s_In zhKsjCtxzU#e(4%o_za53hsP#I;h(XWnGm=Y5%C@J6}nn5Rt0i?=h3+S6{E?9no(Pi zFI`@&_jjJ93=aQySx-1`X?t%*h}K5eKe>Rj2yeh;y@BnHTgG({2DIHfb_4*R=wuwH z>j+)z!2C)`5h%h%{(#gw2HMNlV)nA>Zaz4!ZHFF=+CG0YP>7P77>PL%)LGYil3xZAgG4Z(|#p$YDG zRSZo4QGiga+qPX&aEAb>l`7i=jx{7AVs&bJwzk7WiSDzQKXnf*_UOos`ud>Hlv)=`#8k++NbeJhBIC6EEw)mQBxe5Ssp-p$ zLdgpBhmEd_-Uy*l0{>!~k8rACJmDV%wrcd;Nc z=(c^@t+4AI+4X;5^H`LkGET6*k_X8-p~tphdnUz&J!*cnXEUccP! z5VwUXkCiO`UoF$Eo*OGz&%ZlWCqM#9R%>RgHG8~5vXUC=GrVI!zF z{LJ5fIO!WtsgzI&Z^QVaM{idIMl|}P(__Bv5>&@5WSHP}~_#OxnY2Ps} z8vHV2c)gMMqsA6x;@8>hV(aj$hV>?y_~X4D;l!{1|E>R@Et4vT6OL7I2bsHZlSt{C zG_~QWK&XdTmtdp%1C8tl z2<7KF$4Ml|awiv;4w$z@YsH>}HBOOsQHBBFBZ!TWfq@KgWqbGS(?pNIgd&;)F}%EcX#*w=blkvX3*Pp2BB;34hJBHqEyD(_h2wvCc3-3 zzdWPVHZZ^_L41CEd=B`Pqdxh;!NCLz!?f*C&N>k!mHRqq zLi^7?QH04Z5htTVeK$W-c(f6C7f4}w8WeS%Cbi8YFTw88Hfmy@EGSD9z`C!Bmh zD+|@VePRoeairC%2o|n$(XP#ky6?g7`~k~4hW)*ZT zps8Bk?v(89g%%`@Y^Z#ObT8&i0#973f$R&!XbRpZ-+SJ3BcI>3o}>)psOH# zwwTane zI0|4W8{hb10|v3ehP=ypOw1V?MPlU3qdtG1fFjGl5{pPnpTnJS_^m=^9|!+*FEUa) zFfC8kb>hpXpR6QOPCGbR*VSduyk^Hns3*lhfSXE%=BBZrv z^>RZTvj82=uBv0$>;&46O-U($j%u z!FE0=TOUlgc7I~y0_n&&d+s*XYXUy=G-x`vHn|18M$i6#lksA@cMyai!7 zsjIgOM9SVrxq5aS(WX8DMoBkK-dEix_h24>&fARwBbk}{ccFHxCnO|XU0DDc-h}7a zQ;g*lp-}EO?uf4bM@Ic3cFb?(-&VbiJ=@GPud^FVmU{hpwE8=3%?3IQ5m?}1cJ6fu z9EOol;0}6VHl!vaeA`MpJTJS{P;+2Ve}LnQ#NEpM?Z4sd?q2dzy}xs#Kr9X_XcJoo zbRwt*T2t59IQjo9RK(jg%ZJEjFjH@T(%akJByYwU5kthl;WH<3UNRF8Jcg`~MJXtg zC6RQLK+P%P3p@;=mFDp~GTbEJT3lSr^Ph&2 zZ}E<_M@f46=Z<9ZnraxaWj#>I?8wf_a(xvu!skwDVwnesV`)WMqd{tW_i`BUp}>WjrqL+sJN=5E8{`@rR9c!SUdb|5pcGH- z_*5X&Eoky`hwswuxli9KIHG-2m^IoIL|RjXBy9~t>uE{-vOp?&baA3;)%@1{R9QKA za{V>}E8u{;Jw^VfWrqWE;D#6}wyPu~2v>$Bfi`db>NxDH1+ z@dEXevC&t*IC%THjy04oey&@O<4Wz3^dv<(N;oMXwyO8u0&A_$T4Ci!O3vI+ai#X9 zPygbsb~4#^y&GJjC7JESQ=c81MuOc)X_mLjrl0t#5*g#GiDFA4?$h;Orf+$xuO4$eQJRdaa`yP)6&&H&Ksrv_e#08r4 zbwjiKcYo~|A7&Ei(MIBI$9z+;soNR-}FF$;?jO zYjg#-wIjQhaNJ)$Y?Q0Oo#oN%Yi0Eijq?F~DsB^B^wF5_6c!eOOwxyi$?ezYQ_zUJ zaO6_=(F{$E?!?jI0<&SG=ZgOp6MqjGS0C7)yr8i()2H4#wb$F1WG4PS?QwJM&vok2 zDBf^OLb|gB&uSdyt9$x%Y+~Xgh%`Sys_KCIKV<%TJs8AO_>QtzV{uYUd!1UlyLVO$ z``(fKxf0vb5T6*2UFxrOC_!SHP4#F972@J2T_- z!vo+Z_#X~U8bfbCrK=l#`VV+FHKLWk_{q-3_Mm*StT}gxriNA0PJOCENa^<5ay`2% zmwUf{Zm1moJhK+RvwrpH)ToSGrh9KJ&$2r=>5&ZaG-G13gSSK<;e)(zl#pm=YPu*< z#hCEv)~}DzI0c>7ZO@LHpeh)Z;-R<9}vP=Q>6z zuJG}-{}9)$RSs#^zglv5 z9QqD9P79MiHSO!eMg^`7e#IuUv(As@`cq3Bswx#3iQ4c|b}*{M!@r8{asOMZ*g_JdNKQ7`f7c z4nJQpdSZ4B=y1YS4&5Th3m1!!2#f-4y;nxY5G*yCO+l&L?%m2DK_uhe^ZWt-{<#MeJ7NN51QRvf`ymnCl!KvWw(y%5-K-f3n8|7*|u`!O8OTnwlYL= z#k}nX)SRvjvWq?jHMNFj=xGnzKsJ{gsqFhWm)haAPcd+fwR79vY2@}!`{;H(CF)1^ z450QDk!lHm*gHP|(_gQzqoH*84F3$9$Uwu;(9roAjLOLkVF{DABIdMZYYOu7J!9I0 zap-8O$p^7rNOHJT7w}UcZ*x)l$}d{J0&_1UCT2I@hj(nD%i6hE@fN$XviAr5dl=W? z0!t_@Ed}OE);byMG82S#$obejl5`EVO5#}IqU+n(nA{%atXV%g(bs40%z&1gjEcpZ zFr-6*qV5-UuBfO;2nyPgH2?PzN2|^kO96hQq3Du;i##JtciBQL?L{JS!)xEd;7ndA ze3cjt2mo2PQI$V}1bT()Q9qj-SNc5FZk-?QnEnH|ajJ&R6t9P8vY)CZOp3cvSKF*=QP9m7I)o+@uX18ss8(rqvz?0V+#(cWQbI&@b-l zRo49sZ#PC@Kl)U>4nt}K0AYxQVA)w<1Q&FL$t!v-)hO>Cx-^paJFBa zU9!{{_#qk;qP?I^j^ z9XjWp^#nKJ>^*D01#b1?Ts1&}yJ$N2pz^RZtnW~hkkF5ah{%P;+S}WEirvFAwz9G^ zZnHduX95mg71%M0L!e=S_=1!0a48>W@c{( z6Z=)t#&9ckh1dQ;y#zn(xZVu}YwAK=ty{>Gv$>z~#~0i*))MTjH))&2-Rm~goWM-g}xnlS1pFA}P1)CQ4L#*L}0~R>yh%(5{ z$e><=OL+YJ&Qc}@u*;W!gr`&rBZ-TP3s9)5%-Gm_;0d)p)hs>FS|%tcXn}>azrSDH zz!h%0_EOLMpz-po7Ytc^w7D-^2GZ~dDyKzFj}|v195&wzfuic7;IdkMmpF$|t5nWg zkfU?=&5vh*#vsGR+p5!jVGDzdh5gW^Gn0I&l7P!#4*M0X_;nn{q?=wtG~9(5^RYf)?Pp+eh_>qX*_=T&>4eUspxh!HA~c#Cek}^=n6b~ z`0yj@{rzBWk(rqpnM(UVd~im#8R_K#*4PlMcr!;;+}kaf%AoW^=Eh1_@@O~)z4Sp> zPQ!eVHm2q2nx(7M=VyDz#@uaPOCVDUkCrxc!6&YjW&=FUbd^)2n1*)-UeeKad17qr zP3Q^<5HmSDn+OXiUYOse3SD=52>eWrTctiiku8E-B-0Rr_(Sr*iKw2sQZ5wFWZvk3 zu7=J-2^>wmXkr4UFD9BU{SvGFR7cMO4K#X0`Iu$(*Ldx@Q6=oS2VhQkO&}Bak8VFa zO`0-lSvDv|4Ck?3MnNLV&ezcurKP2fP?wsC19SF@20rdxNz(PZ8&Wj3Nlq9X$CzHK z$=J({ly@A970cwhiAEK2DB3yALw@9L9>rTZi^M1?)jkN z8q9O7SE^9ka73!l)t!CxjB%h7u{IY%fgVJg& zmb~bHqE?>2^2Z`Yi-*CjL-8@eupyBLK^tx`qMHbB3Ns(XU|!3G$5qX;!VBg z7Zltv=92q6D)8EJtwn}lRE6juY>f$VXSU7bGmjiK_u@`~LGJgi7Qh?M^E%IUT5#2O z>CUzNBr{2?c)=#`aOE~L+nwM$%q%P{tinu5_9ySp_#)Af?Dxz(Hk(cDn$(UUx{nacFrPClF(XGE>pR|!~y_58;PH{(Ey`%K& z&%ja#*3*F#C<^u^q~Xzt-#>((&(=Y{n3Uv1*c@gg^tbyKdF|y#E%?bADI9erPe)`YvudAUxHm);T_W`dQT11ysf$J&Cf|O8 z=lH*0H3#6ksGp}W$%YBEK z+$k2G^^S3^Gu_?Y%*pY+lEc~qot@TWJ=N8khWVGdJC0{CKkVM=0sL*?sG0!jGtfcg z#Kj5OR0Ugsd@St>T@_u?5rm^GRY9I8i<{TVG+y0HA(8%I?0eOW~}C`mXBRe|&pIh~f^wQ&CMtrjThM8faWh%ofQB zBUNk+?p^l}VQ>Md@0i}l>CuGoH_a90ZYSIU{cEx1pY?_YPUVhuxfxLV7EqDRi1?fy z>#$t>+E#rR8gslkJFHGE=nK<%c05B&fbmomVTL&tuCd4W7Z>IZL6Bh(5Z%H<3&BdQ za!oV9jKQt5gY`!O0MuHm@M2EgWNO1t;^K$4U9|WIkjgu@l}AwI&1tj*m_@FG62z=< z1csL+?#xTL4~8*x$oU3)c@;Tc=9z?0daBhB+o;3C|Ich0~^TN zPJSIONd>oy2fc%9XIUYBWhS(6LLyHv^x{d61Db}E%sbdea9u+z_IMLid$&-dT!F0X zw)T$B7gY=v?+ah)ZX}%ZGr1%13Mj*2@U5*{72m=iZ=v~+%WH!Oe~OgxfKdp6l+nro z&sySSlm@5B8DZ9>PY)Hd-rdq z^8Z8Vek!<6DGQrOkcmHGe@7PFPFC>vM1JHM6_pN*8vLtPm5!_d&IFAn+kHwpq#8gB6;OX@*M%FpaW5`qz&VND;j|(LTm&Q#Je4OyT2MR+a4@!ippPx z<^4l2@9Wjl@x%z?o3?RQtR!PivRZ@3M&9$*e9Y~`O_`CDXka!YXn$ZxEWx#v_oat# zmQr4E4XmE3XZNYnOQBP-85jy}-ifWH)VL2|tT3Y`yq%ezmT5+c-+s*2^p1~~C83b` z(0qM;)2qrj{+NCCVQ+U%eF=i>NO9dh5k#DJaPSo4U)lGr=Q4{_ zAH;=!Mdpy9iZ;5>*~HC!do)P%fXD)IUCL;Ftf$&JIXM8-TEGfTfh;A{%vJg0=dcz? zAfn!oB}}1=fR`_;K-CaxZ^f9${qjZKw*uXI9}i0l3-v`pQu0~OSA0Q02FYHAROUiN zgyfWm7=>cJHhN~6*M3CI$W3+nGz>vr#LU38x`IjL|NeW4#Lu%6J;3||CB?-bc?1E_ zLfmRPIwpzWMuS1WH`UQO2e}2=;@Wo0%bURYK{GKiDQ{i|ptdAQp079R^xxrjkG1{| zw`0}7b94}EU?a3&AjsT3Ji+nM$2)UyLlbf^qvxu3EAjQdGzEG~x;_?4GM0goNyqgM zW95;1T?QVqNMI{!Gv09HM$Zb<_nF7A_`k;3HjR$h-X-mgB)o%HkX|yB+THioe3$BSc!EqCaNp`FRohb)W zMB__Kar}OdUrjla@Hc3g+&k}P#mqtNw^5w_XISh%oA6khEnjUA_%S_v z3d8@Eu@^56xTDK9li%9{wxFzni0#nB9NFk>?J$etI&Wa67={amV6A>1o~{PZXvidV zGY${X>xwt0tD)s&(-AFIXYB@0)@VCM3>gmLCJsSaA}a%I5#CDq4je`E6DMwj@YN*t^A0Ki!f1bS}ndl<3CVe=X+au?+JYBCR| zX?L+IAt_LSrt8fDoV7>FywbVrrr=TBi_cnjrcxtAeU8eyL1N%o*AfzF0}4wh*|{Le ztXtuxzl%hW;x4GGbQ1Tj%>?#HUvd&dtf8^7Z1cpxAOqg0Ji(TM&$F|oZau?}L0Fxg z$eYMJ_G1hfiNNRY>^X8R%t^kz4~!}&yF|5dMh8xwKkwk^nBb4u(|X16@6Of{DA8t@ zy84@U_Dg{qWt(m*MlodRgy3sCM%y6__b&SLPmijpkpUkpWrp7_?l0tP_E+`XUfxFC zF8xqWN8>6{_1@+$x`+}yM$omIcv2v4C(9+1HQ4;g9G9E4J1Z+|eY@D^%^p?BKR*w0 zIc~Mq`q$4WmcG$OhK3iwniQsCIL;2>3}8FUu7amUvCTXVz^A0Pc2)D-63Wy4!b^IK zJgR!$18p_lWLHoPRy>^tUd04->kIm+Q?~&?y*n9S{q*^BGyLgo==+H69^7?bk{wQ- z{D`p0e0Y0Un8_+pell5E68IqaSFC7+P{1UY2Sou`p57wjFgfIHyL zyTKpsI0rHTNcwPi<4djBUH{J~3<74; zA3l7j9#R})I_X(6J2e#-9=<=F2k5Q^yH6f^M>bYeT!CriIvLW?&_>&*Lx2pTY#_&4 z!Jr923dk73myqlZpGh1@VS=>Y`Sz45Fg<-HLE%sc@}TR@g*luI!Kg!5c#G5dj3IP# zCZGY3_?ZO-1>OM#0I|;rQ+oeIg>%D`Rd@NMz9R6oi*Me%IWY%6c_TvX^WNGqKLb_Y z>B~Za5&_(*8og23`SNF^9>x2!P}i>VAS7`f?I@i{V5H73AY)OsaKbZ`vvD7@5n=o~ zq?(=}VV(8?{{F&f3&nFmQtAsB*PZTq_H>gZIO+yKzY2hcJh9WiOy^~4WE~gQ169A} z*~iv9$qGoXXD`Zf#US;yM-A4)+8i@ii7UmMi~DkB8KvMMgFL0(=&NHtWdTcl3=j7u zRGkN-v8kyZaOFIN5I)DI2aM4+C8gq5S5U^4AROw`NkgDky_b)VQnV+)c?GOD+ki!A zs!B`O`D5ApCXwbLm;4e=2m7glkGJ;=dn5jBSg`dle0)YCwFt4aQ8xe=QX@iGb|`js zJ#@2r$`s@S8(=G!7p#>h|LZ1k%uIUL-K)Ro6Mpo8F5EiI}DuM=jSWtg3c#N}mi5P8hXjA~cxQvS_JDbEz^HFx_3NP_; zx}xl27E`STMbb(M%b|*73GK4g`F_=V(=9m2v7#Nrn&4Y@+-d-Rq<|wIr z7dP#q3+3|i8N9qL&qy>1VqEN;8CW5a0(44W5l@KQ`V7O3dWJzS=jFFPL*}Y}dLITP z=W#KuK;Lv8U>wz2e#-Ud+*Pxrt^O+%2V<9NDZo)T&^3no`UOD(b7KS0=0G)Oo37T# zzyi(uR>*_j)Api&Tvc?qKpjFKZ9@mDvo;DyQBqVadR4M~vwzKe0KQ`C{0!hZVT1K}!rWBBCn@ z={!ow9=8*o1qjUU!J|zeeggvoT&4+be_T>h4h9Vav-DE-dctYdb#xqsv;~l$8H6Q< zHckQ8IQWpIeGgz&u1`a3y_GX#;ov+r%FNtN6q7=n&~XU}Yv86Nz)#X+7nsm;?8Yq< z>;;}P8uU%c7K`E41zE=JaEG9*r0?bp{X%%&1{{jYG^(2O{nZ-8 z1i_r7g>`mLE)4C4=C1HbSJ~-W>uVBU-al{ba~Q6>{(pgRqP`1TL%@gTKJ0 zMDX~?H?UzgBS?b1oz`FdOl!At=j}3{gT{7BjUVQmUR6I}_V^9$Ayr?8k(_nU5GC3Y z559wN7`RKwyxcdd(MJz=AyI{poY3^$Ll7><#hfrQK!+d?lptz4h=>NnX-#r!G2~#i zSA_(nA2aP-C`wsF>AmlNbseSiR(IftOyzXzQSliNY*+DZR{K;uyE{8+u+D|xdpd?+ zXGN1)7dSdjZ5*N=is% zzdB7w8fX+jTi=Kuh1tLH^xNuqc?(U@Lba_pCJpPS30?~?yw NplkdyOXt|R{{pi^f};Qc literal 0 HcmV?d00001 diff --git a/src/Mod/Ship/simRun/theory/images/Omega.svg b/src/Mod/Ship/simRun/theory/images/Omega.svg new file mode 100644 index 000000000..00c10c872 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/images/Omega.svg @@ -0,0 +1,206 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + δΩBottom + δΩFS + Ω + + + + + + + δΩInlet + δΩOutlet + + diff --git a/src/Mod/Ship/simRun/theory/images/Omega2.png b/src/Mod/Ship/simRun/theory/images/Omega2.png new file mode 100644 index 0000000000000000000000000000000000000000..0ebe7e232d050ece46bb94acb397485f45a808bf GIT binary patch literal 43277 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 literal 0 HcmV?d00001 diff --git a/src/Mod/Ship/simRun/theory/images/Omega2.svg b/src/Mod/Ship/simRun/theory/images/Omega2.svg new file mode 100644 index 000000000..c93a3d4fb --- /dev/null +++ b/src/Mod/Ship/simRun/theory/images/Omega2.svg @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + δΩBottom + δΩFS + Ω + + + δΩInlet + δΩOutlet + + + δΩFS,I + δΩFS,I + + diff --git a/src/Mod/Ship/simRun/theory/images/test_bem.png b/src/Mod/Ship/simRun/theory/images/test_bem.png new file mode 100644 index 0000000000000000000000000000000000000000..4d8d097bd329e42646f57e848bc0fc272eb06d58 GIT binary patch literal 49139 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

o#YXdEn`SyXgtZ?M8zwb-a(WUn4bzS+6C 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 D?UfMF literal 0 HcmV?d00001 diff --git a/src/Mod/Ship/simRun/theory/images/test_direct.png b/src/Mod/Ship/simRun/theory/images/test_direct.png new file mode 100644 index 0000000000000000000000000000000000000000..1e8e22e9e5032aa61f185692a4b9651a1b87b819 GIT binary patch literal 48587 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 literal 0 HcmV?d00001 diff --git a/src/Mod/Ship/simRun/theory/images/test_wave.png b/src/Mod/Ship/simRun/theory/images/test_wave.png new file mode 100644 index 0000000000000000000000000000000000000000..ac983211eb9f3ef5d89d50a2ad4ab4e370a1c97b GIT binary patch literal 66196 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

L+fl5_C@E&1DmBeUDu56I2y43wmd*M%I7a9N#<{ z@q=kZE>SC#hJNsl7p$=vYYR6AY5-usz(X95H>kze^JFdI{EM*@wQTPbdWNEGnM?TH?FnwX?HhHJ<%Q zHi|STEDSR{CueoHv{km$u=#M&V|lfk#K?8cLn58#=uIXaoM>@?{US}!<+mPO{Rhyp zvOZS-zC5|kfOI`-q!v5+^+yNFx}7rwwfV4N$xJ-F4W7?orJU9p;q3J3@| z-Jd7P&(EK!bD{^l1v#!yqsXJ%mT&DdiQ#KCwWng2DH)if0%aQ}CVTft- z3z^BAaN3y zS$FU9+0F!BUcwCaOPkNhHiy#+1>9HK zkh*$$)~1T}BG!Nv(Y4+eN7SRHriMpNZDcDG&)IT`y!Izronl~kSk~891OY)2$f%#7|yznGfX)C3@Fntjqkx(eVIh;kh57)9G@j6<0(v8yX}5x%J^l z7@@E2+!!|=ryfY9M=}LaJKu^)+nkrQM+@=?J~UTZxp9g5QUf!~ZMQXa`H}caz|Ld5 z!`)<~_g7-_f6L9}{ub+zuxb{yt#*cjNx{{~SChHEY4*7={S)=<@Z>}auo$t{{4WTCp|VcCJE|V1f{C7G7$jthhSSJct-=> z8uRAjfW-f5gX9<3Ai=S*v0z!kZd&-5nH3;3z;F;u6ZXQXoMro)VyN2o95V@ZwY)yI z{_LKB@r~o|onqzYI@!(x8l%MJ>Nc)!t~ASpUJCu$t=WV)p?E8^hgy}20u1h+Xq3eH z$^R+KUF-IZlu>AD_Xx%X|Htv??Z#Y~vRUu6>z#982ltn2xH|_=(51>bv&LRDJ>1{8 zFHcMbVBM$Whl;Z0U}9l4I&dm_dpDe3B2DL zCbZ8pyeP)h4PRQlySrHS0IfVp482DVa0p=DEGw&!bFho~OaI^%9UUf9JgQ4(k+lwY z-&)%UfuA)h9er^je{0O*XoF+E*cDD-!k1$5GCAVR$`!t#b1hsstG_q!;iXB(r$=Pw zD(A-SY7xMkf`JFQQidYd)Bze4|Bod`-dMtfiCkkl8>|@5!u&@^?TV38+xl}^>PFW8&I0_ETq`&y=`fG> ztu6y@)Lv7SI$-9##I31n=U;S7ueGSo@|IE1wfP{M)+W;Dz#ohNE~M-J98s2RbVsV7 zOPSY+MHDGFGC7}Z+jnO5Y=hoVY;tsJYHIxkR|TO9u!jDCu9rJ+DB8|epeZGC$N={Z z^gIGMq?bWAwQsM!K~sW?Nop0HfJ|jSyJ$G)ko|7hLKXrVQVwU@v`6Oe6u@I}}PUXMI%s702$)QXVP%ukc*+i5A3o zd-RumtK~wr%)aV2exOK

oxJb(TC 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 XJ%ogFwF \frac{\lambda}{2}$ we +can rewrite the phase velocity \ref{eq:laplace2D:c_general} as +% +\begin{eqnarray} + \label{eq:laplace2D:c_deep} + c_j^{deep} = \sqrt{\frac{g \lambda}{2 \pi}} +\end{eqnarray} +% +By definition the phase velocity can be also written as +$c_j = \omega_j / k_j$, so we can relate the wave length +with the period +% +\begin{eqnarray} + \label{eq:laplace2D:k_w} + k_j = \frac{\omega_j^2}{g} +\end{eqnarray} +% +Regarding the velocity potential, let us define it as +% +\begin{eqnarray} + \label{eq:laplace2D:incident_waves_potential} + \phi(x,z,t) = \sum_{j=1}^{n_{waves}} - \frac{a_j \omega_j}{k_j} + \cos\left(k_j x - \omega_j t + \delta_j \right) + \exp\left(k_j z\right) +\end{eqnarray} +% +such that +% +\begin{eqnarray*} + \begin{array}{rcl} + \dsty{\left. \frac{\partial \phi(x,z,t)}{\partial z} \right\vert_{z=0}} & = & v_z(x,t) + \\ + \laplacian \phi(x,z,t) & = & 0 + \end{array} +\end{eqnarray*} +% +This potential is valid for deep water waves if the exponent +$k_j z$ is small enough. $z$ can take values of the order of +$\mathcal{O}(a_j)$, so this method is valid for waves which +the length is such that +% +\begin{eqnarray*} + \lambda_j \gg 2 \pi a_j +\end{eqnarray*} +% +\section{BEM applied to Laplace 2D problem} +\label{ss:laplace2D:bem} +% +We have defined the sea waves outside from our computational domain +$\Omega$, where the waves can be perturbed by floating objects. In +the figure \ref{fig:ss:laplace2D:bem} a schematic view of the +computational domain is shown.\rc +% +The BEM is based in the reciprocal relation application +% +\begin{eqnarray} + \label{eq:laplace2D:reciprocal_relation} + \lambda(X, Z) \phi(X, Z; t) = \int_{\partial \Omega} + \phi(x, z; t) \frac{\partial G(x, z, X, Z)}{\partial \bs{n}(x, z)} - + G(x, z, X, Z) \frac{\partial \phi(x, z; t)}{\partial \bs{n}(x, z)} + \mbox{d} s(x, z) +\end{eqnarray} +% +Where +% +\begin{eqnarray*} +\lambda(X, Z) = \left\lbrace +\begin{array}{lcl} + 1 & \mbox{if} & (X, Z) \in \Omega + \\ + \frac{1}{2} & \mbox{if} & (X, Z) \in \partial \Omega + \\ + 0 & \mbox{if} & (X, Z) \not \in \Omega +\end{array} +\right. +\end{eqnarray*} +% +$G(x, z, X, Z)$ is the Green's function (a particular solution +of the Laplace equation), and the derivative respect to normal +denotes the gradient of the function projected over the normal. +% +\begin{eqnarray*} +\frac{\partial f(x, z)}{\partial \bs{n}(x, z)} = +\gradient f(x, z) \cdot \bs{n}(x, z) +\end{eqnarray*} +% +Hereinafter let we define the function $H(x, z, X, Z)$ as +% +\begin{eqnarray*} +H(x, z, X, Z) = \frac{\partial G(x, z, X, Z)}{\partial \bs{n}(x, z)} +\end{eqnarray*} +% +Therefore BEM allows to, knowing along the contour the potential or +the gradient, not both, compute the another one. The parts of the +contour where we know both potential and the gradient will enter in +the method as part of the independent term in the linear system of +equations.\rc +% +Since we know the potential out from the domain $\Omega$, we can know +the potential and the gradient along the inlet $\partial \Omega_{Inlet}$ +and outlet $\partial \Omega_{Outlet}$.\rc +% +Regarding the bottom, we only can assert that the gradient along the +normal, that is the vertical velocity of the fluid, is null.\rc +% +Therefore, the inlet and outlet have relatively good properties because +we know all the data, so will not be additional work into the linear +system matrix that must be inverted, but the bottom don't have this +desirable property.\rc +% +Nevertheless, since the geometry of the inlet and +outlet is different from the free surface, and the bottom must be +explicitly considered, all the contour must be discretized with an +undesirable computational cost associated.\rc +% +So we are interested to know if we can replace our computational +domain $\Omega$ for other where only the free surface contour is +involved, moving the Inlet, the Outlet, and the bottom infinity far. We +could change our computational domain if the Green's function, and their +gradient, goes to zero as we go far enough. In 2D we can found a Green's +function for the Laplace problem such that +% +\begin{eqnarray} + \label{eq:laplace2D:g} + G(x, z, X, Z) = & \dsty{\frac{1}{4 \pi}} \log \left( \left(x - X\right)^2 + \left(z - Z\right)^2 \right) + \\ + \label{eq:laplace2D:h} + H(x, z, X, Z) = & \dsty{\frac{1}{2 \pi}} \frac{\left( x - X, z - Z \right)}{\left( \left(x - X\right)^2 + \left(z - Z\right)^2 \right)} +\end{eqnarray} +% +Whose limits when the radius goes to infinite can be found +% +\begin{eqnarray} + \label{eq:laplace2D:limit_g} + \lim_{(x-X)^2 + (z-Z)^2 \to \infty} G(x, z, X, Z) = & \infty + \\ + \label{eq:laplace2D:limit_h} + \lim_{(x-X)^2 + (z-Z)^2 \to \infty} H(x, z, X, Z) = & 0 +\end{eqnarray} +% +So in the 2D Laplace problem, if we try to send the Inlet, the Outlet, +or the bottom to the infinite we can't use BEM because the Green's +function is not well defined, diverging with the distance. +% +\begin{figure}[ht!] + \centering + \includegraphics[width=0.4\textwidth]{Omega} + \caption{Computational domain $\Omega$} + \label{fig:ss:laplace2D:bem} +\end{figure} +% +\section{Conclusions to Laplace 2D problem} +\label{ss:laplace2D:conclusions} +% +We have briefly discussed the wave propagation problem using BEM in a 2D +case, seeing that in this case we need to consider all the contours, +including the Inlet, the Outlet, and the bottom. This approach is +successfully applied in a 2D problem in the reference \citep{vinayan2007}. +In 2D problem considering all the contours is not a heavy problem because +the number of nodes is usually small compared with a 3D case, but in a 3D +problem a computational less expensive method is required.\rc +% +We will not continue with the 2D Laplace problem because the solution will +not be useful for us in the 3D case. \ No newline at end of file diff --git a/src/Mod/Ship/simRun/theory/laplace3D.tex b/src/Mod/Ship/simRun/theory/laplace3D.tex new file mode 100644 index 000000000..96854c14b --- /dev/null +++ b/src/Mod/Ship/simRun/theory/laplace3D.tex @@ -0,0 +1,642 @@ +\chapter{Waves propagations in 3D} +\label{s:laplace3D} +% +\section{General} +% +In this chapter the 3D case will be discussed, looking for +a method to solve the BEM using only the information about +the free surface. +% +This case is our main objective in order to can setup 6-DOF +seakeeping simulations. +% +\section{Incident waves} +% +We can rewrite the sea waves system outside from our +computational domain $\Omega$ +% +\begin{eqnarray} + \label{eq:laplace3D:incident_waves} + \begin{array}{rcl} + z(x,y,t) & = & \dsty{\sum_{j=1}^{n_{waves}}} a_j \sin\left(k_j \left(x \cos(\beta) + y \sin(\beta)\right) - \omega_j t + \delta_j \right) + \\ + v_z(x,y,t) & = & \dsty{\sum_{j=1}^{n_{waves}}} - a_j \omega_j \cos\left(k_j \left(x \cos(\beta) + y \sin(\beta)\right) - \omega_j t + \delta_j \right) + \\ + \phi(x,z,t) & = & \dsty{\sum_{j=1}^{n_{waves}}} - \frac{a_j \omega_j}{k_j} + \cos\left(k_j \left(x \cos(\beta) + y \sin(\beta)\right) - \omega_j t + \delta_j \right) + \exp\left(k_j z\right) + \\ + k_j & = & \dsty{\frac{\omega_j^2}{g}} + \end{array} +\end{eqnarray} +% +Where $\beta$ is the heading angle, being 0 for stern waves. For +this wave system still being valid the phase velocity from the +equation \ref{eq:laplace2D:c_deep}. The purposed potential is +compatible with the Laplace equation +\ref{eq:governing_equations:laplace} as well. +% +\section{BEM applied to Laplace 3D problem} +\label{ss:laplace3D:bem} +% +\subsection{Computational domain} +\label{sss:laplace3D:computational_domain} +% +We have a domain similar to the shown in the figure +\ref{fig:ss:laplace2D:bem}, but in this case 2 more boundaries +must be considered in the missed direction, that we will call +$\partial \Omega_{Front}$ and $\partial \Omega_{Back}$. As in +the 2D case we will apply the reciprocal relation +% +\begin{eqnarray} + \label{eq:laplace3D:reciprocal_relation} + \lambda(X, Y, Z) \phi(X, Y, Z; t) = \int_{\partial \Omega} + \phi(x, y, z; t) \frac{\partial G(x, y, z, X, Y, Z)}{\partial \bs{n}(x, y, z)} - + G(x, y, z, X, Y, Z) \frac{\partial \phi(x, y, z; t)}{\partial \bs{n}(x, y, z)} + \mbox{d} s(x, y, z) +\end{eqnarray} +% +We are focused into compute the gradient of the velocity +potential along the free surface knowing the velocity +potential value in each point one. Let we define the +function $H(x,y,z,X,Y,Z)$ again +% +\begin{eqnarray*} +H(x, y, z, X, Y, Z) = \frac{\partial G(x, y, z, X, Y, Z)}{\partial \bs{n}(x, y, z)} +\end{eqnarray*} +% +As in the Laplace equation for the 2D case, described in the +chapter \ref{s:laplace2D}, we want to expand the domain $\Omega$ +such that all the boundaries except the free surface will the +infinity far, adding the boundary $\partial \Omega_{FS,I}$, where +we know the velocity potential and their gradient from +\ref{eq:laplace3D:incident_waves}. In the figure +\ref{fig:ss:laplace3D:bem} a schematic view of the expanded +domain can be seen.\rc +% +The main advantage is that, as happens with the Inlet and the +Outlet, we know all the needed data about the velocity potential, +so we can significantly reduce the linear system matrix dimensions, +and as happens with the bottom, the geometry is so quite similar +to the $\Omega_{FS}$ one, so no additional discretization or memory +storage is needed.\rc +% +This trick will only works if the Green's function $G(x,y,z,X,Y,Z)$, +and their gradient $H(x,y,z,X,Y,Z)$, goes to zero as $(x,y,z)$ goes +to infinite. In 3D Laplace problems we can use the following Green's +function: +% +\begin{eqnarray} + \label{eq:laplace3D:g} + G(x,y,z,X,Y,Z) = & \dsty{\frac{1}{\sqrt{\left(x - X\right)^2 + \left(y - Y\right)^2 + \left(z - Z\right)^2}}} + \\ + \label{eq:laplace3D:h} + H(x,y,z,X,Y,Z) = & - \dsty{\frac{\left( x - X, y - Y, z - Z \right)}{\left(\left(x - X\right)^2 + \left(y - Y\right)^2 + \left(z - Z\right)^2\right)^{3/2}}} +\end{eqnarray} +% +That in the limit +% +\begin{eqnarray} + \label{eq:laplace3D:limit_g} + \lim_{(x-X)^2 + (y-Y)^2 + (z-Z)^2 \to \infty} G(x,y,z,X,Y,Z) = & 0 + \\ + \label{eq:laplace3D:limit_h} + \lim_{(x-X)^2 + (y-Y)^2 + (z-Z)^2 \to \infty} H(x,y,z,X,Y,Z) = & 0 +\end{eqnarray} +% +So in this case, if the potential of the incidents waves is +a good function along all the free surface we can move from +the domain shown in the figure \ref{fig:ss:laplace2D:bem} to +the shown in the figure \ref{fig:ss:laplace3D:bem}, due to +along the other boundaries the Green's functions $G(x,y,z,X,Y,Z)$ +and $H(x,y,z,X,Y,Z)$ are nulls, not computing in the equation +\ref{eq:laplace2D:reciprocal_relation}. +% +\begin{figure}[ht!] + \centering + \includegraphics[width=0.6\textwidth]{Omega2} + \caption{Computational domain $\Omega$} + \label{fig:ss:laplace3D:bem} +\end{figure} +% +\subsection{Boundary conditions (BC)} +\label{sss:laplace3D:BC} +% +In order to can purpose an evolution process we need to use +the boundary conditions along the free surface. In the most +general way we can rewrite the Bernoulli equation, that is +the dynamic free surface boundary condition (DFSBC), as (see +\citep{yang2004}): +% +\begin{eqnarray} + \label{eq:laplace3D:FS_Bernoulli} + \frac{\mbox{D} \phi(x,y,z;t)}{\mbox{D} t} = + \frac{1}{2}\left\vert \gradient \phi \right\vert^2 + - g z(x,y;t) + - \frac{p_0}{\rho} + - \bs{U}(t) \cdot \gradient \phi(x,y,z;t) + - \frac{\partial \bs{U}(t)}{\partial t} \cdot (x,y,0) +\end{eqnarray} +% +Where $p_0$ is the atmospheric pressure, that we will consider +null, and $\bs{U}(t)$ is the ship velocity, in this case will be +a null vector. Since the material derivative denotes +% +\begin{eqnarray*} + \frac{\mbox{D} f}{\mbox{D} t} = + \frac{\partial f}{\partial t} + \gradient{\phi(x,y,z;t)} \cdot \gradient{f} +\end{eqnarray*} +% +We can rewrite the dynamic boundary condition for this specific case as +% +\begin{eqnarray} + \label{eq:laplace3D:DFSBC} + \frac{\partial \phi(x,y,z;t)}{\partial t} = + - \frac{1}{2}\left\vert \gradient \phi \right\vert^2 + - g z(x,y;t) +\end{eqnarray} +% +Regarding the kinematic free surface boundary condition (KFSBC), in the +most general way we can write that +% +\begin{eqnarray} + \label{eq:laplace3D:FS_Kinematic} + \frac{\mbox{D} z(x,y;t)}{\mbox{D} t} = + \frac{\partial \phi(x,y,z;t)}{\partial z} + - \bs{U}(t) \cdot \gradient z(x,y;t) +\end{eqnarray} +% +Where we can expand the material derivative, writing the KFSBC for this +specific case +% +\begin{eqnarray} + \label{eq:laplace3D:KFSBC} + \frac{\partial z(x,y;t)}{\partial t} = + \frac{\partial \phi(x,y,z;t)}{\partial z} + - \gradient{\phi(x,y,z;t)} \cdot \gradient{z(x,y;t)} +\end{eqnarray} +% +\subsection{Time integration scheme} +\label{sss:laplace3D:TimeIntegration} +% +We may start the simulation in a initial condition where we know the +full free surface shape and velocity potential, including the gradients. +% +\begin{eqnarray} + \label{eq:laplace3D:IC} + \begin{array}{lcl} + z(x,y;t=0) & = & z_0(x,y) + \\ + \phi(x,y,z;t=0) & = & \phi_0(x,y,z) + \\ + \gradient z(x,y;t=0) & = & \gradient z_0(x,y) + \\ + \gradient \phi(x,y,z;t=0) & = & \gradient \phi_0(x,y,z) + \end{array} +\end{eqnarray} +% +In the computational part of the free surface is enough to know the free +surface shape $z_0(x,y)$ and the velocity potential $\phi_0(x,y,z)$.\rc +% +For simplicity we will use an Euler's integration scheme, but the same +method can be easily applied for any other explicit time integrator, like +the Adams-Bashforth ones.\rc +% +In each time step we start knowing the shape of the free surface, and the +velocity potential, and basically we want to compute these fields for the +next time step. To do it the following steps are followed: +% +\begin{enumerate} + \item We use BEM to compute the velocity potential gradient, as will be + described in the section \ref{sss:laplace3D:bem_solve}. + \begin{eqnarray} + \label{eq:laplace3D:time_march:bem} + \gradient{\phi(x,y,z;t)} = \mbox{BEM}\left(\phi(x,y,z;t), z(x,y;t)\right) + \end{eqnarray} + \item We use the KFSBC to compute the derivative of the free surface + elevation, and the DFSBC to know the derivative of the velocity potential. + \begin{eqnarray} + \label{eq:laplace3D:time_march:dzdt} + \frac{\partial z(x,y;t)}{\partial t} = & + \mbox{KFSBC}\left(\gradient{\phi(x,y,z;t)}\right) + \\ + \label{eq:laplace3D:time_march:dphidt} + \frac{\partial \phi(x,y,z;t)}{\partial t} = & + \mbox{DFSBC}\left(z(x,y;t), \gradient{\phi(x,y,z;t)}\right) + \end{eqnarray} + \item And then we can perform the time integration. + \begin{eqnarray} + \label{eq:laplace3D:time_march:z_integrate} + z(x,y;t + \Delta t) = & + z(x,y;t) + + \Delta t \dsty \frac{\partial z(x,y;t)}{\partial t} + \\ + \label{eq:laplace3D:time_march:phi_integrate} + \phi(x,y,z;t + \Delta t) = & + \phi(x,y,z;t + \Delta t) + + \Delta t \dsty \frac{\partial \phi(x,y,z;t)}{\partial t} + \end{eqnarray} +\end{enumerate} +% +\subsection{Discrete Laplace solution using the BEM} +\label{sss:laplace3D:bem_solve} +% +As we have seen in the previous sections we want to use the BEM in order +to compute the velocity potential gradient in the free surface from the +velocity potential value known. In the equation +\ref{eq:laplace3D:reciprocal_relation} we can starting dividing the domain +contour as shown in the figure \ref{fig:ss:laplace3D:bem}, getting the +computational one, denoted by $\partial \Omega_{FS}$, and +the extension one, denoted by $\partial \Omega_{FS,I}$, where the free +surface and the velocity potential and gradient is known for all the +time instants. +% +\begin{eqnarray} + \label{eq:laplace3D:reciprocal_relation:002} + \begin{array}{l} + \frac{1}{2} \phi(X, Y, Z; t) = + \\ + \dsty \int_{\partial \Omega_{FS}} + \phi(x, y, z; t) \frac{\partial G(x, y, z, X, Y, Z)}{\partial \bs{n}(x, y, z)} - + G(x, y, z, X, Y, Z) \frac{\partial \phi(x, y, z; t)}{\partial \bs{n}(x, y, z)} + \mbox{d} s(x, y, z) + \\ + \dsty \int_{\partial \Omega_{FS,I}} + \phi(x, y, z; t) \frac{\partial G(x, y, z, X, Y, Z)}{\partial \bs{n}(x, y, z)} - + G(x, y, z, X, Y, Z) \frac{\partial \phi(x, y, z; t)}{\partial \bs{n}(x, y, z)} + \mbox{d} s(x, y, z) + \end{array} +\end{eqnarray} +% +Where we already assumed that $(x,y,z) \in \partial \Omega$. We can start discretizing +the velocity potential, assuming that the potential and their gradient changes smoothly +enough. The our contours can be divided according to the grid: +% +\begin{eqnarray} + \label{eq:laplace3D:reciprocal_relation:003} + \begin{array}{rl} + \frac{1}{2} \phi_a = & + \dsty \sum_{b=1}^{n_{FS}} + \phi_b + \dsty \int_{\partial \Omega_{FS}^b} H(\bs{x}, \bs{x}_a) \mbox{d} s(\bs{x}) + - + \dsty \sum_{b=1}^{n_{FS}} + \frac{\partial \phi_b}{\partial \bs{n}_b} + \dsty \int_{\partial \Omega_{FS}^b} G(\bs{x}, \bs{x}_a) \mbox{d} s(\bs{x}) + \\ + & + \dsty \sum_{b=1}^{n_{FS,I}} + \phi_b + \dsty \int_{\partial \Omega_{FS,I}^b} H(\bs{x}, \bs{x}_a) \mbox{d} s(\bs{x}) + - + \dsty \sum_{b=1}^{n_{FS,I}} + \frac{\partial \phi_b}{\partial \bs{n}_b} + \dsty \int_{\partial \Omega_{FS,I}^b} G(\bs{x}, \bs{x}_a) \mbox{d} s(\bs{x}) + \end{array} +\end{eqnarray} +% +The functions $G(x,y,z,X,Y,Z)$ and $H(x,y,z,X,Y,Z)$, according to the equations +\ref{eq:laplace3D:g} and \ref{eq:laplace3D:h}, are well defined in all the +subintervals where $(x,y,z) \neq (X,Y,Z)$, and are so quite smooth, so we will +change all the integrals that accomplish it for point evaluations. +% +\begin{eqnarray} + \label{eq:laplace3D:reciprocal_relation:004} + \begin{array}{rl} + \frac{1}{2} \phi_a = & + \phi_a + \dsty \int_{\partial \Omega_{FS}^a} H(\bs{x}, \bs{x}_a) \mbox{d} s(\bs{x}) + - + \frac{\partial \phi_a}{\partial \bs{n}_a} + \dsty \int_{\partial \Omega_{FS}^a} G(\bs{x}, \bs{x}_a) \mbox{d} s(\bs{x}) + \\ + & + \dsty \sum_{\substack{b = 1 \\ b \neq a}}^{n_{FS}} + \left( + \phi_b H_{ba} - \frac{\partial \phi_b}{\partial \bs{n}_b} G_{ba} + \right) S_b + + + \dsty \sum_{b=1}^{n_{FS,I}} + \left( + \phi_b H_{ba} - \frac{\partial \phi_b}{\partial \bs{n}_b} G_{ba} + \right) S_b + \end{array} +\end{eqnarray} +% +The remaining integrals must be treated carefully since the functions are +singular in the center of the interval. $H(x,y,z,X,Y,Z)$ is an odd function, +so the limit of the integral when the radius of the interval goes to zero +is null, being well defined. Regarding the function $G(x,y,z,X,Y,Z)$ is an +even function of order: +% +\begin{eqnarray*} + G(\bs{x},\bs{x_a}) = \mathcal{O}\left(\frac{1}{\vert \bs{x} - \bs{x_a}\vert}\right) +\end{eqnarray*} +% +Which their integral is defined if the function $z(x,y)$ is well defined +as well. So the remaining integrals can be numerically computed, being mindful +that: +% +\begin{enumerate} + \item Can't be evaluated at the point $\bs{x_a}$. + \item Changes too fast around the point $\bs{x_a}$. +\end{enumerate} +% +We will discuss later how to solve this integrals, for the moment we will define +new functions such that: +% +\begin{eqnarray} + \label{eq:laplace3D:g:hat} + \hat G_{ab} = + \left\lbrace \begin{array}{l} + \dsty \int_{\partial \Omega_{FS}^a} G(\bs{x}, \bs{x}_a) \mbox{d} s(\bs{x}); \, \, \mbox{if} \, a = b + \\ + G(\bs{x_b},\bs{x_a}) S_b; \, \, \mbox{if} \, a \neq b + \end{array} \right. + \\ + \label{eq:laplace3D:h:hat} + \hat H_{ab} = + \left\lbrace \begin{array}{l} + \dsty \int_{\partial \Omega_{FS}^a} H(\bs{x}, \bs{x}_a) \mbox{d} s(\bs{x}); \, \, \mbox{if} \, a = b + \\ + H(\bs{x_b},\bs{x_a}) S_b; \, \, \mbox{if} \, a \neq b + \end{array} \right. +\end{eqnarray} +% +So we can rewrite the equation \ref{eq:laplace3D:reciprocal_relation:004} +% +\begin{eqnarray} + \label{eq:laplace3D:reciprocal_relation:005} + \frac{1}{2} \phi_a + = + \dsty \sum_{b=1}^{n_{FS}} + \left( + \phi_b \hat H_{ba} - \frac{\partial \phi_b}{\partial \bs{n}_b} \hat G_{ba} + \right) + + + \dsty \sum_{b=1}^{n_{FS,I}} + \left( + \phi_b \hat H_{ba} - \frac{\partial \phi_b}{\partial \bs{n}_b} \hat G_{ba} + \right) +\end{eqnarray} +% +Where we can move all the terms of the computational free surface that affects +to the gradient of the velocity potential (that is the value that we want to +compute) to left hand side, and let all the other ones in the right hand side +of the equation +% +\begin{eqnarray} + \label{eq:laplace3D:reciprocal_relation:006} + \dsty \sum_{b \in \partial \Omega_{FS}} + \frac{\partial \phi_b}{\partial \bs{n}_b} \hat G_{ba} + = + - + \frac{1}{2} \phi_a + + + \dsty \sum_{b \in \partial \Omega_{FS}} + \phi_b \hat H_{ba} + + + \dsty \sum_{b \in \partial \Omega_{FS,I}} + \left( + \phi_b \hat H_{ba} - + \frac{\partial \phi_b}{\partial \bs{n}_b} \hat G_{ba} + \right) +\end{eqnarray} +% +The equation \ref{eq:laplace3D:reciprocal_relation:006}, that +has been written for the velocity potential at one point $\bs{x}_a$, +can be written for all the points of the free surface along +the computational domain using the matrix notation +% +\begin{eqnarray} + \label{eq:laplace3D:reciprocal_relation:007} + \mathcal{G} \left[ \frac{ \partial \phi}{\partial \bs{n}} \right] + = + \left( \mathcal{H} - \frac{1}{2} \mathcal{I} \right) \left[ \phi \right] + + + \mathcal{H}_{FS,I} \left[ \phi \right]_{FS,I} + - + \mathcal{G}_{FS,I} \left[ \frac{ \partial \phi}{\partial \bs{n}} \right]_{FS,I} +\end{eqnarray} +% +Note that the area of the elements $S_b$ has been included into +the matrices. The equation +\ref{eq:laplace3D:reciprocal_relation:007} is a linear system +of equations that can be numerically solved, either inverting +the matrix, or using an iterative method. The matrix inversion +is probably the best way for linear seakeeping codes, where the +same matrix will be ever used, but in this case the iterative +method is the faster way.\rc +% +The method described along this section allows to us to compute +the gradient of the velocity potential along the free surface +knowing the potential in the computational free surface, and both +velocity potential and the gradient along the extended free +surface. +% +\subsection{Integrals computation} +\label{sss:laplace3D:integrals} +% +In the equations \ref{eq:laplace3D:g:hat} and \ref{eq:laplace3D:g:hat} +we have introduced two inconvenient integrals. Even though the functions +are not well defined when $\bs{x} = \bs{x_a}$, their integrals it is. +For instance, if we can assume that the free surface is fully planar +($z = 0$), the integrals can be analytically computed +% +\begin{eqnarray*} + \dsty \int_{y_a - \delta y}^{y_a + \delta y} \int_{x_a - \delta x}^{x_a + \delta x} + G(x,y,0,x_a,y_a,0) + \, \mbox{d}x \, \mbox{d}y + = & + \dsty \frac{ + \delta x \, \, \mbox{asinh}\left(\frac{\delta y}{\delta x}\right) + + + \delta y \, \, \mbox{asinh}\left(\frac{\delta x}{\delta y}\right) + }{\pi} + \\ + \dsty \int_{y_a - \delta y}^{y_a + \delta y} \int_{x_a - \delta x}^{x_a + \delta x} + H(x,y,0,x_a,y_a,0) + \, \mbox{d}x \, \mbox{d}y + = & + 0 +\end{eqnarray*} +% +But can not be analytically computed for every function $z(x,y)$, being +necessary to compute it in a numerical way.\rc +% +In the figure \ref{fig:ss:laplace3D:integral} a schematic representation +of the integration method is shown. Let we want to compute the integral +for an element of the grid $(x_a,y_a)$, then we subdivide the element in +\textbf{a even number} of subelements of area $dx \cdot dy$, so we can +assert that any subelement will be evaluated in the point $(x_a,y_a)$, +but as near as we want because we can ever add more subelements; then we +can numerically approximate the integral by (here in after we will use +only the function $G(\bs{x}, bs{x_a})$, because same method can be applied +to the function $H(\bs{x}, bs{x_a})$). +% +\begin{eqnarray} + \label{eq:laplace3D:integral:g} + \dsty \int_{\partial \Omega_{FS}^a} G(\bs{x}, \bs{x}_a) \mbox{d} s(\bs{x}) + \simeq + \sum_{i=1}^{n_x} \sum_{j=1}^{n_y} G(x_i,y_j,z(x_i,y_i), x_a, y_a, z(x_a, y_a)) \, dx \, dy +\end{eqnarray} +% +Of course the value $z(x_a, y_a)$ is known, but not the function $z(x_i,y_i)$ +because is evaluated in points that are not reflected in the grid, so we must +compute this points from the available data. We will start renormalizing the +coordinates such that: +% +\begin{eqnarray} + \label{eq:laplace3D:integral:uv} + \begin{array}{lcl} + u & = & \dsty \frac{x - \left(x_a - Dx\right)}{2 Dx} + \\ + v & = & \dsty \frac{y - \left(y_a - Dy\right)}{2 Dy} + \end{array} +\end{eqnarray} +% +So we know the value of $z$ for all the combinations of $u = 0,0.5,1$ and +$v = 0,0.5,1$. Then, to can evaluate the function $z(u,v)$ for all $u,v$ +values we may to build a Spline surface with the data known from the 9 +points shown in the figure \ref{fig:ss:laplace3D:integral}. The Spline +surface can be characterized as +% +\begin{eqnarray} + \label{eq:laplace3D:integral:spline} + z(u,v) = k_0 + k_u u + k_v v + k_{uv} u v + k_{uu} u^2 + k_{vv} v^2 + + k_{uuv} u^2 v + k_{uvv} u v^2 + k_{uuvv} u^2 v^2 +\end{eqnarray} +% +In the equation \ref{eq:laplace3D:integral:spline} we have 9 unknown +coefficients, but we have available $z(u,v)$ for 9 points, so have 9 +unknowns with 9 equations that can be set as a linear system of +equations, that results in the following coefficients: +% +\begin{eqnarray} + \label{eq:laplace3D:integral:k} + \begin{array}{lcl} + k_0 & = & z \left( 0,0 \right) + \\ + k_u & = & - z \left( 1,0 \right) + 4 z \left( \frac{1}{2},0 \right) - 3 z \left( 0,0 \right) + \\ + k_v & = & - z \left( 0,1 \right) + 4 z \left( 0,\frac{1}{2} \right) - 3 z \left( 0,0 \right) + \\ + k_{uv} & = & z \left( 1,1 \right) - 4 z \left( 1,\frac{1}{2} \right) + 3 z \left( 1,0 \right) + - 4 z \left( \frac{1}{2},1 \right) + 16 z \left( \frac{1}{2},\frac{1}{2} \right) + \\ & & + - 12 z \left( \frac{1}{2},0 \right) + 3 z \left( 0,1 \right) + - 12 z \left( 0,\frac{1}{2} \right) + 9 z \left( 0,0 \right) + \\ + k_{uu} & = & 2 z \left( 1,0 \right) - 4 z \left( \frac{1}{2},0 \right) + 2 z \left( 1,0 \right) + \\ + k_{vv} & = & 2 z \left( 0,1 \right) - 4 z \left( 0,\frac{1}{2} \right) + 2 z \left( 1,0 \right) + \\ + k_{uuv} & = & - 2 z \left( 1,1 \right) + 8 z \left( 1,\frac{1}{2} \right) - 6 z \left( 1,0 \right) + + 4 z \left( \frac{1}{2},1 \right) - 16 z \left( \frac{1}{2},\frac{1}{2} \right) + \\ & & + + 12 z \left( \frac{1}{2},0 \right) - 2 z \left( 0,1 \right) + + 8 z \left( 0,\frac{1}{2} \right) - 6 z \left( 0,0 \right) + \\ + k_{uvv} & = & - 2 z \left( 1,1 \right) + 4 z \left( 1,\frac{1}{2} \right) - 2 z \left( 1,0 \right) + + 8 z \left( \frac{1}{2},1 \right) - 16 z \left( \frac{1}{2},\frac{1}{2} \right) + \\ & & + + 8 z \left( \frac{1}{2},0 \right) - 6 z \left( 0,1 \right) + + 12 z \left( 0,\frac{1}{2} \right) - 6 z \left( 0,0 \right) + \\ + k_{uuvv} & = & 4 z \left( 1,1 \right) - 8 z \left( 1,\frac{1}{2} \right) + 4 z \left( 1,0 \right) + - 8 z \left( \frac{1}{2},1 \right) + 16 z \left( \frac{1}{2},\frac{1}{2} \right) + \\ & & + - 8 z \left( \frac{1}{2},0 \right) + 4 z \left( 0,1 \right) + - 8 z \left( 0,\frac{1}{2} \right) + 4 z \left( 0,0 \right) + \end{array} +\end{eqnarray} +% +So using the equation \ref{eq:laplace3D:integral:g} to \ref{eq:laplace3D:integral:k} +we can compute the integrals in the equations \ref{eq:laplace3D:g:hat} and +\ref{eq:laplace3D:h:hat}. +% +\begin{figure}[ht!] + \centering + \includegraphics[width=0.6\textwidth]{Integral} + \caption{Integration method scheme} + \label{fig:ss:laplace3D:integral} +\end{figure} +% +\section{BEM test} +\label{ss:laplace3D:test} +% +\subsection{General} +\label{sss:laplace3D:test:general} +% +A Python script has been provided with this document in the subfolder \textbf{test}. +In the script all this theory is tested in order to know if the BEM is well purposed, +and the errors that can be expected from the method application.\rc +% +In the test, for the moment, only one wave will be set, and the computational free +surface will be big enough to contain 2 wave lengths. In this case a wave period +of $T = 2.5 s$ is used, resulting in a wave of 10 meters.\rc +% +In the figure \ref{fig:laplace3D:test:wave} the wave used, that runs in the x direction, +is shown. The free surface will be extended while $G(x,y,z,X,Y,Z) > 0.1$. +% +\begin{figure}[ht!] + \centering + \includegraphics[width=0.6\textwidth]{test_wave} + \caption{Wave used in the test} + \label{fig:laplace3D:test:wave} +\end{figure} +% +\subsection{Direct method} +\label{sss:laplace3D:test:direct} +% +The direct method consist in evaluate the velocity potential in several points +using the equation \ref{eq:laplace3D:reciprocal_relation:005}, testing the error +get.\rc +% +If we apply the direct method for all the points of the computational free surface, +we can compute the root mean square error as +% +\begin{eqnarray*} + RMS(nx,ny) = \sqrt{\frac{1}{nx \, ny} \sum_{i=1}^{nx} \sum_{j=1}^{ny} + \left( \phi_{direct}(x_i,y_j) - \phi(x_i,y_j) \right)^2 + } +\end{eqnarray*} +% +For $nx = 31$ and $ny = 15$ we have $RMS(31,15) = 0.08$. In the figure +\ref{fig:laplace3D:test:direct} the analytic velocity potential, and the +interpolated using the direct method, for a slice in the middle of the +free surface ($y=0$).\rc +% +The results quality is good, and can be improved increasing the number of +points in the computational free surface. +% +\begin{figure}[ht!] + \centering + \includegraphics[width=0.6\textwidth]{test_direct} + \caption{Direct method} + \label{fig:laplace3D:test:direct} +\end{figure} +% +\subsection{BEM} +\label{sss:laplace3D:test:bem} +% +In this case we want to apply the equation \ref{eq:laplace3D:reciprocal_relation:006}, +where a linear system of equations is purposed in order to compute the gradient of the +velocity potential, projected over the normal, for all the points of the grid. +% +For $nx = 31$ and $ny = 15$ we have $RMS(31,15) = 0.04$. In the figure +\ref{fig:laplace3D:test:bem} the analytic velocity potential, and the +interpolated using the direct method, for a slice in the middle of the +free surface ($y=0$).\rc +% +The results quality is nice like in the direct method. In order to get enough good +results at least 15 points per wave length must be used (like in this application). +% +\begin{figure}[ht!] + \centering + \includegraphics[width=0.6\textwidth]{test_bem} + \caption{BEM solution} + \label{fig:laplace3D:test:bem} +\end{figure} +% \ No newline at end of file diff --git a/src/Mod/Ship/simRun/theory/main.aux b/src/Mod/Ship/simRun/theory/main.aux new file mode 100644 index 000000000..e21f47e16 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/main.aux @@ -0,0 +1,125 @@ +\relax +\bibstyle{plainnat} +\providecommand\HyperFirstAtBeginDocument{\AtBeginDocument} +\HyperFirstAtBeginDocument{\ifx\hyper@anchor\@undefined +\global\let\oldcontentsline\contentsline +\gdef\contentsline#1#2#3#4{\oldcontentsline{#1}{#2}{#3}} +\global\let\oldnewlabel\newlabel +\gdef\newlabel#1#2{\newlabelxx{#1}#2} +\gdef\newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}} +\AtEndDocument{\ifx\hyper@anchor\@undefined +\let\contentsline\oldcontentsline +\let\newlabel\oldnewlabel +\fi} +\fi} +\global\let\hyper@last\relax +\gdef\HyperFirstAtBeginDocument#1{#1} +\providecommand\HyField@AuxAddToFields[1]{} +\citation{bem_2007} +\citation{vinayan2007} +\@writefile{toc}{\contentsline {chapter}{\numberline {1}Introduction}{5}{chapter.1}} +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{s:introduction}{{1}{5}{Introduction\relax }{chapter.1}{}} +\@writefile{toc}{\contentsline {section}{\numberline {1.1}Objective}{5}{section.1.1}} +\citation{bem_2007} +\@writefile{toc}{\contentsline {chapter}{\numberline {2}Governing equations}{7}{chapter.2}} +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{s:governing_equations}{{2}{7}{Governing equations\relax }{chapter.2}{}} +\newlabel{eq:governing_equations:v_potential}{{2.2}{7}{Governing equations\relax }{equation.2.0.2}{}} +\newlabel{eq:governing_equations:laplace}{{2.3}{7}{Governing equations\relax }{equation.2.0.3}{}} +\newlabel{eq:governing_equations:bernoulli}{{2.4}{7}{Governing equations\relax }{equation.2.0.3}{}} +\@writefile{toc}{\contentsline {chapter}{\numberline {3}Waves propagations in 2D plane}{9}{chapter.3}} +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{s:laplace2D}{{3}{9}{Waves propagations in 2D plane\relax }{chapter.3}{}} +\@writefile{toc}{\contentsline {section}{\numberline {3.1}General}{9}{section.3.1}} +\@writefile{toc}{\contentsline {section}{\numberline {3.2}Incident waves}{9}{section.3.2}} +\newlabel{eq:laplace2D:incident_waves}{{3.1}{9}{Incident waves\relax }{equation.3.2.1}{}} +\newlabel{eq:laplace2D:c_general}{{3.2}{9}{Incident waves\relax }{equation.3.2.2}{}} +\newlabel{eq:laplace2D:c_deep}{{3.3}{9}{Incident waves\relax }{equation.3.2.3}{}} +\newlabel{eq:laplace2D:k_w}{{3.4}{9}{Incident waves\relax }{equation.3.2.4}{}} +\newlabel{eq:laplace2D:incident_waves_potential}{{3.5}{9}{Incident waves\relax }{equation.3.2.5}{}} +\@writefile{toc}{\contentsline {section}{\numberline {3.3}BEM applied to Laplace 2D problem}{10}{section.3.3}} +\newlabel{ss:laplace2D:bem}{{3.3}{10}{BEM applied to Laplace 2D problem\relax }{section.3.3}{}} +\newlabel{eq:laplace2D:reciprocal_relation}{{3.6}{10}{BEM applied to Laplace 2D problem\relax }{equation.3.3.6}{}} +\citation{vinayan2007} +\newlabel{eq:laplace2D:g}{{3.7}{11}{BEM applied to Laplace 2D problem\relax }{equation.3.3.7}{}} +\newlabel{eq:laplace2D:h}{{3.8}{11}{BEM applied to Laplace 2D problem\relax }{equation.3.3.7}{}} +\newlabel{eq:laplace2D:limit_g}{{3.9}{11}{BEM applied to Laplace 2D problem\relax }{equation.3.3.9}{}} +\newlabel{eq:laplace2D:limit_h}{{3.10}{11}{BEM applied to Laplace 2D problem\relax }{equation.3.3.9}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {3.1}{\ignorespaces Computational domain $\Omega $}}{11}{figure.3.1}} +\newlabel{fig:ss:laplace2D:bem}{{3.1}{11}{Computational domain $\Omega $\relax }{figure.3.1}{}} +\@writefile{toc}{\contentsline {section}{\numberline {3.4}Conclusions to Laplace 2D problem}{11}{section.3.4}} +\newlabel{ss:laplace2D:conclusions}{{3.4}{11}{Conclusions to Laplace 2D problem\relax }{section.3.4}{}} +\@writefile{toc}{\contentsline {chapter}{\numberline {4}Waves propagations in 3D}{13}{chapter.4}} +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{s:laplace3D}{{4}{13}{Waves propagations in 3D\relax }{chapter.4}{}} +\@writefile{toc}{\contentsline {section}{\numberline {4.1}General}{13}{section.4.1}} +\@writefile{toc}{\contentsline {section}{\numberline {4.2}Incident waves}{13}{section.4.2}} +\newlabel{eq:laplace3D:incident_waves}{{4.1}{13}{Incident waves\relax }{equation.4.2.1}{}} +\@writefile{toc}{\contentsline {section}{\numberline {4.3}BEM applied to Laplace 3D problem}{13}{section.4.3}} +\newlabel{ss:laplace3D:bem}{{4.3}{13}{BEM applied to Laplace 3D problem\relax }{section.4.3}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.3.1}Computational domain}{13}{subsection.4.3.1}} +\newlabel{sss:laplace3D:computational_domain}{{4.3.1}{13}{Computational domain\relax }{subsection.4.3.1}{}} +\newlabel{eq:laplace3D:reciprocal_relation}{{4.2}{13}{Computational domain\relax }{equation.4.3.2}{}} +\citation{yang2004} +\newlabel{eq:laplace3D:g}{{4.3}{14}{Computational domain\relax }{equation.4.3.3}{}} +\newlabel{eq:laplace3D:h}{{4.4}{14}{Computational domain\relax }{equation.4.3.3}{}} +\newlabel{eq:laplace3D:limit_g}{{4.5}{14}{Computational domain\relax }{equation.4.3.5}{}} +\newlabel{eq:laplace3D:limit_h}{{4.6}{14}{Computational domain\relax }{equation.4.3.5}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {4.1}{\ignorespaces Computational domain $\Omega $}}{14}{figure.4.1}} +\newlabel{fig:ss:laplace3D:bem}{{4.1}{14}{Computational domain $\Omega $\relax }{figure.4.1}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.3.2}Boundary conditions (BC)}{14}{subsection.4.3.2}} +\newlabel{sss:laplace3D:BC}{{4.3.2}{14}{Boundary conditions (BC)\relax }{subsection.4.3.2}{}} +\newlabel{eq:laplace3D:FS_Bernoulli}{{4.7}{14}{Boundary conditions (BC)\relax }{equation.4.3.7}{}} +\newlabel{eq:laplace3D:DFSBC}{{4.8}{15}{Boundary conditions (BC)\relax }{equation.4.3.8}{}} +\newlabel{eq:laplace3D:FS_Kinematic}{{4.9}{15}{Boundary conditions (BC)\relax }{equation.4.3.9}{}} +\newlabel{eq:laplace3D:KFSBC}{{4.10}{15}{Boundary conditions (BC)\relax }{equation.4.3.10}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.3.3}Time integration scheme}{15}{subsection.4.3.3}} +\newlabel{sss:laplace3D:TimeIntegration}{{4.3.3}{15}{Time integration scheme\relax }{subsection.4.3.3}{}} +\newlabel{eq:laplace3D:IC}{{4.11}{15}{Time integration scheme\relax }{equation.4.3.11}{}} +\newlabel{eq:laplace3D:time_march:bem}{{4.12}{15}{Time integration scheme\relax }{equation.4.3.12}{}} +\newlabel{eq:laplace3D:time_march:dzdt}{{4.13}{15}{Time integration scheme\relax }{equation.4.3.13}{}} +\newlabel{eq:laplace3D:time_march:dphidt}{{4.14}{15}{Time integration scheme\relax }{equation.4.3.13}{}} +\newlabel{eq:laplace3D:time_march:z_integrate}{{4.15}{15}{Time integration scheme\relax }{equation.4.3.15}{}} +\newlabel{eq:laplace3D:time_march:phi_integrate}{{4.16}{15}{Time integration scheme\relax }{equation.4.3.15}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.3.4}Discrete Laplace solution using the BEM}{16}{subsection.4.3.4}} +\newlabel{sss:laplace3D:bem_solve}{{4.3.4}{16}{Discrete Laplace solution using the BEM\relax }{subsection.4.3.4}{}} +\newlabel{eq:laplace3D:reciprocal_relation:002}{{4.17}{16}{Discrete Laplace solution using the BEM\relax }{equation.4.3.17}{}} +\newlabel{eq:laplace3D:reciprocal_relation:003}{{4.18}{16}{Discrete Laplace solution using the BEM\relax }{equation.4.3.18}{}} +\newlabel{eq:laplace3D:reciprocal_relation:004}{{4.19}{16}{Discrete Laplace solution using the BEM\relax }{equation.4.3.19}{}} +\newlabel{eq:laplace3D:g:hat}{{4.20}{16}{Discrete Laplace solution using the BEM\relax }{equation.4.3.20}{}} +\newlabel{eq:laplace3D:h:hat}{{4.21}{16}{Discrete Laplace solution using the BEM\relax }{equation.4.3.20}{}} +\newlabel{eq:laplace3D:reciprocal_relation:005}{{4.22}{17}{Discrete Laplace solution using the BEM\relax }{equation.4.3.22}{}} +\newlabel{eq:laplace3D:reciprocal_relation:006}{{4.23}{17}{Discrete Laplace solution using the BEM\relax }{equation.4.3.23}{}} +\newlabel{eq:laplace3D:reciprocal_relation:007}{{4.24}{17}{Discrete Laplace solution using the BEM\relax }{equation.4.3.24}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.3.5}Integrals computation}{17}{subsection.4.3.5}} +\newlabel{sss:laplace3D:integrals}{{4.3.5}{17}{Integrals computation\relax }{subsection.4.3.5}{}} +\newlabel{eq:laplace3D:integral:g}{{4.25}{17}{Integrals computation\relax }{equation.4.3.25}{}} +\newlabel{eq:laplace3D:integral:uv}{{4.26}{18}{Integrals computation\relax }{equation.4.3.26}{}} +\newlabel{eq:laplace3D:integral:spline}{{4.27}{18}{Integrals computation\relax }{equation.4.3.27}{}} +\newlabel{eq:laplace3D:integral:k}{{4.28}{18}{Integrals computation\relax }{equation.4.3.28}{}} +\@writefile{toc}{\contentsline {section}{\numberline {4.4}BEM test}{18}{section.4.4}} +\newlabel{ss:laplace3D:test}{{4.4}{18}{BEM test\relax }{section.4.4}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.4.1}General}{18}{subsection.4.4.1}} +\newlabel{sss:laplace3D:test:general}{{4.4.1}{18}{General\relax }{subsection.4.4.1}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {4.2}{\ignorespaces Integration method scheme}}{19}{figure.4.2}} +\newlabel{fig:ss:laplace3D:integral}{{4.2}{19}{Integration method scheme\relax }{figure.4.2}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {4.3}{\ignorespaces Wave used in the test}}{19}{figure.4.3}} +\newlabel{fig:laplace3D:test:wave}{{4.3}{19}{Wave used in the test\relax }{figure.4.3}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.4.2}Direct method}{19}{subsection.4.4.2}} +\newlabel{sss:laplace3D:test:direct}{{4.4.2}{19}{Direct method\relax }{subsection.4.4.2}{}} +\bibdata{bib} +\@writefile{lof}{\contentsline {figure}{\numberline {4.4}{\ignorespaces Direct method}}{20}{figure.4.4}} +\newlabel{fig:laplace3D:test:direct}{{4.4}{20}{Direct method\relax }{figure.4.4}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.4.3}BEM}{20}{subsection.4.4.3}} +\newlabel{sss:laplace3D:test:bem}{{4.4.3}{20}{BEM\relax }{subsection.4.4.3}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {4.5}{\ignorespaces BEM solution}}{21}{figure.4.5}} +\newlabel{fig:laplace3D:test:bem}{{4.5}{21}{BEM solution\relax }{figure.4.5}{}} +\bibcite{bem_2007}{{1}{2007}{{Ang}}{{}}} +\bibcite{vinayan2007}{{2}{2007}{{Vinayan and Kinnas}}{{}}} +\bibcite{yang2004}{{3}{2004}{{Yang}}{{}}} +\@writefile{toc}{\contentsline {chapter}{Bibliography}{23}{chapter*.2}} diff --git a/src/Mod/Ship/simRun/theory/main.bbl b/src/Mod/Ship/simRun/theory/main.bbl new file mode 100644 index 000000000..501e72326 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/main.bbl @@ -0,0 +1,24 @@ +\begin{thebibliography}{3} +\providecommand{\natexlab}[1]{#1} +\providecommand{\url}[1]{\texttt{#1}} +\expandafter\ifx\csname urlstyle\endcsname\relax + \providecommand{\doi}[1]{doi: #1}\else + \providecommand{\doi}{doi: \begingroup \urlstyle{rm}\Url}\fi + +\bibitem[Ang(2007)]{bem_2007} +Whye-Teong Ang. +\newblock \emph{A Beginner’s Course in Boundary Element Methods}. +\newblock Cambridge University Press, New York, 2007. + +\bibitem[Vinayan and Kinnas(2007)]{vinayan2007} +V.~Vinayan and S.~A. Kinnas. +\newblock A bem for the propagation of nonlinear planar free-surface waves. +\newblock \emph{Electronic Journal of Boundary Elements}, 5:\penalty0 17--40, + 2007. + +\bibitem[Yang(2004)]{yang2004} +Jinghai Yang. +\newblock \emph{Time domain, nonlinear theories on ship motions}. +\newblock PhD thesis, University of Hawaii, 2004. + +\end{thebibliography} diff --git a/src/Mod/Ship/simRun/theory/main.blg b/src/Mod/Ship/simRun/theory/main.blg new file mode 100644 index 000000000..72657ecfe --- /dev/null +++ b/src/Mod/Ship/simRun/theory/main.blg @@ -0,0 +1,48 @@ +This is BibTeX, Version 0.99d (TeX Live 2012/Debian) +Capacity: max_strings=35307, hash_size=35307, hash_prime=30011 +The top-level auxiliary file: main.aux +The style file: plainnat.bst +Database file #1: bib.bib +Warning--can't use both author and editor fields in bem_2007 +You've used 3 entries, + 2773 wiz_defined-function locations, + 726 strings with 6674 characters, +and the built_in function-call counts, 1030 in all, are: += -- 88 +> -- 41 +< -- 3 ++ -- 15 +- -- 12 +* -- 67 +:= -- 173 +add.period$ -- 9 +call.type$ -- 3 +change.case$ -- 11 +chr.to.int$ -- 3 +cite$ -- 7 +duplicate$ -- 56 +empty$ -- 92 +format.name$ -- 17 +if$ -- 207 +int.to.chr$ -- 1 +int.to.str$ -- 1 +missing$ -- 3 +newline$ -- 23 +num.names$ -- 12 +pop$ -- 25 +preamble$ -- 1 +purify$ -- 10 +quote$ -- 0 +skip$ -- 41 +stack$ -- 0 +substring$ -- 21 +swap$ -- 4 +text.length$ -- 0 +text.prefix$ -- 0 +top$ -- 0 +type$ -- 28 +warning$ -- 1 +while$ -- 10 +width$ -- 0 +write$ -- 45 +(There was 1 warning) diff --git a/src/Mod/Ship/simRun/theory/main.log b/src/Mod/Ship/simRun/theory/main.log new file mode 100644 index 000000000..a224a19a6 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/main.log @@ -0,0 +1,827 @@ +This is pdfTeX, Version 3.1415926-2.4-1.40.13 (TeX Live 2012/Debian) (format=pdflatex 2012.12.24) 1 APR 2013 19:55 +entering extended mode + restricted \write18 enabled. + %&-line parsing enabled. +**main.tex +(./main.tex +LaTeX2e <2011/06/27> +Babel and hyphenation patterns for english, dumylang, nohyphenation, lo +aded. +(/usr/share/texlive/texmf-dist/tex/latex/base/book.cls +Document Class: book 2007/10/19 v1.4h Standard LaTeX document class +(/usr/share/texlive/texmf-dist/tex/latex/base/bk12.clo +File: bk12.clo 2007/10/19 v1.4h Standard LaTeX file (size option) +) +\c@part=\count79 +\c@chapter=\count80 +\c@section=\count81 +\c@subsection=\count82 +\c@subsubsection=\count83 +\c@paragraph=\count84 +\c@subparagraph=\count85 +\c@figure=\count86 +\c@table=\count87 +\abovecaptionskip=\skip41 +\belowcaptionskip=\skip42 +\bibindent=\dimen102 +) +(/usr/share/texlive/texmf-dist/tex/latex/natbib/natbib.sty +Package: natbib 2010/09/13 8.31b (PWD, AO) +\bibhang=\skip43 +\bibsep=\skip44 +LaTeX Info: Redefining \cite on input line 694. +\c@NAT@ctr=\count88 +) +(/usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty +Package: graphicx 1999/02/16 v1.0f Enhanced LaTeX Graphics (DPC,SPQR) + +(/usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty +Package: keyval 1999/03/16 v1.13 key=value parser (DPC) +\KV@toks@=\toks14 +) +(/usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty +Package: graphics 2009/02/05 v1.0o Standard LaTeX Graphics (DPC,SPQR) + +(/usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty +Package: trig 1999/03/16 v1.09 sin cos tan (DPC) +) +(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/graphics.cfg +File: graphics.cfg 2010/04/23 v1.9 graphics configuration of TeX Live +) +Package graphics Info: Driver file: pdftex.def on input line 91. + +(/usr/share/texlive/texmf-dist/tex/latex/pdftex-def/pdftex.def +File: pdftex.def 2011/05/27 v0.06d Graphics/color for pdfTeX + +(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/infwarerr.sty +Package: infwarerr 2010/04/08 v1.3 Providing info/warning/error messages (HO) +) +(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ltxcmds.sty +Package: ltxcmds 2011/11/09 v1.22 LaTeX kernel commands for general use (HO) +) +\Gread@gobject=\count89 +)) +\Gin@req@height=\dimen103 +\Gin@req@width=\dimen104 +) +(/usr/share/texlive/texmf-dist/tex/latex/tools/verbatim.sty +Package: verbatim 2003/08/22 v1.5q LaTeX2e package for verbatim enhancements +\every@verbatim=\toks15 +\verbatim@line=\toks16 +\verbatim@in@stream=\read1 +) +(/usr/share/texlive/texmf-dist/tex/latex/graphics/color.sty +Package: color 2005/11/14 v1.0j Standard LaTeX Color (DPC) + +(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/color.cfg +File: color.cfg 2007/01/18 v1.5 color configuration of teTeX/TeXLive +) +Package color Info: Driver file: pdftex.def on input line 130. +) +(/usr/share/texlive/texmf-dist/tex/latex/colortbl/colortbl.sty +Package: colortbl 2012/02/13 v1.0a Color table columns (DPC) + +(/usr/share/texlive/texmf-dist/tex/latex/tools/array.sty +Package: array 2008/09/09 v2.4c Tabular extension package (FMi) +\col@sep=\dimen105 +\extrarowheight=\dimen106 +\NC@list=\toks17 +\extratabsurround=\skip45 +\backup@length=\skip46 +) +\everycr=\toks18 +\minrowclearance=\skip47 +) +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/hyperref.sty +Package: hyperref 2012/05/13 v6.82q Hypertext links for LaTeX + +(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/hobsub-hyperref.sty +Package: hobsub-hyperref 2012/05/28 v1.13 Bundle oberdiek, subset hyperref (HO) + + +(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/hobsub-generic.sty +Package: hobsub-generic 2012/05/28 v1.13 Bundle oberdiek, subset generic (HO) +Package: hobsub 2012/05/28 v1.13 Construct package bundles (HO) +Package hobsub Info: Skipping package `infwarerr' (already loaded). +Package hobsub Info: Skipping package `ltxcmds' (already loaded). +Package: ifluatex 2010/03/01 v1.3 Provides the ifluatex switch (HO) +Package ifluatex Info: LuaTeX not detected. +Package: ifvtex 2010/03/01 v1.5 Detect VTeX and its facilities (HO) +Package ifvtex Info: VTeX not detected. +Package: intcalc 2007/09/27 v1.1 Expandable calculations with integers (HO) +Package: ifpdf 2011/01/30 v2.3 Provides the ifpdf switch (HO) +Package ifpdf Info: pdfTeX in PDF mode is detected. +Package: etexcmds 2011/02/16 v1.5 Avoid name clashes with e-TeX commands (HO) +Package etexcmds Info: Could not find \expanded. +(etexcmds) That can mean that you are not using pdfTeX 1.50 or +(etexcmds) that some package has redefined \expanded. +(etexcmds) In the latter case, load this package earlier. +Package: kvsetkeys 2012/04/25 v1.16 Key value parser (HO) +Package: kvdefinekeys 2011/04/07 v1.3 Define keys (HO) +Package: pdftexcmds 2011/11/29 v0.20 Utility functions of pdfTeX for LuaTeX (HO +) +Package pdftexcmds Info: LuaTeX not detected. +Package pdftexcmds Info: \pdf@primitive is available. +Package pdftexcmds Info: \pdf@ifprimitive is available. +Package pdftexcmds Info: \pdfdraftmode found. +Package: pdfescape 2011/11/25 v1.13 Implements pdfTeX's escape features (HO) +Package: bigintcalc 2012/04/08 v1.3 Expandable calculations on big integers (HO +) +Package: bitset 2011/01/30 v1.1 Handle bit-vector datatype (HO) +Package: uniquecounter 2011/01/30 v1.2 Provide unlimited unique counter (HO) +) +Package hobsub Info: Skipping package `hobsub' (already loaded). +Package: letltxmacro 2010/09/02 v1.4 Let assignment for LaTeX macros (HO) +Package: hopatch 2012/05/28 v1.2 Wrapper for package hooks (HO) +Package: xcolor-patch 2011/01/30 xcolor patch +Package: atveryend 2011/06/30 v1.8 Hooks at the very end of document (HO) +Package atveryend Info: \enddocument detected (standard20110627). +Package: atbegshi 2011/10/05 v1.16 At begin shipout hook (HO) +Package: refcount 2011/10/16 v3.4 Data extraction from label references (HO) +Package: hycolor 2011/01/30 v1.7 Color options for hyperref/bookmark (HO) +) +(/usr/share/texlive/texmf-dist/tex/generic/ifxetex/ifxetex.sty +Package: ifxetex 2010/09/12 v0.6 Provides ifxetex conditional +) +(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/kvoptions.sty +Package: kvoptions 2011/06/30 v3.11 Key value format for package options (HO) +) +\@linkdim=\dimen107 +\Hy@linkcounter=\count90 +\Hy@pagecounter=\count91 + +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/pd1enc.def +File: pd1enc.def 2012/05/13 v6.82q Hyperref: PDFDocEncoding definition (HO) +) +\Hy@SavedSpaceFactor=\count92 + +(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/hyperref.cfg +File: hyperref.cfg 2002/06/06 v1.2 hyperref configuration of TeXLive +) +Package hyperref Info: Hyper figures OFF on input line 4062. +Package hyperref Info: Link nesting OFF on input line 4067. +Package hyperref Info: Hyper index ON on input line 4070. +Package hyperref Info: Plain pages OFF on input line 4077. +Package hyperref Info: Backreferencing OFF on input line 4082. +Package hyperref Info: Implicit mode ON; LaTeX internals redefined. +Package hyperref Info: Bookmarks ON on input line 4300. +\c@Hy@tempcnt=\count93 + +(/usr/share/texlive/texmf-dist/tex/latex/url/url.sty +\Urlmuskip=\muskip10 +Package: url 2006/04/12 ver 3.3 Verb mode for urls, etc. +) +LaTeX Info: Redefining \url on input line 4653. +\Fld@menulength=\count94 +\Field@Width=\dimen108 +\Fld@charsize=\dimen109 +Package hyperref Info: Hyper figures OFF on input line 5773. +Package hyperref Info: Link nesting OFF on input line 5778. +Package hyperref Info: Hyper index ON on input line 5781. +Package hyperref Info: backreferencing OFF on input line 5788. +Package hyperref Info: Link coloring OFF on input line 5793. +Package hyperref Info: Link coloring with OCG OFF on input line 5798. +Package hyperref Info: PDF/A mode OFF on input line 5803. +LaTeX Info: Redefining \ref on input line 5843. +LaTeX Info: Redefining \pageref on input line 5847. +\Hy@abspage=\count95 +\c@Item=\count96 +\c@Hfootnote=\count97 +) + +Package hyperref Message: Driver (autodetected): hpdftex. + +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/hpdftex.def +File: hpdftex.def 2012/05/13 v6.82q Hyperref driver for pdfTeX +\Fld@listcount=\count98 +\c@bookmark@seq@number=\count99 + +(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/rerunfilecheck.sty +Package: rerunfilecheck 2011/04/15 v1.7 Rerun checks for auxiliary files (HO) +Package uniquecounter Info: New unique counter `rerunfilecheck' on input line 2 +82. +) +\Hy@SectionHShift=\skip48 +) +(/usr/share/texlive/texmf-dist/tex/latex/base/inputenc.sty +Package: inputenc 2008/03/30 v1.1d Input encoding file +\inpenc@prehook=\toks19 +\inpenc@posthook=\toks20 + +(/usr/share/texlive/texmf-dist/tex/latex/base/utf8.def +File: utf8.def 2008/04/05 v1.1m UTF-8 support for inputenc +Now handling font encoding OML ... +... no UTF-8 mapping file for font encoding OML +Now handling font encoding T1 ... +... processing UTF-8 mapping file for font encoding T1 + +(/usr/share/texlive/texmf-dist/tex/latex/base/t1enc.dfu +File: t1enc.dfu 2008/04/05 v1.1m UTF-8 support for inputenc + defining Unicode char U+00A1 (decimal 161) + defining Unicode char U+00A3 (decimal 163) + defining Unicode char U+00AB (decimal 171) + defining Unicode char U+00BB (decimal 187) + defining Unicode char U+00BF (decimal 191) + defining Unicode char U+00C0 (decimal 192) + defining Unicode char U+00C1 (decimal 193) + defining Unicode char U+00C2 (decimal 194) + defining Unicode char U+00C3 (decimal 195) + defining Unicode char U+00C4 (decimal 196) + defining Unicode char U+00C5 (decimal 197) + defining Unicode char U+00C6 (decimal 198) + defining Unicode char U+00C7 (decimal 199) + defining Unicode char U+00C8 (decimal 200) + defining Unicode char U+00C9 (decimal 201) + defining Unicode char U+00CA (decimal 202) + defining Unicode char U+00CB (decimal 203) + defining Unicode char U+00CC (decimal 204) + defining Unicode char U+00CD (decimal 205) + defining Unicode char U+00CE (decimal 206) + defining Unicode char U+00CF (decimal 207) + defining Unicode char U+00D0 (decimal 208) + defining Unicode char U+00D1 (decimal 209) + defining Unicode char U+00D2 (decimal 210) + defining Unicode char U+00D3 (decimal 211) + defining Unicode char U+00D4 (decimal 212) + defining Unicode char U+00D5 (decimal 213) + defining Unicode char U+00D6 (decimal 214) + defining Unicode char U+00D8 (decimal 216) + defining Unicode char U+00D9 (decimal 217) + defining Unicode char U+00DA (decimal 218) + defining Unicode char U+00DB (decimal 219) + defining Unicode char U+00DC (decimal 220) + defining Unicode char U+00DD (decimal 221) + defining Unicode char U+00DE (decimal 222) + defining Unicode char U+00DF (decimal 223) + defining Unicode char U+00E0 (decimal 224) + defining Unicode char U+00E1 (decimal 225) + defining Unicode char U+00E2 (decimal 226) + defining Unicode char U+00E3 (decimal 227) + defining Unicode char U+00E4 (decimal 228) + defining Unicode char U+00E5 (decimal 229) + defining Unicode char U+00E6 (decimal 230) + defining Unicode char U+00E7 (decimal 231) + defining Unicode char U+00E8 (decimal 232) + defining Unicode char U+00E9 (decimal 233) + defining Unicode char U+00EA (decimal 234) + defining Unicode char U+00EB (decimal 235) + defining Unicode char U+00EC (decimal 236) + defining Unicode char U+00ED (decimal 237) + defining Unicode char U+00EE (decimal 238) + defining Unicode char U+00EF (decimal 239) + defining Unicode char U+00F0 (decimal 240) + defining Unicode char U+00F1 (decimal 241) + defining Unicode char U+00F2 (decimal 242) + defining Unicode char U+00F3 (decimal 243) + defining Unicode char U+00F4 (decimal 244) + defining Unicode char U+00F5 (decimal 245) + defining Unicode char U+00F6 (decimal 246) + defining Unicode char U+00F8 (decimal 248) + defining Unicode char U+00F9 (decimal 249) + defining Unicode char U+00FA (decimal 250) + defining Unicode char U+00FB (decimal 251) + defining Unicode char U+00FC (decimal 252) + defining Unicode char U+00FD (decimal 253) + defining Unicode char U+00FE (decimal 254) + defining Unicode char U+00FF (decimal 255) + defining Unicode char U+0102 (decimal 258) + defining Unicode char U+0103 (decimal 259) + defining Unicode char U+0104 (decimal 260) + defining Unicode char U+0105 (decimal 261) + defining Unicode char U+0106 (decimal 262) + defining Unicode char U+0107 (decimal 263) + defining Unicode char U+010C (decimal 268) + defining Unicode char U+010D (decimal 269) + defining Unicode char U+010E (decimal 270) + defining Unicode char U+010F (decimal 271) + defining Unicode char U+0110 (decimal 272) + defining Unicode char U+0111 (decimal 273) + defining Unicode char U+0118 (decimal 280) + defining Unicode char U+0119 (decimal 281) + defining Unicode char U+011A (decimal 282) + defining Unicode char U+011B (decimal 283) + defining Unicode char U+011E (decimal 286) + defining Unicode char U+011F (decimal 287) + defining Unicode char U+0130 (decimal 304) + defining Unicode char U+0131 (decimal 305) + defining Unicode char U+0132 (decimal 306) + defining Unicode char U+0133 (decimal 307) + defining Unicode char U+0139 (decimal 313) + defining Unicode char U+013A (decimal 314) + defining Unicode char U+013D (decimal 317) + defining Unicode char U+013E (decimal 318) + defining Unicode char U+0141 (decimal 321) + defining Unicode char U+0142 (decimal 322) + defining Unicode char U+0143 (decimal 323) + defining Unicode char U+0144 (decimal 324) + defining Unicode char U+0147 (decimal 327) + defining Unicode char U+0148 (decimal 328) + defining Unicode char U+014A (decimal 330) + defining Unicode char U+014B (decimal 331) + defining Unicode char U+0150 (decimal 336) + defining Unicode char U+0151 (decimal 337) + defining Unicode char U+0152 (decimal 338) + defining Unicode char U+0153 (decimal 339) + defining Unicode char U+0154 (decimal 340) + defining Unicode char U+0155 (decimal 341) + defining Unicode char U+0158 (decimal 344) + defining Unicode char U+0159 (decimal 345) + defining Unicode char U+015A (decimal 346) + defining Unicode char U+015B (decimal 347) + defining Unicode char U+015E (decimal 350) + defining Unicode char U+015F (decimal 351) + defining Unicode char U+0160 (decimal 352) + defining Unicode char U+0161 (decimal 353) + defining Unicode char U+0162 (decimal 354) + defining Unicode char U+0163 (decimal 355) + defining Unicode char U+0164 (decimal 356) + defining Unicode char U+0165 (decimal 357) + defining Unicode char U+016E (decimal 366) + defining Unicode char U+016F (decimal 367) + defining Unicode char U+0170 (decimal 368) + defining Unicode char U+0171 (decimal 369) + defining Unicode char U+0178 (decimal 376) + defining Unicode char U+0179 (decimal 377) + defining Unicode char U+017A (decimal 378) + defining Unicode char U+017B (decimal 379) + defining Unicode char U+017C (decimal 380) + defining Unicode char U+017D (decimal 381) + defining Unicode char U+017E (decimal 382) + defining Unicode char U+200C (decimal 8204) + defining Unicode char U+2013 (decimal 8211) + defining Unicode char U+2014 (decimal 8212) + defining Unicode char U+2018 (decimal 8216) + defining Unicode char U+2019 (decimal 8217) + defining Unicode char U+201A (decimal 8218) + defining Unicode char U+201C (decimal 8220) + defining Unicode char U+201D (decimal 8221) + defining Unicode char U+201E (decimal 8222) + defining Unicode char U+2030 (decimal 8240) + defining Unicode char U+2031 (decimal 8241) + defining Unicode char U+2039 (decimal 8249) + defining Unicode char U+203A (decimal 8250) + defining Unicode char U+2423 (decimal 9251) +) +Now handling font encoding OT1 ... +... processing UTF-8 mapping file for font encoding OT1 + +(/usr/share/texlive/texmf-dist/tex/latex/base/ot1enc.dfu +File: ot1enc.dfu 2008/04/05 v1.1m UTF-8 support for inputenc + defining Unicode char U+00A1 (decimal 161) + defining Unicode char U+00A3 (decimal 163) + defining Unicode char U+00B8 (decimal 184) + defining Unicode char U+00BF (decimal 191) + defining Unicode char U+00C5 (decimal 197) + defining Unicode char U+00C6 (decimal 198) + defining Unicode char U+00D8 (decimal 216) + defining Unicode char U+00DF (decimal 223) + defining Unicode char U+00E6 (decimal 230) + defining Unicode char U+00EC (decimal 236) + defining Unicode char U+00ED (decimal 237) + defining Unicode char U+00EE (decimal 238) + defining Unicode char U+00EF (decimal 239) + defining Unicode char U+00F8 (decimal 248) + defining Unicode char U+0131 (decimal 305) + defining Unicode char U+0141 (decimal 321) + defining Unicode char U+0142 (decimal 322) + defining Unicode char U+0152 (decimal 338) + defining Unicode char U+0153 (decimal 339) + defining Unicode char U+2013 (decimal 8211) + defining Unicode char U+2014 (decimal 8212) + defining Unicode char U+2018 (decimal 8216) + defining Unicode char U+2019 (decimal 8217) + defining Unicode char U+201C (decimal 8220) + defining Unicode char U+201D (decimal 8221) +) +Now handling font encoding OMS ... +... processing UTF-8 mapping file for font encoding OMS + +(/usr/share/texlive/texmf-dist/tex/latex/base/omsenc.dfu +File: omsenc.dfu 2008/04/05 v1.1m UTF-8 support for inputenc + defining Unicode char U+00A7 (decimal 167) + defining Unicode char U+00B6 (decimal 182) + defining Unicode char U+00B7 (decimal 183) + defining Unicode char U+2020 (decimal 8224) + defining Unicode char U+2021 (decimal 8225) + defining Unicode char U+2022 (decimal 8226) +) +Now handling font encoding OMX ... +... no UTF-8 mapping file for font encoding OMX +Now handling font encoding U ... +... no UTF-8 mapping file for font encoding U +Now handling font encoding PD1 ... +... no UTF-8 mapping file for font encoding PD1 + defining Unicode char U+00A9 (decimal 169) + defining Unicode char U+00AA (decimal 170) + defining Unicode char U+00AE (decimal 174) + defining Unicode char U+00BA (decimal 186) + defining Unicode char U+02C6 (decimal 710) + defining Unicode char U+02DC (decimal 732) + defining Unicode char U+200C (decimal 8204) + defining Unicode char U+2026 (decimal 8230) + defining Unicode char U+2122 (decimal 8482) + defining Unicode char U+2423 (decimal 9251) +)) +(/usr/share/texlive/texmf-dist/tex/latex/base/alltt.sty +Package: alltt 1997/06/16 v2.0g defines alltt environment +) +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty +Package: amsmath 2000/07/18 v2.13 AMS math features +\@mathmargin=\skip49 + +For additional information on amsmath, use the `?' option. +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty +Package: amstext 2000/06/29 v2.01 + +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty +File: amsgen.sty 1999/11/30 v2.0 +\@emptytoks=\toks21 +\ex@=\dimen110 +)) +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty +Package: amsbsy 1999/11/29 v1.2d +\pmbraise@=\dimen111 +) +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty +Package: amsopn 1999/12/14 v2.01 operator names +) +\inf@bad=\count100 +LaTeX Info: Redefining \frac on input line 211. +\uproot@=\count101 +\leftroot@=\count102 +LaTeX Info: Redefining \overline on input line 307. +\classnum@=\count103 +\DOTSCASE@=\count104 +LaTeX Info: Redefining \ldots on input line 379. +LaTeX Info: Redefining \dots on input line 382. +LaTeX Info: Redefining \cdots on input line 467. +\Mathstrutbox@=\box26 +\strutbox@=\box27 +\big@size=\dimen112 +LaTeX Font Info: Redeclaring font encoding OML on input line 567. +LaTeX Font Info: Redeclaring font encoding OMS on input line 568. +\macc@depth=\count105 +\c@MaxMatrixCols=\count106 +\dotsspace@=\muskip11 +\c@parentequation=\count107 +\dspbrk@lvl=\count108 +\tag@help=\toks22 +\row@=\count109 +\column@=\count110 +\maxfields@=\count111 +\andhelp@=\toks23 +\eqnshift@=\dimen113 +\alignsep@=\dimen114 +\tagshift@=\dimen115 +\tagwidth@=\dimen116 +\totwidth@=\dimen117 +\lineht@=\dimen118 +\@envbody=\toks24 +\multlinegap=\skip50 +\multlinetaggap=\skip51 +\mathdisplay@stack=\toks25 +LaTeX Info: Redefining \[ on input line 2666. +LaTeX Info: Redefining \] on input line 2667. +) +(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty +Package: amssymb 2009/06/22 v3.00 + +(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty +Package: amsfonts 2009/06/22 v3.00 Basic AMSFonts support +\symAMSa=\mathgroup4 +\symAMSb=\mathgroup5 +LaTeX Font Info: Overwriting math alphabet `\mathfrak' in version `bold' +(Font) U/euf/m/n --> U/euf/b/n on input line 96. +)) +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/txfonts.sty +Package: txfonts 2008/01/22 v3.2.1 +LaTeX Font Info: Redeclaring symbol font `operators' on input line 21. +LaTeX Font Info: Overwriting symbol font `operators' in version `normal' +(Font) OT1/cmr/m/n --> OT1/txr/m/n on input line 21. +LaTeX Font Info: Overwriting symbol font `operators' in version `bold' +(Font) OT1/cmr/bx/n --> OT1/txr/m/n on input line 21. +LaTeX Font Info: Overwriting symbol font `operators' in version `bold' +(Font) OT1/txr/m/n --> OT1/txr/bx/n on input line 22. +\symitalic=\mathgroup6 +LaTeX Font Info: Overwriting symbol font `italic' in version `bold' +(Font) OT1/txr/m/it --> OT1/txr/bx/it on input line 26. +LaTeX Font Info: Redeclaring math alphabet \mathbf on input line 29. +LaTeX Font Info: Overwriting math alphabet `\mathbf' in version `normal' +(Font) OT1/cmr/bx/n --> OT1/txr/bx/n on input line 29. +LaTeX Font Info: Overwriting math alphabet `\mathbf' in version `bold' +(Font) OT1/cmr/bx/n --> OT1/txr/bx/n on input line 29. +LaTeX Font Info: Redeclaring math alphabet \mathit on input line 30. +LaTeX Font Info: Overwriting math alphabet `\mathit' in version `normal' +(Font) OT1/cmr/m/it --> OT1/txr/m/it on input line 30. +LaTeX Font Info: Overwriting math alphabet `\mathit' in version `bold' +(Font) OT1/cmr/bx/it --> OT1/txr/m/it on input line 30. +LaTeX Font Info: Overwriting math alphabet `\mathit' in version `bold' +(Font) OT1/txr/m/it --> OT1/txr/bx/it on input line 31. +LaTeX Font Info: Redeclaring math alphabet \mathsf on input line 40. +LaTeX Font Info: Overwriting math alphabet `\mathsf' in version `normal' +(Font) OT1/cmss/m/n --> OT1/txss/m/n on input line 40. +LaTeX Font Info: Overwriting math alphabet `\mathsf' in version `bold' +(Font) OT1/cmss/bx/n --> OT1/txss/m/n on input line 40. +LaTeX Font Info: Overwriting math alphabet `\mathsf' in version `bold' +(Font) OT1/txss/m/n --> OT1/txss/b/n on input line 41. +LaTeX Font Info: Redeclaring math alphabet \mathtt on input line 50. +LaTeX Font Info: Overwriting math alphabet `\mathtt' in version `normal' +(Font) OT1/cmtt/m/n --> OT1/txtt/m/n on input line 50. +LaTeX Font Info: Overwriting math alphabet `\mathtt' in version `bold' +(Font) OT1/cmtt/m/n --> OT1/txtt/m/n on input line 50. +LaTeX Font Info: Overwriting math alphabet `\mathtt' in version `bold' +(Font) OT1/txtt/m/n --> OT1/txtt/b/n on input line 51. +LaTeX Font Info: Redeclaring symbol font `letters' on input line 58. +LaTeX Font Info: Overwriting symbol font `letters' in version `normal' +(Font) OML/cmm/m/it --> OML/txmi/m/it on input line 58. +LaTeX Font Info: Overwriting symbol font `letters' in version `bold' +(Font) OML/cmm/b/it --> OML/txmi/m/it on input line 58. +LaTeX Font Info: Overwriting symbol font `letters' in version `bold' +(Font) OML/txmi/m/it --> OML/txmi/bx/it on input line 59. +\symlettersA=\mathgroup7 +LaTeX Font Info: Overwriting symbol font `lettersA' in version `bold' +(Font) U/txmia/m/it --> U/txmia/bx/it on input line 67. +LaTeX Font Info: Redeclaring math alphabet \mathfrak on input line 70. +LaTeX Font Info: Redeclaring symbol font `symbols' on input line 77. +LaTeX Font Info: Overwriting symbol font `symbols' in version `normal' +(Font) OMS/cmsy/m/n --> OMS/txsy/m/n on input line 77. +LaTeX Font Info: Overwriting symbol font `symbols' in version `bold' +(Font) OMS/cmsy/b/n --> OMS/txsy/m/n on input line 77. +LaTeX Font Info: Overwriting symbol font `symbols' in version `bold' +(Font) OMS/txsy/m/n --> OMS/txsy/bx/n on input line 78. +LaTeX Font Info: Redeclaring symbol font `AMSa' on input line 93. +LaTeX Font Info: Overwriting symbol font `AMSa' in version `normal' +(Font) U/msa/m/n --> U/txsya/m/n on input line 93. +LaTeX Font Info: Overwriting symbol font `AMSa' in version `bold' +(Font) U/msa/m/n --> U/txsya/m/n on input line 93. +LaTeX Font Info: Overwriting symbol font `AMSa' in version `bold' +(Font) U/txsya/m/n --> U/txsya/bx/n on input line 94. +LaTeX Font Info: Redeclaring symbol font `AMSb' on input line 102. +LaTeX Font Info: Overwriting symbol font `AMSb' in version `normal' +(Font) U/msb/m/n --> U/txsyb/m/n on input line 102. +LaTeX Font Info: Overwriting symbol font `AMSb' in version `bold' +(Font) U/msb/m/n --> U/txsyb/m/n on input line 102. +LaTeX Font Info: Overwriting symbol font `AMSb' in version `bold' +(Font) U/txsyb/m/n --> U/txsyb/bx/n on input line 103. +\symsymbolsC=\mathgroup8 +LaTeX Font Info: Overwriting symbol font `symbolsC' in version `bold' +(Font) U/txsyc/m/n --> U/txsyc/bx/n on input line 113. +LaTeX Font Info: Redeclaring symbol font `largesymbols' on input line 120. +LaTeX Font Info: Overwriting symbol font `largesymbols' in version `normal' +(Font) OMX/cmex/m/n --> OMX/txex/m/n on input line 120. +LaTeX Font Info: Overwriting symbol font `largesymbols' in version `bold' +(Font) OMX/cmex/m/n --> OMX/txex/m/n on input line 120. +LaTeX Font Info: Overwriting symbol font `largesymbols' in version `bold' +(Font) OMX/txex/m/n --> OMX/txex/bx/n on input line 121. +\symlargesymbolsA=\mathgroup9 +LaTeX Font Info: Overwriting symbol font `largesymbolsA' in version `bold' +(Font) U/txexa/m/n --> U/txexa/bx/n on input line 129. +LaTeX Info: Redefining \not on input line 1043. +) +(/usr/share/texlive/texmf-dist/tex/latex/anysize/anysize.sty +Package: anysize 1994/08/13 setting margin sizes + +document style option `anysize' loaded +Michael Salzenberg, Thomas Esser, Dirk Hillbrecht +Version 1.0, Aug 13, 1994 +\@Leftmargin=\dimen119 +\@Rightmargin=\dimen120 +\@Topmargin=\dimen121 +\@Bottommargin=\dimen122 +) (/usr/share/texlive/texmf-dist/tex/latex/fancyhdr/fancyhdr.sty +\fancy@headwidth=\skip52 +\f@ncyO@elh=\skip53 +\f@ncyO@erh=\skip54 +\f@ncyO@olh=\skip55 +\f@ncyO@orh=\skip56 +\f@ncyO@elf=\skip57 +\f@ncyO@erf=\skip58 +\f@ncyO@olf=\skip59 +\f@ncyO@orf=\skip60 +) (./main.aux) +\openout1 = `main.aux'. + +LaTeX Font Info: Checking defaults for OML/txmi/m/it on input line 58. +LaTeX Font Info: Try loading font information for OML+txmi on input line 58. + + +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/omltxmi.fd +File: omltxmi.fd 2000/12/15 v3.1 +) +LaTeX Font Info: ... okay on input line 58. +LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 58. +LaTeX Font Info: ... okay on input line 58. +LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 58. +LaTeX Font Info: ... okay on input line 58. +LaTeX Font Info: Checking defaults for OMS/txsy/m/n on input line 58. +LaTeX Font Info: Try loading font information for OMS+txsy on input line 58. + + +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/omstxsy.fd +File: omstxsy.fd 2000/12/15 v3.1 +) +LaTeX Font Info: ... okay on input line 58. +LaTeX Font Info: Checking defaults for OMX/txex/m/n on input line 58. +LaTeX Font Info: Try loading font information for OMX+txex on input line 58. + + +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/omxtxex.fd +File: omxtxex.fd 2000/12/15 v3.1 +) +LaTeX Font Info: ... okay on input line 58. +LaTeX Font Info: Checking defaults for U/txexa/m/n on input line 58. +LaTeX Font Info: Try loading font information for U+txexa on input line 58. + +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/utxexa.fd +File: utxexa.fd 2000/12/15 v3.1 +) +LaTeX Font Info: ... okay on input line 58. +LaTeX Font Info: Checking defaults for PD1/pdf/m/n on input line 58. +LaTeX Font Info: ... okay on input line 58. +LaTeX Font Info: Try loading font information for OT1+txr on input line 58. + +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/ot1txr.fd +File: ot1txr.fd 2000/12/15 v3.1 +) +(/usr/share/texlive/texmf-dist/tex/context/base/supp-pdf.mkii +[Loading MPS to PDF converter (version 2006.09.02).] +\scratchcounter=\count112 +\scratchdimen=\dimen123 +\scratchbox=\box28 +\nofMPsegments=\count113 +\nofMParguments=\count114 +\everyMPshowfont=\toks26 +\MPscratchCnt=\count115 +\MPscratchDim=\dimen124 +\MPnumerator=\count116 +\makeMPintoPDFobject=\count117 +\everyMPtoPDFconversion=\toks27 +) (/usr/share/texlive/texmf-dist/tex/latex/oberdiek/epstopdf-base.sty +Package: epstopdf-base 2010/02/09 v2.5 Base part for package epstopdf + +(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/grfext.sty +Package: grfext 2010/08/19 v1.1 Manage graphics extensions (HO) +) +Package grfext Info: Graphics extension search list: +(grfext) [.png,.pdf,.jpg,.mps,.jpeg,.jbig2,.jb2,.PNG,.PDF,.JPG,.JPE +G,.JBIG2,.JB2,.eps] +(grfext) \AppendGraphicsExtensions on input line 452. + +(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg +File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv +e +)) +\AtBeginShipoutBox=\box29 +Package hyperref Info: Link coloring OFF on input line 58. + +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/nameref.sty +Package: nameref 2010/04/30 v2.40 Cross-referencing by name of section + +(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/gettitlestring.sty +Package: gettitlestring 2010/12/03 v1.4 Cleanup title references (HO) +) +\c@section@level=\count118 +) +LaTeX Info: Redefining \ref on input line 58. +LaTeX Info: Redefining \pageref on input line 58. +LaTeX Info: Redefining \nameref on input line 58. + +(./main.out) (./main.out) +\@outlinefile=\write3 +\openout3 = `main.out'. + +LaTeX Font Info: Try loading font information for U+txsya on input line 64. + +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/utxsya.fd +File: utxsya.fd 2000/12/15 v3.1 +) +LaTeX Font Info: Try loading font information for U+txsyb on input line 64. + +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/utxsyb.fd +File: utxsyb.fd 2000/12/15 v3.1 +) +LaTeX Font Info: Try loading font information for U+txmia on input line 64. + +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/utxmia.fd +File: utxmia.fd 2000/12/15 v3.1 +) +LaTeX Font Info: Try loading font information for U+txsyc on input line 64. + +(/usr/share/texlive/texmf-dist/tex/latex/txfonts/utxsyc.fd +File: utxsyc.fd 2000/12/15 v3.1 +) +<./images/CC_88x31.png, id=92, 88.33pt x 31.11626pt> +File: ./images/CC_88x31.png Graphic file (type png) + + +Package pdftex.def Info: ./images/CC_88x31.png used on input line 64. +(pdftex.def) Requested size: 105.27359pt x 37.08528pt. + [1 + + +{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map} <./images/CC_88x31.png>] [2 + +] (./main.toc) +\tf@toc=\write4 +\openout4 = `main.toc'. + + + +Package Fancyhdr Warning: \headheight is too small (12.0pt): + Make it at least 14.49998pt. + We now make it that large for the rest of the document. + This may cause the page layout to be inconsistent, however. + +[3] (./abstract.tex [4 + +] +Chapter 1. +[5] [6 + +] +Chapter 2. +) (./laplace2D.tex [7] [8 + +] +Chapter 3. +[9] [10] <./images/Omega.png, id=189, 806.01125pt x 479.7925pt> +File: ./images/Omega.png Graphic file (type png) + + +Package pdftex.def Info: ./images/Omega.png used on input line 179. +(pdftex.def) Requested size: 210.54718pt x 125.32878pt. +) (./laplace3D.tex [11 <./images/Omega.png>] [12 + +] +Chapter 4. +[13] <./images/Omega2.png, id=218, 1132.23pt x 449.68pt> +File: ./images/Omega2.png Graphic file (type png) + + +Package pdftex.def Info: ./images/Omega2.png used on input line 117. +(pdftex.def) Requested size: 315.82881pt x 125.43608pt. + [14 <./images/Omega2.png>] [15] [16] [17] +<./images/Integral.png, id=281, 699.61375pt x 699.61375pt> +File: ./images/Integral.png Graphic file (type png) + + +Package pdftex.def Info: ./images/Integral.png used on input line 561. +(pdftex.def) Requested size: 315.82881pt x 315.82675pt. + +<./images/test_wave.png, id=283, 586.8324pt x 442.2924pt> +File: ./images/test_wave.png Graphic file (type png) + + +Package pdftex.def Info: ./images/test_wave.png used on input line 585. +(pdftex.def) Requested size: 315.82881pt x 238.04472pt. + [18] [19 <./images/Integral.png> <./images/test_wave.png>] <./images/test_dire +ct.png, id=301, 586.8324pt x 442.2924pt> +File: ./images/test_direct.png Graphic file (type png) + + +Package pdftex.def Info: ./images/test_direct.png used on input line 616. +(pdftex.def) Requested size: 315.82881pt x 238.04472pt. + +<./images/test_bem.png, id=304, 586.8324pt x 442.2924pt> +File: ./images/test_bem.png Graphic file (type png) + + +Package pdftex.def Info: ./images/test_bem.png used on input line 638. +(pdftex.def) Requested size: 315.82881pt x 238.04472pt. +) (./main.bbl [20 <./images/test_direct.png>] +[21 <./images/test_bem.png>] [22 + +]) +Package atveryend Info: Empty hook `BeforeClearDocument' on input line 90. + [23] +Package atveryend Info: Empty hook `AfterLastShipout' on input line 90. + (./main.aux) +Package atveryend Info: Executing hook `AtVeryEndDocument' on input line 90. +Package atveryend Info: Executing hook `AtEndAfterFileList' on input line 90. +Package rerunfilecheck Info: File `main.out' has not changed. +(rerunfilecheck) Checksum: 47992CAAC05675F8055DF1DA37B7F7A8;1434. +Package atveryend Info: Empty hook `AtVeryVeryEnd' on input line 90. + ) +Here is how much of TeX's memory you used: + 7457 strings out of 495059 + 103785 string characters out of 3182029 + 206801 words of memory out of 3000000 + 10379 multiletter control sequences out of 15000+200000 + 53484 words of font info for 126 fonts, out of 3000000 for 9000 + 14 hyphenation exceptions out of 8191 + 34i,17n,43p,237b,351s stack positions out of 5000i,500n,10000p,200000b,50000s +{/usr/share/texlive/texmf-dist/fonts/enc/dvips/base/8r.enc} +Output written on main.pdf (23 pages, 322361 bytes). +PDF statistics: + 376 PDF objects out of 1000 (max. 8388607) + 325 compressed objects within 4 object streams + 96 named destinations out of 1000 (max. 500000) + 212 words of extra memory for PDF output out of 10000 (max. 10000000) + diff --git a/src/Mod/Ship/simRun/theory/main.out b/src/Mod/Ship/simRun/theory/main.out new file mode 100644 index 000000000..dd5e06dbb --- /dev/null +++ b/src/Mod/Ship/simRun/theory/main.out @@ -0,0 +1,22 @@ +\BOOKMARK [0][-]{chapter.1}{Introduction}{}% 1 +\BOOKMARK [1][-]{section.1.1}{Objective}{chapter.1}% 2 +\BOOKMARK [0][-]{chapter.2}{Governing equations}{}% 3 +\BOOKMARK [0][-]{chapter.3}{Waves propagations in 2D plane}{}% 4 +\BOOKMARK [1][-]{section.3.1}{General}{chapter.3}% 5 +\BOOKMARK [1][-]{section.3.2}{Incident waves}{chapter.3}% 6 +\BOOKMARK [1][-]{section.3.3}{BEM applied to Laplace 2D problem}{chapter.3}% 7 +\BOOKMARK [1][-]{section.3.4}{Conclusions to Laplace 2D problem}{chapter.3}% 8 +\BOOKMARK [0][-]{chapter.4}{Waves propagations in 3D}{}% 9 +\BOOKMARK [1][-]{section.4.1}{General}{chapter.4}% 10 +\BOOKMARK [1][-]{section.4.2}{Incident waves}{chapter.4}% 11 +\BOOKMARK [1][-]{section.4.3}{BEM applied to Laplace 3D problem}{chapter.4}% 12 +\BOOKMARK [2][-]{subsection.4.3.1}{Computational domain}{section.4.3}% 13 +\BOOKMARK [2][-]{subsection.4.3.2}{Boundary conditions \(BC\)}{section.4.3}% 14 +\BOOKMARK [2][-]{subsection.4.3.3}{Time integration scheme}{section.4.3}% 15 +\BOOKMARK [2][-]{subsection.4.3.4}{Discrete Laplace solution using the BEM}{section.4.3}% 16 +\BOOKMARK [2][-]{subsection.4.3.5}{Integrals computation}{section.4.3}% 17 +\BOOKMARK [1][-]{section.4.4}{BEM test}{chapter.4}% 18 +\BOOKMARK [2][-]{subsection.4.4.1}{General}{section.4.4}% 19 +\BOOKMARK [2][-]{subsection.4.4.2}{Direct method}{section.4.4}% 20 +\BOOKMARK [2][-]{subsection.4.4.3}{BEM}{section.4.4}% 21 +\BOOKMARK [0][-]{chapter*.2}{Bibliography}{}% 22 diff --git a/src/Mod/Ship/simRun/theory/main.pdf b/src/Mod/Ship/simRun/theory/main.pdf new file mode 100644 index 0000000000000000000000000000000000000000..798af56aaa56583e7473fbd5fc67c6ef94ded571 GIT binary patch literal 322361 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 literal 0 HcmV?d00001 diff --git a/src/Mod/Ship/simRun/theory/main.tex b/src/Mod/Ship/simRun/theory/main.tex new file mode 100644 index 000000000..f09787f51 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/main.tex @@ -0,0 +1,90 @@ +\documentclass[a4paper,12pt]{book} +\usepackage[numbers]{natbib} +\bibliographystyle{plainnat} +\usepackage{graphicx} +\usepackage{verbatim} +\usepackage{color, colortbl} +\usepackage{hyperref} +\usepackage[utf8]{inputenc} +\setcounter{tocdepth}{2} +\usepackage{alltt} +\usepackage{amsmath} +\usepackage{amssymb} +\usepackage{amsfonts} +\graphicspath{{./images/}} +\usepackage{txfonts} %%does not work on Windows +% \usepackage{dsfont} +% +\newcommand{\NAME}{FreeCAD-Ship } +\newcommand{\rc}{\\[0.2 in]} +\newcommand{\rcc}{\\[0.3 in]} +\newcommand{\rccc}{\\[0.4 in]} +% \newcommand{\bs}[1]{\boldsymbol{#1}} +\newcommand{\bs}[1]{\pmb{#1}} +\newcommand{\SPHint}{\int_{\bs{y} \in \Omega}} +\newcommand{\SPHboundint}{\int_{\bs{y} \in \partial \Omega}} +\newcommand{\gradient}{\nabla} +\newcommand{\divergence}{\mbox{div}} +\newcommand{\rotational}{\nabla \times} +\newcommand{\laplacian}{\bigtriangleup} +\newcommand{\dsty}{\displaystyle} +\newcommand{\sph}[1]{\langle {#1} \rangle} +% +\author{JL Cercos-Pita $<$jlcercos@gmail.com$>$} +\title{FreeCAD-Ship.\rcc +\textbf{Sea waves transport using Boundary Elements Method}} +\date{\today\\[5.0 in] +\begin{figure}[h!] + \centering + \includegraphics[width=0.2\textwidth]{CC_88x31} +\end{figure} +} +% +\setlength{\parindent}{0em} +% +\usepackage{anysize} +\marginsize{1.5cm}{1cm}{1cm}{1cm} +% +\usepackage{fancyhdr} +\pagestyle{fancyplain} +% Pages header and foot +\lhead{} +\rhead{\NAME} +\lfoot{JL Cercos-Pita} +\cfoot{jlcercos@gmail.com} +\rfoot{\thepage} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\begin{document} + +% ------------------------------- +% Title and summary +% ------------------------------- +\maketitle +\thispagestyle{empty} +% +\newpage +\tableofcontents +\newpage +\newpage +% ------------------------------- +% Introduction +% ------------------------------- +\input{abstract} + +% ------------------------------- +% Laplacian 2D +% ------------------------------- +\input{laplace2D} + +% ------------------------------- +% Laplacian 2D +% ------------------------------- +\input{laplace3D} + +% ------------------------------- +% Bibliography +% ------------------------------- +\bibliography{bib} +\addcontentsline{toc}{chapter}{Bibliography} +\end{document} diff --git a/src/Mod/Ship/simRun/theory/main.toc b/src/Mod/Ship/simRun/theory/main.toc new file mode 100644 index 000000000..c60c1e451 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/main.toc @@ -0,0 +1,22 @@ +\contentsline {chapter}{\numberline {1}Introduction}{5}{chapter.1} +\contentsline {section}{\numberline {1.1}Objective}{5}{section.1.1} +\contentsline {chapter}{\numberline {2}Governing equations}{7}{chapter.2} +\contentsline {chapter}{\numberline {3}Waves propagations in 2D plane}{9}{chapter.3} +\contentsline {section}{\numberline {3.1}General}{9}{section.3.1} +\contentsline {section}{\numberline {3.2}Incident waves}{9}{section.3.2} +\contentsline {section}{\numberline {3.3}BEM applied to Laplace 2D problem}{10}{section.3.3} +\contentsline {section}{\numberline {3.4}Conclusions to Laplace 2D problem}{11}{section.3.4} +\contentsline {chapter}{\numberline {4}Waves propagations in 3D}{13}{chapter.4} +\contentsline {section}{\numberline {4.1}General}{13}{section.4.1} +\contentsline {section}{\numberline {4.2}Incident waves}{13}{section.4.2} +\contentsline {section}{\numberline {4.3}BEM applied to Laplace 3D problem}{13}{section.4.3} +\contentsline {subsection}{\numberline {4.3.1}Computational domain}{13}{subsection.4.3.1} +\contentsline {subsection}{\numberline {4.3.2}Boundary conditions (BC)}{14}{subsection.4.3.2} +\contentsline {subsection}{\numberline {4.3.3}Time integration scheme}{15}{subsection.4.3.3} +\contentsline {subsection}{\numberline {4.3.4}Discrete Laplace solution using the BEM}{16}{subsection.4.3.4} +\contentsline {subsection}{\numberline {4.3.5}Integrals computation}{17}{subsection.4.3.5} +\contentsline {section}{\numberline {4.4}BEM test}{18}{section.4.4} +\contentsline {subsection}{\numberline {4.4.1}General}{18}{subsection.4.4.1} +\contentsline {subsection}{\numberline {4.4.2}Direct method}{19}{subsection.4.4.2} +\contentsline {subsection}{\numberline {4.4.3}BEM}{20}{subsection.4.4.3} +\contentsline {chapter}{Bibliography}{23}{chapter*.2} diff --git a/src/Mod/Ship/simRun/theory/test/green.py b/src/Mod/Ship/simRun/theory/test/green.py new file mode 100644 index 000000000..e8f22a530 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/test/green.py @@ -0,0 +1,127 @@ +#*************************************************************************** +#* * +#* 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 numpy import * + +import waves + +def G_val(x,X): + """ Computed the Green's function value. + @param x Point to evaluate (numpy.array(3)) + @param X Reference point (numpy.array(3)) + @return Green's function value. + """ + return 1.0 / (4.0*pi * linalg.norm(x-X)) + +def H_val(x,X): + """ Computed the Green's function gradient. + @param x Point to evaluate (numpy.array(3)) + @param X Reference point (numpy.array(3)) + @return Green's function gradient. + """ + return (x-X) / (4.0*pi * dot(x-X, x-X)**1.5 ) + +def GH(p,I,J,P,n,L,B,x,y,z,dx,dy,t, a,k,w,d): + """ Computes the Green's function integral + numerically, with an increase resolution of n. + @param p Point to evaluate + @param I Point to evaluate x index + @param J Point to evaluate y index + @param P Reference point + @param n Number of divisors in each direction to + discretize each area element. Should be an even value + @param L Length of the computational domain + @param B width of the computational domain + @param x X coordinates of the area elements + @param y Y coordinates of the area elements + @param z Z coordinates of the area elements + @param dx distance between elements in the x direction + @param dy distance between elements in the y direction + @param t Simulation time (s) + @param a List of waves amplitudes + @param k List of waves k + @param w List of waves omega + @param d List of waves lags. + @return Green's function integral. + """ + # Ensure that n is an even value. If n is even + # we can grant that any point will be placed + # in p, that can be eventually the same than + # P, being G and H functions bad defined. + if n % 2: + n = n + 1 + # Get the new distance between Green's points + DX = dx / n + DY = dy / n + # Get the coordinates of all the grid points + # around the evaluation one + nx = x.shape[0] + ny = y.shape[1] + X = zeros((3,3),dtype=float32) + Y = zeros((3,3),dtype=float32) + Z = zeros((3,3),dtype=float32) + for i in range(0,3): + for j in range(0,3): + X[i,j] = p[0] + (i-1)*dx + Y[i,j] = p[1] + (j-1)*dy + if((X[i,j] > -0.5*L) and (X[i,j] < 0.5*L) and (Y[i,j] > -0.5*B) and (Y[i,j] < 0.5*B)): + Z[i,j] = z[I-1+i,J-1+j] + else: + Z[i,j] = waves.z(X[i,j],Y[i,j],t, a,k,w,d) + # Perform spline surface coeffs + K = zeros((3*3),dtype=float32) + K[0] = Z[0,0] # k_{0} + K[1] = 4*Z[1,0] - Z[2,0] - 3*Z[0,0] # k_{u} + K[2] = 4*Z[0,1] - Z[0,2] - 3*Z[0,0] # k_{v} + K[3] = Z[2,2] - 4*Z[2,1] + 3*Z[2,0] + \ + 3*Z[0,2] - 12*Z[0,1] + 9*Z[0,0] + \ + -4*Z[1,2] + 16*Z[1,1] - 12*Z[1,0] # k_{uv} + K[4] = 2*Z[2,0] + 2*Z[0,0] - 4*Z[1,0] # k_{uu} + K[5] = 2*Z[0,2] + 2*Z[0,0] - 4*Z[0,1] # k_{vv} + K[6] = -2*Z[2,2] + 8*Z[2,1] - 6*Z[2,0] + \ + -2*Z[0,2] + 8*Z[0,1] - 6*Z[0,0] + \ + 4*Z[1,2] - 16*Z[1,1] + 12*Z[1,0] # k_{uuv} + K[7] = -2*Z[2,2] + 4*Z[2,1] - 2*Z[2,0] + \ + -6*Z[0,2] + 12*Z[0,1] - 6*Z[0,0] + \ + 8*Z[1,2] - 16*Z[1,1] + 8*Z[1,0] # k_{uuv} + K[8] = 4*Z[2,2] - 8*Z[2,1] + 4*Z[2,0] + \ + 4*Z[0,2] - 8*Z[0,1] + 4*Z[0,0] + \ + -8*Z[1,2] + 16*Z[1,1] - 8*Z[1,0] # k_{uuvv} + # Loop around the point p collecting the integral + G_tot = 0.0 + H_tot = zeros((3),dtype=float32) + for i in range(0,n): + for j in range(0,n): + xx = x[I,J] - 0.5*dx + (i+0.5)*DX + yy = y[I,J] - 0.5*dy + (j+0.5)*DY + # Interpolate z + u = (xx - X[0,0]) / (X[2,0] - X[0,0]) + v = (yy - Y[0,0]) / (Y[0,2] - Y[0,0]) + zz = K[0] + K[1]*u + K[2]*v + K[3]*u*v + \ + K[4]*u*u + K[5]*v*v + K[6]*u*u*v + \ + K[7]*u*v*v + K[8]*u*u*v*v + p = array([xx,yy,zz]) + G_tot = G_tot + G_val(p,P)*DX*DY + H_tot = H_tot + H_val(p,P)*DX*DY + return (G_tot,H_tot) + diff --git a/src/Mod/Ship/simRun/theory/test/main.py b/src/Mod/Ship/simRun/theory/test/main.py new file mode 100644 index 000000000..2b50f978a --- /dev/null +++ b/src/Mod/Ship/simRun/theory/test/main.py @@ -0,0 +1,285 @@ +#*************************************************************************** +#* * +#* 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 sys +from numpy import* +import scipy.linalg as la +from pylab import * + +from green import * +import waves + +# --------------------------------------------------- +# Input data +# --------------------------------------------------- + +# Computational free surface (the part where we will +# compute the fluid dynamics) definition +L = 20.0 +B = 10.0 +nx = 31 +ny = 15 + +# Waves to use, defined by the wave amplitude period, +# and lag. X direction waves will be assumed. +# l = g*T^2 / (2*pi) +a = [0.1] +t = [2.5] +d = [0.0] + +# Green's function maximum value (Error). Used to compute +# The maximum distance to extend the free surface. +G_error = 1e-1 + +# Green's functions integrals resolution (even values) +nG = 8 + +# --------------------------------------------------- +# Simulation setup +# --------------------------------------------------- + +# Discretization +drx = L / nx +dry = B / ny +dS = drx*dry + +# First we may compute how many domains must be +# included in each directions to reach the Green's +# function requested error. +x = (L-drx)/2.0 +Nx = 0 +Gx = G_error*10.0 +while(Gx > G_error): + x = x + L + Nx = Nx + 1 + p = zeros((3), dtype=float32) + P = zeros((3), dtype=float32) + p[0] = x + Gx = G_val(p,P) +print('{0} times the free surface must be duplicated in the x direction\n\tG={1}'.format(Nx,Gx)) + +y = (B-dry)/2.0 +Ny = 0 +Gy = G_error*10.0 +while(Gy > G_error): + y = y + B + Ny = Ny + 1 + p = zeros((3), dtype=float32) + P = zeros((3), dtype=float32) + p[1] = y + Gy = G_val(p,P) +print('{0} times the free surface must be duplicated in the y direction\n\tG={1}'.format(Ny,Gy)) + +# Now we can compute some additional data of the waves +k = [] +w = [] +c = [] +for i in range(0,len(a)): + w.append(2*pi/t[i]) + k.append(w[i]**2 / 9.81) + c.append(w[i]/k[i]) + +# We can intializate the free surface +x = zeros((nx,ny),dtype=float32) +y = zeros((nx,ny),dtype=float32) +z = zeros((nx,ny),dtype=float32) +gradz = zeros((nx,ny),dtype=float32) +p = zeros((nx,ny),dtype=float32) +gradp = zeros((nx,ny),dtype=float32) +for i in range(0,nx): + for j in range(0,ny): + x[i,j] = -0.5*L + (i+0.5)*drx + y[i,j] = -0.5*B + (j+0.5)*dry + z[i,j] = waves.z(x[i,j],y[i,j],0.0, a,k,w,d) + p[i,j] = waves.phi(x[i,j],y[i,j],z[i,j],0.0, a,k,w,d) + gradp[i,j] = waves.gradphi(x[i,j],y[i,j],z[i,j],0.0, a,k,w,d)[2] + +# We can plot starting data +plot_j = int(ny/2) +fig = figure() +plot(x[:,plot_j], z[:,plot_j], color="blue", linewidth=2.5, linestyle="-", label="z") +plot(x[:,plot_j], gradp[:,plot_j], color="red", linewidth=2.5, linestyle="-", label="vz") +plot(x[:,plot_j], p[:,plot_j], color="green", linewidth=2.5, linestyle="-", label="phi") +legend(loc='best') +grid() +show() +close(fig) + +# Compute the error in an arbitrary point +phi = zeros((nx,ny),dtype=float32) +i = int(nx/2) +j = int(ny/2) +xx = x[i,j] +yy = y[i,j] +zz = z[i,j] +pp = array([xx,yy,zz]) +print('Testing direct method in the point ({0}, {1}, {2})'.format(pp[0],pp[1],pp[2])) +for I in range(0,nx): + for J in range(0,ny): + # Get phi from this point + XX = x[I,J] + YY = y[I,J] + ZZ = z[I,J] + PP = array([XX,YY,ZZ]) + if((I,J) == (i,j)): + # if (I in range(i-1,i+2)) or (J in range(j-1,j+2)): + G,H = GH(PP,I,J,pp,nG,L,B,x,y,z,drx,dry,0.0, a,k,w,d) + else: + G = G_val(PP,pp)*dS + H = H_val(PP,pp)*dS + phi[i,j] = phi[i,j] - (p[I,J]*H[2] - gradp[I,J]*G) + # Get phi from the extended free surface + for II in range(-Nx,Nx+1): + for JJ in range(-Ny,Ny+1): + if (not II) and (not JJ): + # This is the computational domain + continue + XX = x[I,J] + II*L + YY = y[I,J] + JJ*B + ZZ = waves.z(XX,YY,0.0, a,k,w,d) + PP = array([XX,YY,ZZ]) + Phi = waves.phi(XX,YY,ZZ,0.0, a,k,w,d) + gPhi = waves.gradphi(XX,YY,ZZ,0.0, a,k,w,d)[2] + phi[i,j] = phi[i,j] - (Phi*H_val(PP,pp)[2] - gPhi*G_val(PP,pp))*dS +# Correct phi +phi[i,j] = 2.0*phi[i,j] +print('Computed = {0}, analitic = {1}\n'.format(phi[i,j],p[i,j])) + +# Compute the error along all the free surface +phi = zeros((nx,ny),dtype=float32) +error = 0.0 +done = 0 +print('Testing direct method in all the free surface') +for i in range(0,nx): + for j in range(0,ny): + if done != (100*(j + i*ny))/(nx*ny): + done = (100*(j + i*ny))/(nx*ny) + sys.stdout.write("{0}%...".format(done)) + sys.stdout.flush() + xx = x[i,j] + yy = y[i,j] + zz = z[i,j] + pp = array([xx,yy,zz]) + for I in range(0,nx): + for J in range(0,ny): + # Get phi from this point + XX = x[I,J] + YY = y[I,J] + ZZ = z[I,J] + PP = array([XX,YY,ZZ]) + if((I,J) == (i,j)): + # if (I in range(i-1,i+2)) or (J in range(j-1,j+2)): + G,H = GH(PP,I,J,pp,nG,L,B,x,y,z,drx,dry,0.0, a,k,w,d) + else: + G = G_val(PP,pp)*dS + H = H_val(PP,pp)*dS + phi[i,j] = phi[i,j] - (p[I,J]*H[2] - gradp[I,J]*G) + # Get phi from the extended free surface + for II in range(-Nx,Nx+1): + for JJ in range(-Ny,Ny+1): + if (not II) and (not JJ): + # This is the computational domain + continue + XX = x[I,J] + II*L + YY = y[I,J] + JJ*B + ZZ = waves.z(XX,YY,0.0, a,k,w,d) + PP = array([XX,YY,ZZ]) + Phi = waves.phi(XX,YY,ZZ,0.0, a,k,w,d) + gPhi = waves.gradphi(XX,YY,ZZ,0.0, a,k,w,d)[2] + phi[i,j] = phi[i,j] - (Phi*H_val(PP,pp)[2] - gPhi*G_val(PP,pp))*dS + # Correct phi + phi[i,j] = 2.0*phi[i,j] + error = error + (phi[i,j] - p[i,j])**2 +error = sqrt(error / (nx*ny)) +print('\nRoot mean square error = {0}\n'.format(error)) +fig = figure() +plot(x[:,plot_j], p[:,plot_j], color="blue", linewidth=2.5, linestyle="-", label="analitic") +plot(x[:,plot_j], phi[:,plot_j], color="red", linewidth=2.5, linestyle="-", label="interpolated") +legend(loc='best') +grid() +show() +close(fig) + +# Compute the BEM +GG = zeros((nx*ny, nx*ny), dtype=float32) +HH = -0.5 * array(identity(nx*ny),dtype=float32) +BB = zeros((nx*ny), dtype=float32) +error = 0.0 +done = 0 +print('Testing BEM in all the free surface') +for i in range(0,nx): + for j in range(0,ny): + if done != (100*(j + i*ny))/(nx*ny): + done = (100*(j + i*ny))/(nx*ny) + sys.stdout.write("{0}%...".format(done)) + sys.stdout.flush() + xx = x[i,j] + yy = y[i,j] + zz = z[i,j] + pp = array([xx,yy,zz]) + for I in range(0,nx): + for J in range(0,ny): + # Get phi from this point + XX = x[I,J] + YY = y[I,J] + ZZ = z[I,J] + PP = array([XX,YY,ZZ]) + if((I,J) == (i,j)): + # if (I in range(i-1,i+2)) or (J in range(j-1,j+2)): + G,H = GH(PP,I,J,pp,nG,L,B,x,y,z,drx,dry,0.0, a,k,w,d) + else: + G = G_val(PP,pp)*dS + H = H_val(PP,pp)*dS + GG[j + i*ny,J + I*ny] = GG[j + i*ny,J + I*ny] - G + HH[j + i*ny,J + I*ny] = HH[j + i*ny,J + I*ny] - H[2] + # Get phi from the extended free surface + for II in range(-Nx,Nx+1): + for JJ in range(-Ny,Ny+1): + if (not II) and (not JJ): + # This is the computational domain + continue + XX = x[I,J] + II*L + YY = y[I,J] + JJ*B + ZZ = waves.z(XX,YY,0.0, a,k,w,d) + PP = array([XX,YY,ZZ]) + Phi = waves.phi(XX,YY,ZZ,0.0, a,k,w,d) + gPhi = waves.gradphi(XX,YY,ZZ,0.0, a,k,w,d)[2] + BB[j + i*ny] = BB[j + i*ny] - (Phi*H_val(PP,pp)[2] - gPhi*G_val(PP,pp))*dS +[gPhi, residues, rank, s] = la.lstsq(GG, dot(HH,p.reshape(nx*ny)) + BB) +gPhi = gPhi.reshape(nx,ny) +if(rank < nx*ny): + print("Singular matrix G!.\n") + print("\tEffective rank of linear system matrix is %i (N = %i)\n" % (rank, nx*ny)) +for i in range(0,nx): + for j in range(0,ny): + error = error + (gPhi[i,j] - gradp[i,j])**2 +error = sqrt(error / (nx*ny)) +print('\nRoot mean square error = {0}\n'.format(error)) +fig = figure() +plot(x[:,plot_j], gradp[:,plot_j], color="blue", linewidth=2.5, linestyle="-", label="analitic") +plot(x[:,plot_j], gPhi[:,plot_j], color="red", linewidth=2.5, linestyle="-", label="interpolated") +legend(loc='best') +grid() +show() +close(fig) + diff --git a/src/Mod/Ship/simRun/theory/test/waves.py b/src/Mod/Ship/simRun/theory/test/waves.py new file mode 100644 index 000000000..1964be933 --- /dev/null +++ b/src/Mod/Ship/simRun/theory/test/waves.py @@ -0,0 +1,94 @@ +#*************************************************************************** +#* * +#* 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 numpy import * +from green import * + +def z(x,y,t, a,k,w,d): + """ Returns free surface shape + @param x X coordinate + @param y Y coordinate + @param t Time instant + @param a List of waves amplitudes + @param k List of waves k + @param w List of waves omega + @param d List of waves lags. + @return free surface elevation + """ + Z = 0.0 + for i in range(0,len(a)): + Z = Z + a[i]*sin(k[i]*x - w[i]*t + d[i]) + return Z + +def gradz(x,y,t, a,k,w,d): + """ Returns free surface shape gradient + @param x X coordinate + @param y Y coordinate + @param t Time instant + @param a List of waves amplitudes + @param k List of waves k + @param w List of waves omega + @param d List of waves lags. + @return free surface elevation + """ + gradZ = zeros((3), dtype=float32) + gradZ[2] = 1.0 + for i in range(0,len(a)): + gradZ[0] = gradZ[0] + a[i]*k[i]*cos(k[i]*x - w[i]*t + d[i]) + return gradZ + +def phi(x,y,z,t, a,k,w,d): + """ Returns velocity potential + @param x X coordinate + @param y Y coordinate + @param z Free surface elevation + @param t Time instant + @param a List of waves amplitudes + @param k List of waves k + @param w List of waves omega + @param d List of waves lags. + @return Velocity potential + """ + p = 0.0 + for i in range(0,len(a)): + p = p - a[i]*w[i]/k[i]*cos(k[i]*x - w[i]*t + d[i])*exp(k[i]*z) + return p + +def gradphi(x,y,z,t, a,k,w,d): + """ Returns velocity potential gradient + @param x X coordinate + @param y Y coordinate + @param z Free surface elevation + @param t Time instant + @param a List of waves amplitudes + @param k List of waves k + @param w List of waves omega + @param d List of waves lags. + @return velocity potential gradient + """ + gradp = zeros((3), dtype=float32) + for i in range(0,len(a)): + gradp[0] = gradp[0] + a[i]*w[i]*sin(k[i]*x - w[i]*t + d[i])*exp(k[i]*z) + gradp[2] = gradp[2] - a[i]*w[i]*cos(k[i]*x - w[i]*t + d[i])*exp(k[i]*z) + return gradp + From 2b38876e40659b1d1233cf5e8ca6c7ddb7927091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Luis=20Cerc=C3=B3s=20Pita?= Date: Mon, 20 May 2013 09:29:18 -0400 Subject: [PATCH 050/160] Managed situations when no tank volume can be found --- src/Mod/Ship/TankInstance.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Mod/Ship/TankInstance.py b/src/Mod/Ship/TankInstance.py index 8bb084bf9..d85db4856 100644 --- a/src/Mod/Ship/TankInstance.py +++ b/src/Mod/Ship/TankInstance.py @@ -735,9 +735,12 @@ def tankWeight(obj, angles=Vector(0.0,0.0,0.0), cor=Vector(0.0,0.0,0.0)): z = z0 + dz dx = bbox.XMax-bbox.XMin dy = bbox.YMax-bbox.YMin - box = Part.makeBox(3.0*(dx), 3.0*(dy), (z1-z0)+dz, Vector(bbox.XMin-dx, bbox.YMin-dy, bbox.ZMin-(z1-z0))) - fluid = s.common(box) - vol = fluid.Volume + try: + box = Part.makeBox(3.0*(dx), 3.0*(dy), (z1-z0)+dz, Vector(bbox.XMin-dx, bbox.YMin-dy, bbox.ZMin-(z1-z0))) + fluid = s.common(box) + vol = fluid.Volume + except: + vol = 0.0 W[0] = W[0] + vol*obj.Density # Compute fluid solid in rotated position (non linear rotation # are ussually computed as Roll -> Pitch -> Yaw). @@ -755,9 +758,12 @@ def tankWeight(obj, angles=Vector(0.0,0.0,0.0), cor=Vector(0.0,0.0,0.0)): while(abs(vol - v) > Error): z = z + (vol - v) / (dx*dy) dz = z - z0 - box = Part.makeBox(3.0*(dx), 3.0*(dy), (z1-z0)+dz, Vector(bbox.XMin-dx, bbox.YMin-dy, bbox.ZMin-(z1-z0))) - fluid = s.common(box) - v = fluid.Volume + try: + box = Part.makeBox(3.0*(dx), 3.0*(dy), (z1-z0)+dz, Vector(bbox.XMin-dx, bbox.YMin-dy, bbox.ZMin-(z1-z0))) + fluid = s.common(box) + v = fluid.Volume + except: + v = 0.0 if(abs(vol - v) / (dx*dy) <= 0.000001): break # Add fluid moments From 970c6a7fad36ea011e3a35262f7837c58219aae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Luis=20Cerc=C3=B3s=20Pita?= Date: Mon, 20 May 2013 12:09:21 -0400 Subject: [PATCH 051/160] Fixed main frame area coefficient --- src/Mod/Ship/shipHydrostatics/Tools.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Mod/Ship/shipHydrostatics/Tools.py b/src/Mod/Ship/shipHydrostatics/Tools.py index 8e4faab28..0929eeef3 100644 --- a/src/Mod/Ship/shipHydrostatics/Tools.py +++ b/src/Mod/Ship/shipHydrostatics/Tools.py @@ -322,13 +322,13 @@ def mainFrameCoeff(ship, draft): @param draft Draft. @return Main frame coefficient """ - cm = 0.0 - maxY = 0.0 - minY = 0.0 + cm = 0.0 + maxY = 0.0 + minY = 0.0 # We will take a duplicate of ship shape in order to place it shape = ship.Shape.copy() shape.translate(Vector(0.0,0.0,-draft)) - x = 0.0 + x = 0.0 area = 0.0 # Now we need to know the x range of values bbox = shape.BoundBox @@ -339,6 +339,8 @@ def mainFrameCoeff(ship, draft): B = bbox.YMax - bbox.YMin p = Vector(-1.5*L, -1.5*B, bbox.ZMin - 1.0) box = Part.makeBox(1.5*L + x, 3.0*B, - bbox.ZMin + 1.0, p) + maxY = bbox.YMin + minY = bbox.YMax # Compute common part with ship for s in shape.Solids: # Get solids intersection @@ -367,7 +369,7 @@ def mainFrameCoeff(ship, draft): # Valid face, compute area area = area + f.Area maxY = max(maxY, faceBounds.YMax) - minY = max(minY, faceBounds.YMin) + minY = min(minY, faceBounds.YMin) # Destroy last object generated App.ActiveDocument.removeObject(App.ActiveDocument.Objects[-1].Name) dy = maxY - minY From 9f2b514ae6bc15f5492c3223332999bae72b8aed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Luis=20Cerc=C3=B3s=20Pita?= Date: Mon, 20 May 2013 12:16:18 -0400 Subject: [PATCH 052/160] Prevented some errors in the floating coefficient computation --- src/Mod/Ship/shipHydrostatics/Tools.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Mod/Ship/shipHydrostatics/Tools.py b/src/Mod/Ship/shipHydrostatics/Tools.py index 0929eeef3..09123204f 100644 --- a/src/Mod/Ship/shipHydrostatics/Tools.py +++ b/src/Mod/Ship/shipHydrostatics/Tools.py @@ -253,6 +253,10 @@ def FloatingArea(ship, draft, trim): p = Vector(-1.5*L, -1.5*B, bbox.ZMin - 1.0) box = Part.makeBox(3.0*L, 3.0*B, - bbox.ZMin + 1.0, p) # Compute common part with ship + maxX = bbox.XMin + minX = bbox.XMax + maxY = bbox.YMin + minY = bbox.YMax for s in shape.Solids: # Get solids intersection try: From 213bc56c1c3b1c6e1defb1a37d37a1992642907e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Luis=20Cerc=C3=B3s=20Pita?= Date: Tue, 21 May 2013 08:21:15 -0400 Subject: [PATCH 053/160] Updated the windows installer --- src/WindowsInstaller/FreeCAD.wxs | 1 + src/WindowsInstaller/ModShip.wxi | 31 ++++++++++++++++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/WindowsInstaller/FreeCAD.wxs b/src/WindowsInstaller/FreeCAD.wxs index bd2d427f5..fd8e9e758 100644 --- a/src/WindowsInstaller/FreeCAD.wxs +++ b/src/WindowsInstaller/FreeCAD.wxs @@ -165,6 +165,7 @@ + diff --git a/src/WindowsInstaller/ModShip.wxi b/src/WindowsInstaller/ModShip.wxi index 03386f5e3..9e30d9210 100644 --- a/src/WindowsInstaller/ModShip.wxi +++ b/src/WindowsInstaller/ModShip.wxi @@ -24,12 +24,12 @@ - - - + + + @@ -45,6 +45,14 @@ + + + + + + + + @@ -118,17 +126,26 @@ - - - + + + + + + + + + + + + - + From 10fd202f95554a5a009258e33af1f437ea186e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Luis=20Cerc=C3=B3s=20Pita?= Date: Tue, 21 May 2013 08:24:58 -0400 Subject: [PATCH 054/160] Disabled simulations stuff for the master branch --- src/Mod/Ship/InitGui.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Mod/Ship/InitGui.py b/src/Mod/Ship/InitGui.py index 17aa80443..8fdf24c6c 100644 --- a/src/Mod/Ship/InitGui.py +++ b/src/Mod/Ship/InitGui.py @@ -51,6 +51,7 @@ class ShipWorkbench ( Workbench ): # Simulation stuff only if pyOpenCL & numpy are present hasOpenCL = True hasNumpy = True + hasSim = False # In development, activate it only for development purposes try: import pyopencl except ImportError: @@ -65,7 +66,7 @@ class ShipWorkbench ( Workbench ): msg = QtGui.QApplication.translate("ship_console", "numpy not installed, simulations stuff will disabled therefore", None,QtGui.QApplication.UnicodeUTF8) FreeCAD.Console.PrintMessage(msg + '\n') - if hasOpenCL and hasNumpy: + if hasOpenCL and hasNumpy and hasSim: simlist = ["Ship_CreateSim", "Ship_RunSim", "Ship_StopSim", "Ship_TrackSim"] self.appendToolbar(str(QtCore.QT_TRANSLATE_NOOP("Ship", "Simulation")),simlist) self.appendMenu(str(QtCore.QT_TRANSLATE_NOOP("Ship", "Simulation")),simlist) From 163fbe1dcd9fc538810041569efc25a444d7cc25 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 25 May 2013 01:45:37 +0200 Subject: [PATCH 055/160] Fix lock file issue on Linux --- src/Gui/Application.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index 915de9b8d..f93d3550b 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -1795,7 +1795,9 @@ void Application::checkForPreviousCrashes() QList locks = tmp.entryInfoList(); for (QList::iterator it = locks.begin(); it != locks.end(); ++it) { QString bn = it->baseName(); - if (bn.startsWith(exeName)) { + // ignore the lock file for this instance + QString pid = QString::number(QCoreApplication::applicationPid()); + if (bn.startsWith(exeName) && bn.indexOf(pid) < 0) { QString fn = it->absoluteFilePath(); boost::interprocess::file_lock flock((const char*)fn.toLocal8Bit()); if (flock.try_lock()) { From 152d2b895f69b436b448147508e5dda3435780b8 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 25 May 2013 13:30:01 +0200 Subject: [PATCH 056/160] Port to OCC 6.6 --- .../src/StdMeshers/StdMeshers_RadialPrism_3D.cpp | 7 +++++++ src/Mod/Part/App/TopoShapeSolidPyImp.cpp | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_RadialPrism_3D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_RadialPrism_3D.cpp index 133b68160..b88232be1 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_RadialPrism_3D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_RadialPrism_3D.cpp @@ -45,6 +45,9 @@ #include #include #include +#if OCC_VERSION_HEX >= 0x060600 +#include +#endif #include #include #include @@ -159,7 +162,11 @@ bool StdMeshers_RadialPrism_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& a // get 2 shells TopoDS_Solid solid = TopoDS::Solid( aShape ); +#if OCC_VERSION_HEX >= 0x060600 + TopoDS_Shell outerShell = BRepClass3d::OuterShell( solid ); +#else TopoDS_Shell outerShell = BRepTools::OuterShell( solid ); +#endif TopoDS_Shape innerShell; int nbShells = 0; for ( TopoDS_Iterator It (solid); It.More(); It.Next(), ++nbShells ) diff --git a/src/Mod/Part/App/TopoShapeSolidPyImp.cpp b/src/Mod/Part/App/TopoShapeSolidPyImp.cpp index 8af8b1300..f0ff38fed 100644 --- a/src/Mod/Part/App/TopoShapeSolidPyImp.cpp +++ b/src/Mod/Part/App/TopoShapeSolidPyImp.cpp @@ -25,6 +25,9 @@ #include #include +#if OCC_VERSION_HEX >= 0x060600 +#include +#endif #include #include #include @@ -178,7 +181,11 @@ Py::Object TopoShapeSolidPy::getOuterShell(void) const TopoDS_Shell shell; const TopoDS_Shape& shape = getTopoShapePtr()->_Shape; if (!shape.IsNull() && shape.ShapeType() == TopAbs_SOLID) +#if OCC_VERSION_HEX >= 0x060600 + shell = BRepClass3d::OuterShell(TopoDS::Solid(shape)); +#else shell = BRepTools::OuterShell(TopoDS::Solid(shape)); +#endif return Py::Object(new TopoShapeShellPy(new TopoShape(shell)),true); } From ff031ec4c62c90667568b2ee04c8ff761a27940c Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 25 May 2013 14:01:15 +0200 Subject: [PATCH 057/160] Show question dialog to ask user to continue when deleting an object --- src/Gui/CommandDoc.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Gui/CommandDoc.cpp b/src/Gui/CommandDoc.cpp index db858e01c..65c705f78 100644 --- a/src/Gui/CommandDoc.cpp +++ b/src/Gui/CommandDoc.cpp @@ -1050,6 +1050,15 @@ void StdCmdDelete::activated(int iMsg) } } + if (!doDeletion) { + int ret = QMessageBox::question(Gui::getMainWindow(), + qApp->translate("Std_Delete", "Object dependencies"), + qApp->translate("Std_Delete", "This object is referenced by other objects and thus these objects might get broken.\n" + "Are you sure to continue?"), + QMessageBox::Yes, QMessageBox::No); + if (ret == QMessageBox::Yes) + doDeletion = true; + } if (doDeletion) { (*it)->openTransaction("Delete"); for (std::vector::iterator ft = sel.begin(); ft != sel.end(); ++ft) { @@ -1063,11 +1072,6 @@ void StdCmdDelete::activated(int iMsg) } (*it)->commitTransaction(); } - else { - QMessageBox::warning(Gui::getMainWindow(), - qApp->translate("Std_Delete", "Object dependencies"), - qApp->translate("Std_Delete", "This object is referenced by other objects and thus cannot be deleted.")); - } } } } From fad26c93a5ce8ea6caccd3c6c852af3787762a3f Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 25 May 2013 14:02:26 +0200 Subject: [PATCH 058/160] Implement authenticate slot in download dialog --- src/Gui/DlgAuthorization.ui | 182 +++++++++++------------------------- src/Gui/DownloadDialog.cpp | 12 +++ 2 files changed, 69 insertions(+), 125 deletions(-) diff --git a/src/Gui/DlgAuthorization.ui b/src/Gui/DlgAuthorization.ui index 35fb1e567..b9e5592a7 100644 --- a/src/Gui/DlgAuthorization.ui +++ b/src/Gui/DlgAuthorization.ui @@ -1,10 +1,8 @@ - - - - + + Gui::Dialog::DlgAuthorization - - + + 0 0 @@ -12,107 +10,46 @@ 189 - + Authorization - + true - - - 11 - - - 6 - - - - - 0 - - - 6 - - - - - &OK - - - - - - true - - - true - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 140 - 20 - - - - - - - - &Cancel - - - - - - true - - - - - - - - - QLineEdit::Password + + + + + Username: - - - + + + + + + Password: - - - - - - - User name: + + + + QLineEdit::Password - + - + Qt::Vertical - + QSizePolicy::Expanding - + 21 41 @@ -120,48 +57,43 @@ + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Site: + + + + + + + + 75 + true + + + + %1 at %2 + + + true + + + - + username password - buttonOk - buttonCancel - - - buttonOk - clicked() - Gui::Dialog::DlgAuthorization - accept() - - - 20 - 20 - - - 20 - 20 - - - - - buttonCancel - clicked() - Gui::Dialog::DlgAuthorization - reject() - - - 20 - 20 - - - 20 - 20 - - - - + diff --git a/src/Gui/DownloadDialog.cpp b/src/Gui/DownloadDialog.cpp index 979e092ea..1c20d829d 100644 --- a/src/Gui/DownloadDialog.cpp +++ b/src/Gui/DownloadDialog.cpp @@ -27,7 +27,9 @@ # include #endif +#include #include "DownloadDialog.h" +#include "ui_DlgAuthorization.h" using namespace Gui::Dialog; @@ -202,6 +204,16 @@ void DownloadDialog::updateDataReadProgress(int bytesRead, int totalBytes) void DownloadDialog::slotAuthenticationRequired(const QString &hostName, quint16, QAuthenticator *authenticator) { + QDialog dlg; + Ui_DlgAuthorization ui; + ui.setupUi(&dlg); + dlg.adjustSize(); + ui.siteDescription->setText(tr("%1 at %2").arg(authenticator->realm()).arg(hostName)); + + if (dlg.exec() == QDialog::Accepted) { + authenticator->setUser(ui.username->text()); + authenticator->setPassword(ui.password->text()); + } } From d07fc1626866e8e8827ced93a7021645e67ee445 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 25 May 2013 16:58:20 +0200 Subject: [PATCH 059/160] Improve ruled surface feature --- src/Mod/Part/App/PartFeatures.cpp | 66 +++++++++++++++++++++++++++++++ src/Mod/Part/App/PartFeatures.h | 4 ++ 2 files changed, 70 insertions(+) diff --git a/src/Mod/Part/App/PartFeatures.cpp b/src/Mod/Part/App/PartFeatures.cpp index 57b9d9af0..dc239da90 100644 --- a/src/Mod/Part/App/PartFeatures.cpp +++ b/src/Mod/Part/App/PartFeatures.cpp @@ -24,6 +24,10 @@ #include "PreCompiled.h" #ifndef _PreComp_ # include +# include +# include +# include +# include # include # include # include @@ -32,7 +36,9 @@ # include # include # include +# include # include +# include #endif @@ -43,10 +49,14 @@ using namespace Part; PROPERTY_SOURCE(Part::RuledSurface, Part::Feature) +const char* RuledSurface::OrientationEnums[] = {"Automatic","Forward","Reversed",NULL}; + RuledSurface::RuledSurface() { ADD_PROPERTY_TYPE(Curve1,(0),"Ruled Surface",App::Prop_None,"Curve of ruled surface"); ADD_PROPERTY_TYPE(Curve2,(0),"Ruled Surface",App::Prop_None,"Curve of ruled surface"); + ADD_PROPERTY_TYPE(Orientation,((long)0),"Ruled Surface",App::Prop_None,"Orientation of ruled surface"); + Orientation.setEnums(OrientationEnums); } short RuledSurface::mustExecute() const @@ -55,6 +65,8 @@ short RuledSurface::mustExecute() const return 1; if (Curve2.isTouched()) return 1; + if (Orientation.isTouched()) + return 1; return 0; } @@ -109,6 +121,60 @@ App::DocumentObjectExecReturn *RuledSurface::execute(void) if (curve1.IsNull() || curve2.IsNull()) return new App::DocumentObjectExecReturn("Linked shapes are empty."); + + if (Orientation.getValue() == 0) { + // Automatic + Handle_Adaptor3d_HCurve a1; + Handle_Adaptor3d_HCurve a2; + if (curve1.ShapeType() == TopAbs_EDGE && curve2.ShapeType() == TopAbs_EDGE) { + BRepAdaptor_Curve adapt1(TopoDS::Edge(curve1)); + BRepAdaptor_Curve adapt2(TopoDS::Edge(curve2)); + a1 = new BRepAdaptor_HCurve(adapt1); + a2 = new BRepAdaptor_HCurve(adapt2); + } + else if (curve1.ShapeType() == TopAbs_WIRE && curve2.ShapeType() == TopAbs_WIRE) { + BRepAdaptor_CompCurve adapt1(TopoDS::Wire(curve1)); + BRepAdaptor_CompCurve adapt2(TopoDS::Wire(curve2)); + a1 = new BRepAdaptor_HCompCurve(adapt1); + a2 = new BRepAdaptor_HCompCurve(adapt2); + } + + if (!a1.IsNull() && !a2.IsNull()) { + // get end points of 1st curve + gp_Pnt p1 = a1->Value(a1->FirstParameter()); + gp_Pnt p2 = a1->Value(a1->LastParameter()); + if (curve1.Orientation() == TopAbs_REVERSED) { + std::swap(p1, p2); + } + + // get end points of 2nd curve + gp_Pnt p3 = a2->Value(a2->FirstParameter()); + gp_Pnt p4 = a2->Value(a2->LastParameter()); + if (curve2.Orientation() == TopAbs_REVERSED) { + std::swap(p3, p4); + } + + // Form two triangles (P1,P2,P3) and (P4,P3,P2) and check their normals. + // If the dot product is negative then it's assumed that the resulting face + // is twisted, hence the 2nd edge is reversed. + gp_Vec v1(p1, p2); + gp_Vec v2(p1, p3); + gp_Vec n1 = v1.Crossed(v2); + + gp_Vec v3(p4, p3); + gp_Vec v4(p4, p2); + gp_Vec n2 = v3.Crossed(v4); + + if (n1.Dot(n2) < 0) { + curve2.Reverse(); + } + } + } + else if (Orientation.getValue() == 2) { + // Reverse + curve2.Reverse(); + } + if (curve1.ShapeType() == TopAbs_EDGE && curve2.ShapeType() == TopAbs_EDGE) { TopoDS_Face face = BRepFill::Face(TopoDS::Edge(curve1), TopoDS::Edge(curve2)); this->Shape.setValue(face); diff --git a/src/Mod/Part/App/PartFeatures.h b/src/Mod/Part/App/PartFeatures.h index 0bf9971e1..609ac6f04 100644 --- a/src/Mod/Part/App/PartFeatures.h +++ b/src/Mod/Part/App/PartFeatures.h @@ -38,6 +38,7 @@ class RuledSurface : public Part::Feature public: RuledSurface(); + App::PropertyEnumeration Orientation; App::PropertyLinkSub Curve1; App::PropertyLinkSub Curve2; @@ -53,6 +54,9 @@ public: protected: void onChanged (const App::Property* prop); + +private: + static const char* OrientationEnums[]; }; class Loft : public Part::Feature From 376fdb4e919795244bd19966a3a419b84dc8cbf7 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 25 May 2013 23:46:28 +0200 Subject: [PATCH 060/160] Port to OCC 6.6 --- .../salomesmesh/src/StdMeshers/StdMeshers_RadialPrism_3D.cpp | 1 + src/Mod/Part/App/TopoShapeSolidPyImp.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_RadialPrism_3D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_RadialPrism_3D.cpp index b88232be1..fb6be0b1e 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_RadialPrism_3D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_RadialPrism_3D.cpp @@ -42,6 +42,7 @@ #include "utilities.h" +#include #include #include #include diff --git a/src/Mod/Part/App/TopoShapeSolidPyImp.cpp b/src/Mod/Part/App/TopoShapeSolidPyImp.cpp index f0ff38fed..15ef23bbd 100644 --- a/src/Mod/Part/App/TopoShapeSolidPyImp.cpp +++ b/src/Mod/Part/App/TopoShapeSolidPyImp.cpp @@ -23,6 +23,7 @@ #include "PreCompiled.h" +#include #include #include #if OCC_VERSION_HEX >= 0x060600 From 97dd5fd059a89bbf717adaf15e6f40674c01ab4b Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 27 May 2013 11:13:32 +0200 Subject: [PATCH 061/160] Pass argument to moc to fix problem with boost --- cMake/UseLibPack6x.cmake | 2 ++ cMake/UseLibPack7x.cmake | 2 ++ cMake/UseLibPack8x.cmake | 2 ++ cMake/UseLibPackCustom.cmake | 2 ++ 4 files changed, 8 insertions(+) diff --git a/cMake/UseLibPack6x.cmake b/cMake/UseLibPack6x.cmake index ef6bc2011..847ede524 100644 --- a/cMake/UseLibPack6x.cmake +++ b/cMake/UseLibPack6x.cmake @@ -196,6 +196,8 @@ include(AddFileDependencies) macro(fc_wrap_cpp outfiles ) QT4_EXTRACT_OPTIONS(moc_files moc_options ${ARGN}) + # fixes bug 0000585: bug with boost 1.48 + SET(moc_options ${moc_options} -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED) SET(ARGN) foreach(it ${moc_files}) get_filename_component(it ${it} ABSOLUTE) diff --git a/cMake/UseLibPack7x.cmake b/cMake/UseLibPack7x.cmake index 6063ef3b3..2e6ba13f6 100644 --- a/cMake/UseLibPack7x.cmake +++ b/cMake/UseLibPack7x.cmake @@ -207,6 +207,8 @@ include(AddFileDependencies) macro(fc_wrap_cpp outfiles ) QT4_EXTRACT_OPTIONS(moc_files moc_options ${ARGN}) + # fixes bug 0000585: bug with boost 1.48 + SET(moc_options ${moc_options} -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED) SET(ARGN) foreach(it ${moc_files}) get_filename_component(it ${it} ABSOLUTE) diff --git a/cMake/UseLibPack8x.cmake b/cMake/UseLibPack8x.cmake index 4def5d1f7..4b774a1d5 100644 --- a/cMake/UseLibPack8x.cmake +++ b/cMake/UseLibPack8x.cmake @@ -219,6 +219,8 @@ include(AddFileDependencies) macro(fc_wrap_cpp outfiles ) QT4_EXTRACT_OPTIONS(moc_files moc_options ${ARGN}) + # fixes bug 0000585: bug with boost 1.48 + SET(moc_options ${moc_options} -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED) SET(ARGN) foreach(it ${moc_files}) get_filename_component(it ${it} ABSOLUTE) diff --git a/cMake/UseLibPackCustom.cmake b/cMake/UseLibPackCustom.cmake index 740291a02..3747af21f 100644 --- a/cMake/UseLibPackCustom.cmake +++ b/cMake/UseLibPackCustom.cmake @@ -230,6 +230,8 @@ include(AddFileDependencies) macro(fc_wrap_cpp outfiles ) QT4_EXTRACT_OPTIONS(moc_files moc_options ${ARGN}) + # fixes bug 0000585: bug with boost 1.48 + SET(moc_options ${moc_options} -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED) SET(ARGN) foreach(it ${moc_files}) get_filename_component(it ${it} ABSOLUTE) From 2e31e177a8b03d9a58b4a35ddf19904e4dfc56bc Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 27 May 2013 11:25:50 +0200 Subject: [PATCH 062/160] Apply fix from mrlukeparry for datum labels --- src/Mod/Sketcher/Gui/SoDatumLabel.cpp | 28 ++-- src/Mod/Sketcher/Gui/SoDatumLabel.h | 2 + src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 146 +++++++++++--------- 3 files changed, 91 insertions(+), 85 deletions(-) diff --git a/src/Mod/Sketcher/Gui/SoDatumLabel.cpp b/src/Mod/Sketcher/Gui/SoDatumLabel.cpp index 3db2fb096..3a07a6e88 100644 --- a/src/Mod/Sketcher/Gui/SoDatumLabel.cpp +++ b/src/Mod/Sketcher/Gui/SoDatumLabel.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) 2011-2012 Luke Parry * + * Copyright (c) 2011-2012 Luke Parry * * * * This file is part of the FreeCAD CAx development system. * * * @@ -44,7 +44,6 @@ # include # include #endif - #include #include #include @@ -75,6 +74,7 @@ SoDatumLabel::SoDatumLabel() SO_NODE_ADD_FIELD(string, ("")); SO_NODE_ADD_FIELD(textColor, (SbVec3f(1.0f,1.0f,1.0f))); SO_NODE_ADD_FIELD(pnts, (SbVec3f(.0f,.0f,.0f))); + SO_NODE_ADD_FIELD(norm, (SbVec3f(.0f,.0f,1.f))); SO_NODE_ADD_FIELD(name, ("Helvetica")); SO_NODE_ADD_FIELD(size, (12.f)); @@ -88,7 +88,7 @@ SoDatumLabel::SoDatumLabel() SO_NODE_DEFINE_ENUM_VALUE(Type, ANGLE); SO_NODE_DEFINE_ENUM_VALUE(Type, RADIUS); SO_NODE_SET_SF_ENUM_TYPE(datumtype, Type); - + SO_NODE_ADD_FIELD(param1, (0.f)); SO_NODE_ADD_FIELD(param2, (0.f)); @@ -123,7 +123,7 @@ void SoDatumLabel::drawImage() QImage image(w, h,QImage::Format_ARGB32_Premultiplied); image.fill(0x00000000); - + QPainter painter(&image); painter.setRenderHint(QPainter::Antialiasing); @@ -191,7 +191,7 @@ void SoDatumLabel::generatePrimitives(SoAction * action) float c = cos(angle); img1 = SbVec3f((img1[0] * c) - (img1[1] * s), (img1[0] * s) + (img1[1] * c), 0.f); - img2 = SbVec3f((img2[0] * c) - (img2[1] * s), (img2[0] * s) + (img2[1] * c), 0.f); + img2 = SbVec3f((img2[0] * c) - (img2[1] * s), (img2[0] * s) + (img2[1] * c), 0.f); img3 = SbVec3f((img3[0] * c) - (img3[1] * s), (img3[0] * s) + (img3[1] * c), 0.f); img4 = SbVec3f((img4[0] * c) - (img4[1] * s), (img4[0] * s) + (img4[1] * c), 0.f); @@ -589,7 +589,7 @@ void SoDatumLabel::GLRender(SoGLRenderAction * action) // Get the Points SbVec3f p1 = pnts[0]; SbVec3f p2 = pnts[1]; - + SbVec3f dir = (p2-p1); dir.normalize(); SbVec3f norm (-dir[1],dir[0],0); @@ -668,7 +668,7 @@ void SoDatumLabel::GLRender(SoGLRenderAction * action) float range = this->param3.getValue(); float endangle = startangle + range; - + float r = 2*length; // Set the Text label angle to zero @@ -813,7 +813,7 @@ void SoDatumLabel::GLRender(SoGLRenderAction * action) std::vector corners; corners.push_back(p1); corners.push_back(p2); - + float minX = p1[0], minY = p1[1], maxX = p1[0] , maxY = p1[1]; for (std::vector::iterator it=corners.begin(); it != corners.end(); ++it) { minX = ((*it)[0] < minX) ? (*it)[0] : minX; @@ -829,18 +829,10 @@ void SoDatumLabel::GLRender(SoGLRenderAction * action) const unsigned char * dataptr = this->image.getValue(size, nc); - SbVec3f surfNorm(0.f, 0.f, 1.f) ; //Get the camera z-direction SbVec3f z = vv.zVector(); - const SbViewportRegion & vpr = SoViewportRegionElement::get(state); - SoGetMatrixAction getmatrixaction(vpr); - getmatrixaction.apply(action); - - SbMatrix transform = getmatrixaction.getMatrix(); - transform.multVecMatrix(surfNorm, surfNorm); - - bool flip = surfNorm.dot(z) > FLT_EPSILON; + bool flip = norm.getValue().dot(z) > FLT_EPSILON; glDisable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); // Enable Textures @@ -850,7 +842,7 @@ void SoDatumLabel::GLRender(SoGLRenderAction * action) // deleting the texture. I guess we don't need this texture and thus // comment out the block. // #0000721: massive memory leak when dragging an unconstrained model - // + // #if 0 // Copy the text bitmap into memory and bind GLuint myTexture; diff --git a/src/Mod/Sketcher/Gui/SoDatumLabel.h b/src/Mod/Sketcher/Gui/SoDatumLabel.h index a57f8b37c..40ed7d9d0 100644 --- a/src/Mod/Sketcher/Gui/SoDatumLabel.h +++ b/src/Mod/Sketcher/Gui/SoDatumLabel.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,7 @@ public: SoSFFloat param2; SoSFFloat param3; SoMFVec3f pnts; + SoSFVec3f norm; SoSFImage image; SoSFFloat lineWidth; diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 636100a5f..1d415ec10 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -1041,11 +1041,11 @@ void ViewProviderSketch::moveConstraint(int constNum, const Base::Vector2D &toPo } else { Base::Vector3d norm(-dir.y,dir.x,0); Constr->LabelDistance = vec.x * norm.x + vec.y * norm.y; - if (Constr->Type == Distance || - Constr->Type == DistanceX || Constr->Type == DistanceY) { + if (Constr->Type == Distance || + Constr->Type == DistanceX || Constr->Type == DistanceY) { vec = Base::Vector3d(toPos.fX, toPos.fY, 0) - (p2 + p1) / 2; Constr->LabelPosition = vec.x * dir.x + vec.y * dir.y; - } + } } } else if (Constr->Type == Angle) { @@ -1743,7 +1743,7 @@ void ViewProviderSketch::updateColor(void) type == Sketcher::Distance || type == Sketcher::DistanceX || type == Sketcher::DistanceY); - // Non DatumLabel Nodes will have a material excluding coincident + // Non DatumLabel Nodes will have a material excluding coincident bool hasMaterial = false; SoMaterial *m; @@ -1756,7 +1756,7 @@ void ViewProviderSketch::updateColor(void) if (hasDatumLabel) { SoDatumLabel *l = dynamic_cast(s->getChild(0)); l->textColor = SelectColor; - } else if (hasMaterial) + } else if (hasMaterial) m->diffuseColor = SelectColor; } else if (edit->PreselectConstraint == i) { if (hasDatumLabel) { @@ -2695,6 +2695,16 @@ void ViewProviderSketch::rebuildConstraintsVisual(void) SoMaterial *mat = new SoMaterial; mat->ref(); mat->diffuseColor = ConstrDimColor; + // Get sketch normal + Base::Vector3d RN(0,0,1); + + // move to position of Sketch + Base::Placement Plz = getSketchObject()->Placement.getValue(); + Base::Rotation tmp(Plz.getRotation()); + tmp.multVec(RN,RN); + Plz.setRotation(tmp); + + SbVec3f norm(RN.x, RN.y, RN.z); // distinguish different constraint types to build up switch ((*it)->Type) { @@ -2703,85 +2713,87 @@ void ViewProviderSketch::rebuildConstraintsVisual(void) case DistanceY: case Radius: case Angle: - { - SoDatumLabel *text = new SoDatumLabel(); - text->string = ""; - text->textColor = ConstrDimColor; - SoAnnotation *anno = new SoAnnotation(); - anno->renderCaching = SoSeparator::OFF; - anno->addChild(text); - sep->addChild(text); - edit->constrGroup->addChild(anno); - edit->vConstrType.push_back((*it)->Type); - // nodes not needed - sep->unref(); - mat->unref(); - continue; // jump to next constraint - } - break; + { + SoDatumLabel *text = new SoDatumLabel(); + text->norm.setValue(norm); + text->string = ""; + text->textColor = ConstrDimColor; + SoAnnotation *anno = new SoAnnotation(); + anno->renderCaching = SoSeparator::OFF; + anno->addChild(text); + sep->addChild(text); + edit->constrGroup->addChild(anno); + edit->vConstrType.push_back((*it)->Type); + // nodes not needed + sep->unref(); + mat->unref(); + continue; // jump to next constraint + } + break; case Horizontal: case Vertical: - { - sep->addChild(mat); - sep->addChild(new SoZoomTranslation()); // 1. - sep->addChild(new SoImage()); // 2. constraint icon + { + sep->addChild(mat); + sep->addChild(new SoZoomTranslation()); // 1. + sep->addChild(new SoImage()); // 2. constraint icon - // remember the type of this constraint node - edit->vConstrType.push_back((*it)->Type); - } - break; + // remember the type of this constraint node + edit->vConstrType.push_back((*it)->Type); + } + break; case Coincident: // no visual for coincident so far edit->vConstrType.push_back(Coincident); break; case Parallel: case Perpendicular: case Equal: - { - // Add new nodes to Constraint Seperator - sep->addChild(mat); - sep->addChild(new SoZoomTranslation()); // 1. - sep->addChild(new SoImage()); // 2. first constraint icon - sep->addChild(new SoZoomTranslation()); // 3. - sep->addChild(new SoImage()); // 4. second constraint icon + { + // Add new nodes to Constraint Seperator + sep->addChild(mat); + sep->addChild(new SoZoomTranslation()); // 1. + sep->addChild(new SoImage()); // 2. first constraint icon + sep->addChild(new SoZoomTranslation()); // 3. + sep->addChild(new SoImage()); // 4. second constraint icon - // remember the type of this constraint node - edit->vConstrType.push_back((*it)->Type); - } - break; + // remember the type of this constraint node + edit->vConstrType.push_back((*it)->Type); + } + break; case PointOnObject: case Tangent: - { - // Add new nodes to Constraint Seperator - sep->addChild(mat); - sep->addChild(new SoZoomTranslation()); // 1. - sep->addChild(new SoImage()); // 2. constraint icon + { + // Add new nodes to Constraint Seperator + sep->addChild(mat); + sep->addChild(new SoZoomTranslation()); // 1. + sep->addChild(new SoImage()); // 2. constraint icon - if ((*it)->Type == Tangent) { - const Part::Geometry *geo1 = getSketchObject()->getGeometry((*it)->First); - const Part::Geometry *geo2 = getSketchObject()->getGeometry((*it)->Second); - if (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId() && - geo2->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { - sep->addChild(new SoZoomTranslation()); - sep->addChild(new SoImage()); // 3. second constraint icon + if ((*it)->Type == Tangent) { + const Part::Geometry *geo1 = getSketchObject()->getGeometry((*it)->First); + const Part::Geometry *geo2 = getSketchObject()->getGeometry((*it)->Second); + if (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId() && + geo2->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { + sep->addChild(new SoZoomTranslation()); + sep->addChild(new SoImage()); // 3. second constraint icon } - } - - edit->vConstrType.push_back((*it)->Type); } - break; + + edit->vConstrType.push_back((*it)->Type); + } + break; case Symmetric: - { - SoDatumLabel *arrows = new SoDatumLabel(); - arrows->string = ""; - arrows->textColor = ConstrDimColor; + { + SoDatumLabel *arrows = new SoDatumLabel(); + arrows->norm.setValue(norm); + arrows->string = ""; + arrows->textColor = ConstrDimColor; - sep->addChild(arrows); // 0. - sep->addChild(new SoTranslation()); // 1. - sep->addChild(new SoImage()); // 2. constraint icon + sep->addChild(arrows); // 0. + sep->addChild(new SoTranslation()); // 1. + sep->addChild(new SoImage()); // 2. constraint icon - edit->vConstrType.push_back((*it)->Type); - } - break; + edit->vConstrType.push_back((*it)->Type); + } + break; default: edit->vConstrType.push_back(None); } @@ -3195,7 +3207,7 @@ void ViewProviderSketch::setPositionText(const Base::Vector2D &Pos, const SbStri edit->textX->string = text; edit->textPos->translation = SbVec3f(Pos.fX,Pos.fY,zText); } - + void ViewProviderSketch::setPositionText(const Base::Vector2D &Pos) { SbString text; From 3db10284b1bf19d863782ec296273f9d12a76dff Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 28 May 2013 18:14:58 +0200 Subject: [PATCH 063/160] 0000952: Download manager --- src/Gui/CMakeLists.txt | 10 + src/Gui/DlgAuthorization.ui | 4 +- src/Gui/DownloadItem.cpp | 536 ++++++++++++++++++++++++++++++++ src/Gui/DownloadItem.h | 153 +++++++++ src/Gui/DownloadItem.ui | 141 +++++++++ src/Gui/DownloadManager.cpp | 303 ++++++++++++++++++ src/Gui/DownloadManager.h | 116 +++++++ src/Gui/DownloadManager.ui | 83 +++++ src/Gui/Icons/process-stop.svg | 336 ++++++++++++++++++++ src/Gui/Icons/resource.qrc | 1 + src/Gui/MainWindow.cpp | 8 + src/Mod/Web/Gui/BrowserView.cpp | 11 +- src/Mod/Web/Gui/BrowserView.h | 1 + 13 files changed, 1699 insertions(+), 4 deletions(-) create mode 100644 src/Gui/DownloadItem.cpp create mode 100644 src/Gui/DownloadItem.h create mode 100644 src/Gui/DownloadItem.ui create mode 100644 src/Gui/DownloadManager.cpp create mode 100644 src/Gui/DownloadManager.h create mode 100644 src/Gui/DownloadManager.ui create mode 100644 src/Gui/Icons/process-stop.svg diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 43fa94ed7..ea63ba08c 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -99,6 +99,8 @@ set(Gui_MOC_HDRS Control.h DemoMode.h DownloadDialog.h + DownloadItem.h + DownloadManager.h DlgActionsImp.h DlgActivateWindowImp.h DlgCommandsImp.h @@ -220,6 +222,8 @@ SET(Gui_UIC_SRCS DlgTreeWidget.ui DlgLocationAngle.ui DlgLocationPos.ui + DownloadManager.ui + DownloadItem.ui MouseButtons.ui SceneInspector.ui InputVector.ui @@ -282,6 +286,8 @@ SET(Dialog_CPP_SRCS TextureMapping.cpp Transform.cpp DownloadDialog.cpp + DownloadItem.cpp + DownloadManager.cpp ) SET(Dialog_HPP_SRCS @@ -307,6 +313,8 @@ SET(Dialog_HPP_SRCS TextureMapping.h Transform.h DownloadDialog.h + DownloadItem.h + DownloadManager.h ) SET(Dialog_SRCS @@ -327,6 +335,8 @@ SET(Dialog_SRCS DlgProjectUtility.ui DlgTipOfTheDay.ui DlgTreeWidget.ui + DownloadManager.ui + DownloadItem.ui MouseButtons.ui InputVector.ui Placement.ui diff --git a/src/Gui/DlgAuthorization.ui b/src/Gui/DlgAuthorization.ui index b9e5592a7..afbed6e51 100644 --- a/src/Gui/DlgAuthorization.ui +++ b/src/Gui/DlgAuthorization.ui @@ -6,8 +6,8 @@ 0 0 - 304 - 189 + 284 + 128 diff --git a/src/Gui/DownloadItem.cpp b/src/Gui/DownloadItem.cpp new file mode 100644 index 000000000..29b14a68b --- /dev/null +++ b/src/Gui/DownloadItem.cpp @@ -0,0 +1,536 @@ +/*************************************************************************** + * Copyright (c) 2013 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., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "DownloadItem.h" +#include "DownloadManager.h" +#include "Application.h" +#include "Document.h" +#include "MainWindow.h" +#include "FileDialog.h" +#include "ui_DlgAuthorization.h" + +using namespace Gui::Dialog; + + +EditTableView::EditTableView(QWidget *parent) + : QTableView(parent) +{ +} + +void EditTableView::keyPressEvent(QKeyEvent *event) +{ + if ((event->key() == Qt::Key_Delete + || event->key() == Qt::Key_Backspace) + && model()) { + removeOne(); + } else { + QAbstractItemView::keyPressEvent(event); + } +} + +void EditTableView::removeOne() +{ + if (!model() || !selectionModel()) + return; + int row = currentIndex().row(); + model()->removeRow(row, rootIndex()); + QModelIndex idx = model()->index(row, 0, rootIndex()); + if (!idx.isValid()) + idx = model()->index(row - 1, 0, rootIndex()); + selectionModel()->select(idx, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); +} + +void EditTableView::removeAll() +{ + if (model()) + model()->removeRows(0, model()->rowCount(rootIndex()), rootIndex()); +} + +// ---------------------------------------------------------------------------- + +SqueezeLabel::SqueezeLabel(QWidget *parent) : QLabel(parent) +{ +} + +void SqueezeLabel::paintEvent(QPaintEvent *event) +{ + QFontMetrics fm = fontMetrics(); + if (fm.width(text()) > contentsRect().width()) { + QString elided = fm.elidedText(text(), Qt::ElideMiddle, width()); + QString oldText = text(); + setText(elided); + QLabel::paintEvent(event); + setText(oldText); + } else { + QLabel::paintEvent(event); + } +} + +// ---------------------------------------------------------------------------- + +#define AUTOSAVE_IN 1000 * 3 // seconds +#define MAXWAIT 1000 * 15 // seconds + +AutoSaver::AutoSaver(QObject *parent) : QObject(parent) +{ + Q_ASSERT(parent); +} + +AutoSaver::~AutoSaver() +{ + if (m_timer.isActive()) + qWarning() << "AutoSaver: still active when destroyed, changes not saved."; +} + +void AutoSaver::changeOccurred() +{ + if (m_firstChange.isNull()) + m_firstChange.start(); + + if (m_firstChange.elapsed() > MAXWAIT) { + saveIfNeccessary(); + } else { + m_timer.start(AUTOSAVE_IN, this); + } +} + +void AutoSaver::timerEvent(QTimerEvent *event) +{ + if (event->timerId() == m_timer.timerId()) { + saveIfNeccessary(); + } else { + QObject::timerEvent(event); + } +} + +void AutoSaver::saveIfNeccessary() +{ + if (!m_timer.isActive()) + return; + m_timer.stop(); + m_firstChange = QTime(); + if (!QMetaObject::invokeMethod(parent(), "save", Qt::DirectConnection)) { + qWarning() << "AutoSaver: error invoking slot save() on parent"; + } +} + +// ---------------------------------------------------------------------------- + +NetworkAccessManager::NetworkAccessManager(QObject *parent) + : QNetworkAccessManager(parent) +{ + connect(this, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), + SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + connect(this, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)), + SLOT(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*))); + + QNetworkDiskCache *diskCache = new QNetworkDiskCache(this); + QString location = QDesktopServices::storageLocation(QDesktopServices::CacheLocation); + diskCache->setCacheDirectory(location); + setCache(diskCache); +} + +void NetworkAccessManager::authenticationRequired(QNetworkReply *reply, QAuthenticator *auth) +{ + QWidget *mainWindow = Gui::getMainWindow(); + + QDialog dialog(mainWindow); + dialog.setWindowFlags(Qt::Sheet); + + Ui_DlgAuthorization passwordDialog; + passwordDialog.setupUi(&dialog); + dialog.adjustSize(); + + QString introMessage = tr("Enter username and password for \"%1\" at %2"); + introMessage = introMessage.arg(Qt::escape(reply->url().toString())).arg(Qt::escape(reply->url().toString())); + passwordDialog.siteDescription->setText(introMessage); + passwordDialog.siteDescription->setWordWrap(true); + + if (dialog.exec() == QDialog::Accepted) { + auth->setUser(passwordDialog.username->text()); + auth->setPassword(passwordDialog.password->text()); + } +} + +void NetworkAccessManager::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth) +{ + QWidget *mainWindow = Gui::getMainWindow(); + + QDialog dialog(mainWindow); + dialog.setWindowFlags(Qt::Sheet); + + Ui_DlgAuthorization proxyDialog; + proxyDialog.setupUi(&dialog); + dialog.adjustSize(); + + QString introMessage = tr("Connect to proxy \"%1\" using:"); + introMessage = introMessage.arg(Qt::escape(proxy.hostName())); + proxyDialog.siteDescription->setText(introMessage); + proxyDialog.siteDescription->setWordWrap(true); + + if (dialog.exec() == QDialog::Accepted) { + auth->setUser(proxyDialog.username->text()); + auth->setPassword(proxyDialog.password->text()); + } +} + +// ---------------------------------------------------------------------------- + +DownloadItem::DownloadItem(QNetworkReply *reply, bool requestFileName, QWidget *parent) + : QWidget(parent) + , m_reply(reply) + , m_requestFileName(requestFileName) + , m_bytesReceived(0) +{ + setupUi(this); + QPalette p = downloadInfoLabel->palette(); + p.setColor(QPalette::Text, Qt::darkGray); + downloadInfoLabel->setPalette(p); + progressBar->setMaximum(0); + tryAgainButton->hide(); + connect(stopButton, SIGNAL(clicked()), this, SLOT(stop())); + connect(openButton, SIGNAL(clicked()), this, SLOT(open())); + connect(tryAgainButton, SIGNAL(clicked()), this, SLOT(tryAgain())); + + init(); +} + +void DownloadItem::init() +{ + if (!m_reply) + return; + + // attach to the m_reply + m_url = m_reply->url(); + m_reply->setParent(this); + connect(m_reply, SIGNAL(readyRead()), this, SLOT(downloadReadyRead())); + connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), + this, SLOT(error(QNetworkReply::NetworkError))); + connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), + this, SLOT(downloadProgress(qint64, qint64))); + connect(m_reply, SIGNAL(metaDataChanged()), + this, SLOT(metaDataChanged())); + connect(m_reply, SIGNAL(finished()), + this, SLOT(finished())); + + // reset info + downloadInfoLabel->clear(); + progressBar->setValue(0); + getFileName(); + + // start timer for the download estimation + m_downloadTime.start(); + + if (m_reply->error() != QNetworkReply::NoError) { + error(m_reply->error()); + finished(); + } +} + +void DownloadItem::getFileName() +{ + QSettings settings; + settings.beginGroup(QLatin1String("downloadmanager")); + //QString defaultLocation = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation); + QString defaultLocation = Gui::FileDialog::getWorkingDirectory(); + QString downloadDirectory = settings.value(QLatin1String("downloadDirectory"), defaultLocation).toString(); + if (!downloadDirectory.isEmpty()) + downloadDirectory += QLatin1Char('/'); + + QString defaultFileName = saveFileName(downloadDirectory); + QString fileName = defaultFileName; + if (m_requestFileName) { + fileName = QFileDialog::getSaveFileName(this, tr("Save File"), defaultFileName); + if (fileName.isEmpty()) { + m_reply->close(); + fileNameLabel->setText(tr("Download canceled: %1").arg(QFileInfo(defaultFileName).fileName())); + return; + } + } + m_output.setFileName(fileName); + fileNameLabel->setText(QFileInfo(m_output.fileName()).fileName()); + if (m_requestFileName) + downloadReadyRead(); +} + +QString DownloadItem::saveFileName(const QString &directory) const +{ + // Move this function into QNetworkReply to also get file name sent from the server + QString path = m_url.path(); + if (!m_fileName.isEmpty()) + path = m_fileName; + QFileInfo info(path); + QString baseName = info.completeBaseName(); + QString endName = info.suffix(); + + if (baseName.isEmpty()) { + baseName = QLatin1String("unnamed_download"); + qDebug() << "DownloadManager:: downloading unknown file:" << m_url; + } + QString name = directory + baseName + QLatin1Char('.') + endName; + if (QFile::exists(name)) { + // already exists, don't overwrite + int i = 1; + do { + name = directory + baseName + QLatin1Char('-') + QString::number(i++) + QLatin1Char('.') + endName; + } while (QFile::exists(name)); + } + return name; +} + + +void DownloadItem::stop() +{ + setUpdatesEnabled(false); + stopButton->setEnabled(false); + stopButton->hide(); + tryAgainButton->setEnabled(true); + tryAgainButton->show(); + setUpdatesEnabled(true); + m_reply->abort(); +} + +void DownloadItem::open() +{ + QFileInfo info(m_output); + QString selectedFilter; + QStringList fileList; + fileList << info.absoluteFilePath(); + SelectModule::Dict dict = SelectModule::importHandler(fileList, selectedFilter); + + // load the files with the associated modules + if (!dict.isEmpty()) { + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + if (doc) { + for (SelectModule::Dict::iterator it = dict.begin(); it != dict.end(); ++it) { + Gui::Application::Instance->importFrom(it.key().toUtf8(), + doc->getDocument()->getName(), it.value().toAscii()); + } + } + else { + for (SelectModule::Dict::iterator it = dict.begin(); it != dict.end(); ++it) { + Gui::Application::Instance->open(it.key().toUtf8(), it.value().toAscii()); + } + } + } + else { + QUrl url = QUrl::fromLocalFile(info.absolutePath()); + QDesktopServices::openUrl(url); + } +} + +void DownloadItem::tryAgain() +{ + if (!tryAgainButton->isEnabled()) + return; + + tryAgainButton->setEnabled(false); + tryAgainButton->setVisible(false); + stopButton->setEnabled(true); + stopButton->setVisible(true); + progressBar->setVisible(true); + + QNetworkReply *r = DownloadManager::getInstance()->networkAccessManager()->get(QNetworkRequest(m_url)); + if (m_reply) + m_reply->deleteLater(); + if (m_output.exists()) + m_output.remove(); + m_reply = r; + init(); + /*emit*/ statusChanged(); +} + +void DownloadItem::downloadReadyRead() +{ + if (m_requestFileName && m_output.fileName().isEmpty()) + return; + if (!m_output.isOpen()) { + // in case someone else has already put a file there + if (!m_requestFileName) + getFileName(); + if (!m_output.open(QIODevice::WriteOnly)) { + downloadInfoLabel->setText(tr("Error opening save file: %1") + .arg(m_output.errorString())); + stopButton->click(); + /*emit*/ statusChanged(); + return; + } + /*emit*/ statusChanged(); + } + if (-1 == m_output.write(m_reply->readAll())) { + downloadInfoLabel->setText(tr("Error saving: %1") + .arg(m_output.errorString())); + stopButton->click(); + } +} + +void DownloadItem::error(QNetworkReply::NetworkError) +{ + qDebug() << "DownloadItem::error" << m_reply->errorString() << m_url; + downloadInfoLabel->setText(tr("Network Error: %1").arg(m_reply->errorString())); + tryAgainButton->setEnabled(true); + tryAgainButton->setVisible(true); +} + +void DownloadItem::metaDataChanged() +{ + if (m_reply->hasRawHeader(QByteArray("Content-Disposition"))) { + QByteArray header = m_reply->rawHeader(QByteArray("Content-Disposition")); + int index = header.indexOf("filename="); + if (index > 0) { + header = header.mid(index+9); + m_fileName = QUrl::fromPercentEncoding(header); + } + else { + index = header.indexOf("filename*=UTF-8''"); + if (index > 0) { + header = header.mid(index+17); + m_fileName = QUrl::fromPercentEncoding(header); + } + } + } + + QVariant statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); + if (!statusCode.isValid()) + return; + int status = statusCode.toInt(); + if (status != 200) { + QString reason = m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(); + qDebug() << reason; + } +} + +void DownloadItem::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) +{ + m_bytesReceived = bytesReceived; + if (bytesTotal == -1) { + progressBar->setValue(0); + progressBar->setMaximum(0); + } else { + progressBar->setValue(bytesReceived); + progressBar->setMaximum(bytesTotal); + } + updateInfoLabel(); +} + +void DownloadItem::updateInfoLabel() +{ + if (m_reply->error() == QNetworkReply::NoError) + return; + + qint64 bytesTotal = progressBar->maximum(); + bool running = !downloadedSuccessfully(); + + // update info label + double speed = m_bytesReceived * 1000.0 / m_downloadTime.elapsed(); + double timeRemaining = ((double)(bytesTotal - m_bytesReceived)) / speed; + QString timeRemainingString = tr("seconds"); + if (timeRemaining > 60) { + timeRemaining = timeRemaining / 60; + timeRemainingString = tr("minutes"); + } + timeRemaining = floor(timeRemaining); + + // When downloading the eta should never be 0 + if (timeRemaining == 0) + timeRemaining = 1; + + QString info; + if (running) { + QString remaining; + if (bytesTotal != 0) + remaining = tr("- %4 %5 remaining") + .arg(timeRemaining) + .arg(timeRemainingString); + info = QString(tr("%1 of %2 (%3/sec) %4")) + .arg(dataString(m_bytesReceived)) + .arg(bytesTotal == 0 ? tr("?") : dataString(bytesTotal)) + .arg(dataString((int)speed)) + .arg(remaining); + } else { + if (m_bytesReceived == bytesTotal) + info = dataString(m_output.size()); + else + info = tr("%1 of %2 - Stopped") + .arg(dataString(m_bytesReceived)) + .arg(dataString(bytesTotal)); + } + downloadInfoLabel->setText(info); +} + +QString DownloadItem::dataString(int size) const +{ + QString unit; + if (size < 1024) { + unit = tr("bytes"); + } else if (size < 1024*1024) { + size /= 1024; + unit = tr("kB"); + } else { + size /= 1024*1024; + unit = tr("MB"); + } + return QString(QLatin1String("%1 %2")).arg(size).arg(unit); +} + +bool DownloadItem::downloading() const +{ + return (progressBar->isVisible()); +} + +bool DownloadItem::downloadedSuccessfully() const +{ + return (stopButton->isHidden() && tryAgainButton->isHidden()); +} + +void DownloadItem::finished() +{ + progressBar->hide(); + stopButton->setEnabled(false); + stopButton->hide(); + m_output.close(); + updateInfoLabel(); + /*emit*/ statusChanged(); +} + +#include "moc_DownloadItem.cpp" diff --git a/src/Gui/DownloadItem.h b/src/Gui/DownloadItem.h new file mode 100644 index 000000000..ea828eb43 --- /dev/null +++ b/src/Gui/DownloadItem.h @@ -0,0 +1,153 @@ +/*************************************************************************** + * Copyright (c) 2013 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., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef GUI_DIALOG_DOWNLOADITEM_H +#define GUI_DIALOG_DOWNLOADITEM_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class AutoSaver; +class QFileIconProvider; + +class EditTableView : public QTableView +{ + Q_OBJECT + +public: + EditTableView(QWidget *parent = 0); + void keyPressEvent(QKeyEvent *event); + +public Q_SLOTS: + void removeOne(); + void removeAll(); +}; + +class SqueezeLabel : public QLabel +{ + Q_OBJECT + +public: + SqueezeLabel(QWidget *parent = 0); + +protected: + void paintEvent(QPaintEvent *event); + +}; + +/* + This class will call the save() slot on the parent object when the parent changes. + It will wait several seconds after changed() to combining multiple changes and + prevent continuous writing to disk. + */ +class AutoSaver : public QObject { + +Q_OBJECT + +public: + AutoSaver(QObject *parent); + ~AutoSaver(); + void saveIfNeccessary(); + +public Q_SLOTS: + void changeOccurred(); + +protected: + void timerEvent(QTimerEvent *event); + +private: + QBasicTimer m_timer; + QTime m_firstChange; + +}; + +class NetworkAccessManager : public QNetworkAccessManager +{ + Q_OBJECT + +public: + NetworkAccessManager(QObject *parent = 0); + +private Q_SLOTS: + void authenticationRequired(QNetworkReply *reply, QAuthenticator *auth); + void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth); +}; + +#include "ui_DownloadItem.h" + +namespace Gui { +namespace Dialog { +class DownloadModel; + +class DownloadItem : public QWidget, public Ui_DownloadItem +{ + Q_OBJECT + +Q_SIGNALS: + void statusChanged(); + +public: + DownloadItem(QNetworkReply *reply = 0, bool requestFileName = false, QWidget *parent = 0); + bool downloading() const; + bool downloadedSuccessfully() const; + + QUrl m_url; + QString m_fileName; + + QFile m_output; + QNetworkReply *m_reply; + +private Q_SLOTS: + void stop(); + void tryAgain(); + void open(); + + void downloadReadyRead(); + void error(QNetworkReply::NetworkError code); + void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); + void metaDataChanged(); + void finished(); + +private: + void getFileName(); + void init(); + void updateInfoLabel(); + QString dataString(int size) const; + + QString saveFileName(const QString &directory) const; + + bool m_requestFileName; + qint64 m_bytesReceived; + QTime m_downloadTime; +}; + +} // namespace Dialog +} // namespace Gui + +#endif // GUI_DIALOG_DOWNLOADITEM_H diff --git a/src/Gui/DownloadItem.ui b/src/Gui/DownloadItem.ui new file mode 100644 index 000000000..b6dd8b34b --- /dev/null +++ b/src/Gui/DownloadItem.ui @@ -0,0 +1,141 @@ + + + DownloadItem + + + + 0 + 0 + 423 + 98 + + + + Form + + + + 0 + + + + + + 0 + 0 + + + + Ico + + + + + + + + + + 0 + 0 + + + + Filename + + + + + + + 0 + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + Qt::Vertical + + + + 17 + 1 + + + + + + + + false + + + + :/icons/view-refresh.svg:/icons/view-refresh.svg + + + + + + + + :/icons/process-stop.svg:/icons/process-stop.svg + + + + + + + + :/icons/document-open.svg:/icons/document-open.svg + + + + + + + Qt::Vertical + + + + 17 + 5 + + + + + + + + + + + SqueezeLabel + QWidget +

DownloadItem.h
+ + + + + + + + diff --git a/src/Gui/DownloadManager.cpp b/src/Gui/DownloadManager.cpp new file mode 100644 index 000000000..8846863ec --- /dev/null +++ b/src/Gui/DownloadManager.cpp @@ -0,0 +1,303 @@ +/*************************************************************************** + * Copyright (c) 2013 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., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DownloadItem.h" +#include "DownloadManager.h" +#include "ui_DownloadManager.h" +#include "DockWindowManager.h" +#include "MainWindow.h" + +using namespace Gui::Dialog; + +/* TRANSLATOR Gui::Dialog::DownloadManager */ + +DownloadManager* DownloadManager::self = 0; + +DownloadManager* DownloadManager::getInstance() +{ + if (!self) + self = new DownloadManager(Gui::getMainWindow()); + return self; +} + +DownloadManager::DownloadManager(QWidget *parent) + : QDialog(parent) + , m_autoSaver(new AutoSaver(this)) + , m_manager(new NetworkAccessManager(this)) + , m_iconProvider(0) + , m_removePolicy(Never) + , ui(new Ui_DownloadManager()) +{ + ui->setupUi(this); + ui->downloadsView->setShowGrid(false); + ui->downloadsView->verticalHeader()->hide(); + ui->downloadsView->horizontalHeader()->hide(); + ui->downloadsView->setAlternatingRowColors(true); + ui->downloadsView->horizontalHeader()->setStretchLastSection(true); + m_model = new DownloadModel(this); + ui->downloadsView->setModel(m_model); + connect(ui->cleanupButton, SIGNAL(clicked()), this, SLOT(cleanup())); + load(); + + Gui::DockWindowManager* pDockMgr = Gui::DockWindowManager::instance(); + QDockWidget* dw = pDockMgr->addDockWindow(QT_TR_NOOP("Download Manager"), + this, Qt::BottomDockWidgetArea); + dw->setFeatures(QDockWidget::DockWidgetMovable|QDockWidget::DockWidgetFloatable); + dw->show(); +} + +DownloadManager::~DownloadManager() +{ + m_autoSaver->changeOccurred(); + m_autoSaver->saveIfNeccessary(); + if (m_iconProvider) + delete m_iconProvider; + delete ui; +} + +int DownloadManager::activeDownloads() const +{ + int count = 0; + for (int i = 0; i < m_downloads.count(); ++i) { + if (m_downloads.at(i)->stopButton->isEnabled()) + ++count; + } + return count; +} + +void DownloadManager::download(const QNetworkRequest &request, bool requestFileName) +{ + if (request.url().isEmpty()) + return; + handleUnsupportedContent(m_manager->get(request), requestFileName); +} + +void DownloadManager::handleUnsupportedContent(QNetworkReply *reply, bool requestFileName) +{ + if (!reply || reply->url().isEmpty()) + return; + QVariant header = reply->header(QNetworkRequest::ContentLengthHeader); + bool ok; + int size = header.toInt(&ok); + if (ok && size == 0) + return; + + DownloadItem *item = new DownloadItem(reply, requestFileName, this); + addItem(item); +} + +void DownloadManager::addItem(DownloadItem *item) +{ + connect(item, SIGNAL(statusChanged()), this, SLOT(updateRow())); + int row = m_downloads.count(); + m_model->beginInsertRows(QModelIndex(), row, row); + m_downloads.append(item); + m_model->endInsertRows(); + updateItemCount(); + show(); + ui->downloadsView->setIndexWidget(m_model->index(row, 0), item); + QIcon icon = style()->standardIcon(QStyle::SP_FileIcon); + item->fileIcon->setPixmap(icon.pixmap(48, 48)); + ui->downloadsView->setRowHeight(row, item->sizeHint().height()); +} + +void DownloadManager::updateRow() +{ + DownloadItem *item = qobject_cast(sender()); + int row = m_downloads.indexOf(item); + if (-1 == row) + return; + if (!m_iconProvider) + m_iconProvider = new QFileIconProvider(); + QIcon icon = m_iconProvider->icon(item->m_output.fileName()); + if (icon.isNull()) + icon = style()->standardIcon(QStyle::SP_FileIcon); + item->fileIcon->setPixmap(icon.pixmap(48, 48)); + ui->downloadsView->setRowHeight(row, item->minimumSizeHint().height()); + + bool remove = false; + QWebSettings *globalSettings = QWebSettings::globalSettings(); + if (!item->downloading() + && globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled)) + remove = true; + + if (item->downloadedSuccessfully() + && removePolicy() == DownloadManager::SuccessFullDownload) { + remove = true; + } + if (remove) + m_model->removeRow(row); + + ui->cleanupButton->setEnabled(m_downloads.count() - activeDownloads() > 0); +} + +DownloadManager::RemovePolicy DownloadManager::removePolicy() const +{ + return m_removePolicy; +} + +void DownloadManager::setRemovePolicy(RemovePolicy policy) +{ + if (policy == m_removePolicy) + return; + m_removePolicy = policy; + m_autoSaver->changeOccurred(); +} + +void DownloadManager::save() const +{ + QSettings settings; + settings.beginGroup(QLatin1String("downloadmanager")); + QMetaEnum removePolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("RemovePolicy")); + settings.setValue(QLatin1String("removeDownloadsPolicy"), QLatin1String(removePolicyEnum.valueToKey(m_removePolicy))); + settings.setValue(QLatin1String("size"), size()); + if (m_removePolicy == Exit) + return; + + for (int i = 0; i < m_downloads.count(); ++i) { + QString key = QString(QLatin1String("download_%1_")).arg(i); + settings.setValue(key + QLatin1String("url"), m_downloads[i]->m_url); + settings.setValue(key + QLatin1String("location"), QFileInfo(m_downloads[i]->m_output).filePath()); + settings.setValue(key + QLatin1String("done"), m_downloads[i]->downloadedSuccessfully()); + } + int i = m_downloads.count(); + QString key = QString(QLatin1String("download_%1_")).arg(i); + while (settings.contains(key + QLatin1String("url"))) { + settings.remove(key + QLatin1String("url")); + settings.remove(key + QLatin1String("location")); + settings.remove(key + QLatin1String("done")); + key = QString(QLatin1String("download_%1_")).arg(++i); + } +} + +void DownloadManager::load() +{ + QSettings settings; + settings.beginGroup(QLatin1String("downloadmanager")); + QSize size = settings.value(QLatin1String("size")).toSize(); + if (size.isValid()) + resize(size); + QByteArray value = settings.value(QLatin1String("removeDownloadsPolicy"), QLatin1String("Never")).toByteArray(); + QMetaEnum removePolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("RemovePolicy")); + m_removePolicy = removePolicyEnum.keyToValue(value) == -1 ? + Never : + static_cast(removePolicyEnum.keyToValue(value)); + + int i = 0; + QString key = QString(QLatin1String("download_%1_")).arg(i); + while (settings.contains(key + QLatin1String("url"))) { + QUrl url = settings.value(key + QLatin1String("url")).toUrl(); + QString fileName = settings.value(key + QLatin1String("location")).toString(); + bool done = settings.value(key + QLatin1String("done"), true).toBool(); + if (!url.isEmpty() && !fileName.isEmpty()) { + DownloadItem *item = new DownloadItem(0, this); + item->m_output.setFileName(fileName); + item->fileNameLabel->setText(QFileInfo(item->m_output.fileName()).fileName()); + item->m_url = url; + item->stopButton->setVisible(false); + item->stopButton->setEnabled(false); + item->tryAgainButton->setVisible(!done); + item->tryAgainButton->setEnabled(!done); + item->progressBar->setVisible(!done); + addItem(item); + } + key = QString(QLatin1String("download_%1_")).arg(++i); + } + ui->cleanupButton->setEnabled(m_downloads.count() - activeDownloads() > 0); +} + +void DownloadManager::cleanup() +{ + if (m_downloads.isEmpty()) + return; + m_model->removeRows(0, m_downloads.count()); + updateItemCount(); + if (m_downloads.isEmpty() && m_iconProvider) { + delete m_iconProvider; + m_iconProvider = 0; + } + m_autoSaver->changeOccurred(); +} + +void DownloadManager::updateItemCount() +{ + int count = m_downloads.count(); + ui->itemCount->setText(count == 1 ? tr("1 Download") : tr("%1 Downloads").arg(count)); +} + +// ---------------------------------------------------------------------------- + +DownloadModel::DownloadModel(DownloadManager *downloadManager, QObject *parent) + : QAbstractListModel(parent) + , m_downloadManager(downloadManager) +{ +} + +QVariant DownloadModel::data(const QModelIndex &index, int role) const +{ + if (index.row() < 0 || index.row() >= rowCount(index.parent())) + return QVariant(); + if (role == Qt::ToolTipRole) + if (!m_downloadManager->m_downloads.at(index.row())->downloadedSuccessfully()) + return m_downloadManager->m_downloads.at(index.row())->downloadInfoLabel->text(); + return QVariant(); +} + +int DownloadModel::rowCount(const QModelIndex &parent) const +{ + return (parent.isValid()) ? 0 : m_downloadManager->m_downloads.count(); +} + +bool DownloadModel::removeRows(int row, int count, const QModelIndex &parent) +{ + if (parent.isValid()) + return false; + + int lastRow = row + count - 1; + for (int i = lastRow; i >= row; --i) { + if (m_downloadManager->m_downloads.at(i)->downloadedSuccessfully() + || m_downloadManager->m_downloads.at(i)->tryAgainButton->isEnabled()) { + beginRemoveRows(parent, i, i); + m_downloadManager->m_downloads.takeAt(i)->deleteLater(); + endRemoveRows(); + } + } + m_downloadManager->m_autoSaver->changeOccurred(); + return true; +} + +#include "moc_DownloadManager.cpp" diff --git a/src/Gui/DownloadManager.h b/src/Gui/DownloadManager.h new file mode 100644 index 000000000..48d847eef --- /dev/null +++ b/src/Gui/DownloadManager.h @@ -0,0 +1,116 @@ +/*************************************************************************** + * Copyright (c) 2013 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., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef GUI_DIALOG_DOWNLOADMANAGER_H +#define GUI_DIALOG_DOWNLOADMANAGER_H + +#include +#include +#include +#include + +class AutoSaver; +class QFileIconProvider; + +namespace Gui { +namespace Dialog { +class DownloadItem; +class DownloadModel; +class Ui_DownloadManager; + +class GuiExport DownloadManager : public QDialog +{ + Q_OBJECT + Q_PROPERTY(RemovePolicy removePolicy READ removePolicy WRITE setRemovePolicy) + Q_ENUMS(RemovePolicy) + +public: + enum RemovePolicy { + Never, + Exit, + SuccessFullDownload + }; + + static DownloadManager* getInstance(); + +private: + DownloadManager(QWidget *parent = 0); + ~DownloadManager(); + +public: + int activeDownloads() const; + QNetworkAccessManager * networkAccessManager() + { return m_manager; } + + RemovePolicy removePolicy() const; + void setRemovePolicy(RemovePolicy policy); + +public Q_SLOTS: + void download(const QNetworkRequest &request, bool requestFileName = false); + inline void download(const QUrl &url, bool requestFileName = false) + { download(QNetworkRequest(url), requestFileName); } + void handleUnsupportedContent(QNetworkReply *reply, bool requestFileName = false); + void cleanup(); + +private Q_SLOTS: + void save() const; + void updateRow(); + +private: + void addItem(DownloadItem *item); + void updateItemCount(); + void load(); + + AutoSaver *m_autoSaver; + DownloadModel *m_model; + QNetworkAccessManager *m_manager; + QFileIconProvider *m_iconProvider; + QList m_downloads; + RemovePolicy m_removePolicy; + friend class DownloadModel; + +private: + Ui_DownloadManager* ui; + static DownloadManager* self; +}; + +class DownloadModel : public QAbstractListModel +{ + friend class DownloadManager; + Q_OBJECT + +public: + DownloadModel(DownloadManager *downloadManager, QObject *parent = 0); + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); + +private: + DownloadManager *m_downloadManager; + +}; + +} // namespace Dialog +} // namespace Gui + +#endif // GUI_DIALOG_DOWNLOADMANAGER_H diff --git a/src/Gui/DownloadManager.ui b/src/Gui/DownloadManager.ui new file mode 100644 index 000000000..a040b0585 --- /dev/null +++ b/src/Gui/DownloadManager.ui @@ -0,0 +1,83 @@ + + Gui::Dialog::DownloadManager + + + + 0 + 0 + 332 + 252 + + + + Downloads + + + + 0 + + + 0 + + + + + + + + + + false + + + Clean up + + + + + + + Qt::Horizontal + + + + 58 + 24 + + + + + + + + + + 0 Items + + + + + + + Qt::Horizontal + + + + 148 + 20 + + + + + + + + + EditTableView + QTableView +
DownloadItem.h
+
+
+ + +
diff --git a/src/Gui/Icons/process-stop.svg b/src/Gui/Icons/process-stop.svg new file mode 100644 index 000000000..04ce3a79f --- /dev/null +++ b/src/Gui/Icons/process-stop.svg @@ -0,0 +1,336 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + Stop + 2005-10-16 + + + Andreas Nilsson + + + + + stop + halt + error + + + + + + Jakub Steiner + + + + + + + + + + + + + + + + + + diff --git a/src/Gui/Icons/resource.qrc b/src/Gui/Icons/resource.qrc index e506168b6..e27da77af 100644 --- a/src/Gui/Icons/resource.qrc +++ b/src/Gui/Icons/resource.qrc @@ -49,6 +49,7 @@ edit-edit.svg help-browser.svg preferences-system.svg + process-stop.svg window-new.svg camera-photo.svg applications-accessories.svg diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index e9b621430..a46388adb 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -64,6 +64,8 @@ #include "MainWindow.h" #include "Application.h" #include "Assistant.h" +#include "DownloadDialog.h" +#include "DownloadManager.h" #include "WaitCursor.h" #include "Action.h" @@ -1543,6 +1545,12 @@ void MainWindow::loadUrls(App::Document* doc, const QList& url) (const char*)info.absoluteFilePath().toUtf8()); } } + else if (it->scheme().toLower() == QLatin1String("http")) { + Gui::Dialog::DownloadManager::getInstance()->download(*it); + } + else if (it->scheme().toLower() == QLatin1String("ftp")) { + Gui::Dialog::DownloadManager::getInstance()->download(*it); + } } const char *docName = doc ? doc->getName() : "Unnamed"; diff --git a/src/Mod/Web/Gui/BrowserView.cpp b/src/Mod/Web/Gui/BrowserView.cpp index 5e53f872d..7e73a404c 100644 --- a/src/Mod/Web/Gui/BrowserView.cpp +++ b/src/Mod/Web/Gui/BrowserView.cpp @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -119,6 +120,8 @@ BrowserView::BrowserView(QWidget* parent) this, SLOT(onLinkClicked(const QUrl &))); connect(view->page(), SIGNAL(downloadRequested(const QNetworkRequest &)), this, SLOT(onDownloadRequested(const QNetworkRequest &))); + connect(view->page(), SIGNAL(unsupportedContent(QNetworkReply*)), + this, SLOT(onUnsupportedContent(QNetworkReply*))); } /** Destroys the object and frees any allocated resources */ @@ -181,8 +184,12 @@ bool BrowserView::chckHostAllowed(const QString& host) void BrowserView::onDownloadRequested(const QNetworkRequest & request) { - Dialog::DownloadDialog dlg (request.url(),this); - dlg.exec(); + Gui::Dialog::DownloadManager::getInstance()->download(request); +} + +void BrowserView::onUnsupportedContent(QNetworkReply* reply) +{ + Gui::Dialog::DownloadManager::getInstance()->handleUnsupportedContent(reply); } void BrowserView::load(const char* URL) diff --git a/src/Mod/Web/Gui/BrowserView.h b/src/Mod/Web/Gui/BrowserView.h index 553ccd160..3ba3ee035 100644 --- a/src/Mod/Web/Gui/BrowserView.h +++ b/src/Mod/Web/Gui/BrowserView.h @@ -96,6 +96,7 @@ protected Q_SLOTS: void onLinkClicked (const QUrl& url); bool chckHostAllowed(const QString& host); void onDownloadRequested(const QNetworkRequest& request); + void onUnsupportedContent(QNetworkReply* reply); private: WebView* view; From 2896efe58488a113b403d3d8e1c1d2199dc4f524 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 29 May 2013 12:38:01 +0200 Subject: [PATCH 064/160] 0000952: Download manager --- src/Gui/DownloadItem.cpp | 27 +++++++++++++++++++++++++++ src/Gui/DownloadItem.h | 2 ++ src/Gui/MainWindow.cpp | 20 ++++++++++++++++++-- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/Gui/DownloadItem.cpp b/src/Gui/DownloadItem.cpp index 29b14a68b..a86c5527b 100644 --- a/src/Gui/DownloadItem.cpp +++ b/src/Gui/DownloadItem.cpp @@ -26,7 +26,9 @@ #include #include +#include #include +#include #include #include #include @@ -289,6 +291,7 @@ void DownloadItem::getFileName() } m_output.setFileName(fileName); fileNameLabel->setText(QFileInfo(m_output.fileName()).fileName()); + fileNameLabel->setToolTip(m_output.fileName()); if (m_requestFileName) downloadReadyRead(); } @@ -359,6 +362,13 @@ void DownloadItem::open() } } +void DownloadItem::openFolder() +{ + QFileInfo info(m_output); + QUrl url = QUrl::fromLocalFile(info.absolutePath()); + QDesktopServices::openUrl(url); +} + void DownloadItem::tryAgain() { if (!tryAgainButton->isEnabled()) @@ -380,6 +390,14 @@ void DownloadItem::tryAgain() /*emit*/ statusChanged(); } +void DownloadItem::contextMenuEvent (QContextMenuEvent * e) +{ + QMenu menu; + QAction* a = menu.addAction(tr("Open containing folder"), this, SLOT(openFolder())); + a->setEnabled(m_output.exists()); + menu.exec(e->globalPos()); +} + void DownloadItem::downloadReadyRead() { if (m_requestFileName && m_output.fileName().isEmpty()) @@ -395,6 +413,7 @@ void DownloadItem::downloadReadyRead() /*emit*/ statusChanged(); return; } + downloadInfoLabel->setToolTip(m_url.toString()); /*emit*/ statusChanged(); } if (-1 == m_output.write(m_reply->readAll())) { @@ -419,12 +438,20 @@ void DownloadItem::metaDataChanged() int index = header.indexOf("filename="); if (index > 0) { header = header.mid(index+9); + if (header.startsWith("\"") || header.startsWith("'")) + header = header.mid(1); + if (header.endsWith("\"") || header.endsWith("'")) + header.chop(1); m_fileName = QUrl::fromPercentEncoding(header); } else { index = header.indexOf("filename*=UTF-8''"); if (index > 0) { header = header.mid(index+17); + if (header.startsWith("\"") || header.startsWith("'")) + header = header.mid(1); + if (header.endsWith("\"") || header.endsWith("'")) + header.chop(1); m_fileName = QUrl::fromPercentEncoding(header); } } diff --git a/src/Gui/DownloadItem.h b/src/Gui/DownloadItem.h index ea828eb43..a357fffe9 100644 --- a/src/Gui/DownloadItem.h +++ b/src/Gui/DownloadItem.h @@ -127,6 +127,7 @@ private Q_SLOTS: void stop(); void tryAgain(); void open(); + void openFolder(); void downloadReadyRead(); void error(QNetworkReply::NetworkError code); @@ -135,6 +136,7 @@ private Q_SLOTS: void finished(); private: + void contextMenuEvent(QContextMenuEvent *); void getFileName(); void init(); void updateInfoLabel(); diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index a46388adb..3c003b7ea 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -1401,10 +1401,21 @@ void MainWindow::dragEnterEvent (QDragEnterEvent * e) { // Here we must allow uri drafs and check them in dropEvent const QMimeData* data = e->mimeData(); - if (data->hasUrls()) + if (data->hasUrls()) { +#ifdef QT_NO_OPENSSL + QList urls = data->urls(); + for (QList::ConstIterator it = urls.begin(); it != urls.end(); ++it) { + if (it->scheme().toLower() == QLatin1String("https")) { + e->ignore(); + return; + } + } +#endif e->accept(); - else + } + else { e->ignore(); + } } QMimeData * MainWindow::createMimeDataFromSelection () const @@ -1548,6 +1559,11 @@ void MainWindow::loadUrls(App::Document* doc, const QList& url) else if (it->scheme().toLower() == QLatin1String("http")) { Gui::Dialog::DownloadManager::getInstance()->download(*it); } +#ifndef QT_NO_OPENSSL + else if (it->scheme().toLower() == QLatin1String("https")) { + Gui::Dialog::DownloadManager::getInstance()->download(*it); + } +#endif else if (it->scheme().toLower() == QLatin1String("ftp")) { Gui::Dialog::DownloadManager::getInstance()->download(*it); } From 26d1751aeb1727d79dd8b76c44e056478a904129 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 29 May 2013 17:57:25 +0200 Subject: [PATCH 065/160] 0000952: Download manager --- src/Gui/DownloadItem.cpp | 26 +++++++++++++++++++++++--- src/Gui/DownloadItem.h | 2 +- src/Mod/Web/Gui/BrowserView.cpp | 20 ++++++++------------ src/Mod/Web/Gui/BrowserView.h | 1 + 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/Gui/DownloadItem.cpp b/src/Gui/DownloadItem.cpp index a86c5527b..216a08e09 100644 --- a/src/Gui/DownloadItem.cpp +++ b/src/Gui/DownloadItem.cpp @@ -269,12 +269,32 @@ void DownloadItem::init() } } +QString DownloadItem::getDownloadDirectory() const +{ + QString exe = QString::fromAscii(App::GetApplication().getExecutableName()); + QString path = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); + QString dirPath = QDir(path).filePath(exe); + Base::Reference hPath = App::GetApplication().GetUserParameter().GetGroup("BaseApp") + ->GetGroup("Preferences")->GetGroup("General"); + std::string dir = hPath->GetASCII("DownloadPath", ""); + if (!dir.empty()) { + dirPath = QString::fromUtf8(dir.c_str()); + } + + if (QFileInfo(dirPath).exists() || QDir().mkpath(dirPath)) { + return dirPath; + } + else { + return path; + } +} + void DownloadItem::getFileName() { QSettings settings; settings.beginGroup(QLatin1String("downloadmanager")); //QString defaultLocation = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation); - QString defaultLocation = Gui::FileDialog::getWorkingDirectory(); + QString defaultLocation = getDownloadDirectory(); QString downloadDirectory = settings.value(QLatin1String("downloadDirectory"), defaultLocation).toString(); if (!downloadDirectory.isEmpty()) downloadDirectory += QLatin1Char('/'); @@ -436,7 +456,7 @@ void DownloadItem::metaDataChanged() if (m_reply->hasRawHeader(QByteArray("Content-Disposition"))) { QByteArray header = m_reply->rawHeader(QByteArray("Content-Disposition")); int index = header.indexOf("filename="); - if (index > 0) { + if (index >= 0) { header = header.mid(index+9); if (header.startsWith("\"") || header.startsWith("'")) header = header.mid(1); @@ -446,7 +466,7 @@ void DownloadItem::metaDataChanged() } else { index = header.indexOf("filename*=UTF-8''"); - if (index > 0) { + if (index >= 0) { header = header.mid(index+17); if (header.startsWith("\"") || header.startsWith("'")) header = header.mid(1); diff --git a/src/Gui/DownloadItem.h b/src/Gui/DownloadItem.h index a357fffe9..2503f2ca0 100644 --- a/src/Gui/DownloadItem.h +++ b/src/Gui/DownloadItem.h @@ -141,7 +141,7 @@ private: void init(); void updateInfoLabel(); QString dataString(int size) const; - + QString getDownloadDirectory() const; QString saveFileName(const QString &directory) const; bool m_requestFileName; diff --git a/src/Mod/Web/Gui/BrowserView.cpp b/src/Mod/Web/Gui/BrowserView.cpp index 7e73a404c..1a72d21c7 100644 --- a/src/Mod/Web/Gui/BrowserView.cpp +++ b/src/Mod/Web/Gui/BrowserView.cpp @@ -143,17 +143,7 @@ void BrowserView::onLinkClicked (const QUrl & url) //QString fragment = url. fragment(); if (scheme==QString::fromLatin1("http")) { - bool ok = false; - if (ok) { - //Dialog::DownloadDialog dlg (url,this/*QString::fromLatin1("c:/temp/test.fcstd")*/); - //int result = dlg.exec(); - //if(ext ==QString::fromLatin1("fcstd") ) - // Gui::Command::doCommand(Gui::Command::Gui,"Gui.open('c:/temp/test.fcstd')"); - } - else { - load(url); - } - //OpenURLInBrowser(url.toString().toLatin1()); + load(url); } // run scripts if not from somewhere else! if ((scheme.size() < 2 || scheme==QString::fromLatin1("file"))&& host.isEmpty()) { @@ -189,7 +179,13 @@ void BrowserView::onDownloadRequested(const QNetworkRequest & request) void BrowserView::onUnsupportedContent(QNetworkReply* reply) { - Gui::Dialog::DownloadManager::getInstance()->handleUnsupportedContent(reply); + // Do not call handleUnsupportedContent() directly otherwise we won't get + // the metaDataChanged() signal of the reply. + Gui::Dialog::DownloadManager::getInstance()->download(reply->url()); + // Due to setting the policy QWebPage::DelegateAllLinks the onLinkClicked() + // slot is called even when clicking on a downloadable file but the page + // then fails to load. Thus, we reload the previous url. + view->reload(); } void BrowserView::load(const char* URL) diff --git a/src/Mod/Web/Gui/BrowserView.h b/src/Mod/Web/Gui/BrowserView.h index 3ba3ee035..64bcbd4b7 100644 --- a/src/Mod/Web/Gui/BrowserView.h +++ b/src/Mod/Web/Gui/BrowserView.h @@ -35,6 +35,7 @@ class QWebView; class QUrl; class QNetworkRequest; +class QNetworkReply; namespace WebGui { From ab012f5beeae157bb7bd0c604b7274f8d089b60e Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 30 May 2013 17:03:52 +0200 Subject: [PATCH 066/160] Port to Coin3d 4.x --- src/Gui/SoTextLabel.cpp | 205 +++++++++++++++++++++------------------- 1 file changed, 107 insertions(+), 98 deletions(-) diff --git a/src/Gui/SoTextLabel.cpp b/src/Gui/SoTextLabel.cpp index 9fac1484c..71b29852c 100644 --- a/src/Gui/SoTextLabel.cpp +++ b/src/Gui/SoTextLabel.cpp @@ -45,6 +45,7 @@ # include #endif +#include #include #include #include @@ -55,7 +56,11 @@ #include #include #include +#if COIN_MAJOR_VERSION > 3 +#include +#else #include +#endif #include "SoTextLabel.h" #include "SoFCInteractiveElement.h" @@ -250,7 +255,11 @@ void SoTextLabel::GLRender(SoGLRenderAction *action) // disable textures for all units SoGLTextureEnabledElement::set(state, this, FALSE); +#if COIN_MAJOR_VERSION > 3 + SoMultiTextureEnabledElement::set(state, this, FALSE); +#else SoGLTexture3EnabledElement::set(state, this, FALSE); +#endif glPushAttrib(GL_ENABLE_BIT | GL_PIXEL_MODE_BIT | GL_COLOR_BUFFER_BIT); glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); @@ -285,40 +294,40 @@ void SoTextLabel::GLRender(SoGLRenderAction *action) inherited::GLRender(action); } - -// ------------------------------------------------------ - -SO_NODE_SOURCE(SoStringLabel); - -void SoStringLabel::initClass() -{ - SO_NODE_INIT_CLASS(SoStringLabel, SoNode, "Node"); -} - -SoStringLabel::SoStringLabel() -{ - SO_NODE_CONSTRUCTOR(SoStringLabel); - SO_NODE_ADD_FIELD(string, ("")); - SO_NODE_ADD_FIELD(textColor, (SbVec3f(1.0f,1.0f,1.0f))); - SO_NODE_ADD_FIELD(name, ("Helvetica")); - SO_NODE_ADD_FIELD(size, (12)); -} - -/** - * Renders the open edges only. - */ -void SoStringLabel::GLRender(SoGLRenderAction *action) -{ - QGLWidget* window; - SoState * state = action->getState(); - state->push(); - SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR); - SoGLWidgetElement::get(state, window); - if (!window) { - state->pop(); - return; - } - + +// ------------------------------------------------------ + +SO_NODE_SOURCE(SoStringLabel); + +void SoStringLabel::initClass() +{ + SO_NODE_INIT_CLASS(SoStringLabel, SoNode, "Node"); +} + +SoStringLabel::SoStringLabel() +{ + SO_NODE_CONSTRUCTOR(SoStringLabel); + SO_NODE_ADD_FIELD(string, ("")); + SO_NODE_ADD_FIELD(textColor, (SbVec3f(1.0f,1.0f,1.0f))); + SO_NODE_ADD_FIELD(name, ("Helvetica")); + SO_NODE_ADD_FIELD(size, (12)); +} + +/** + * Renders the open edges only. + */ +void SoStringLabel::GLRender(SoGLRenderAction *action) +{ + QGLWidget* window; + SoState * state = action->getState(); + state->push(); + SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR); + SoGLWidgetElement::get(state, window); + if (!window) { + state->pop(); + return; + } + // Enter in 2D screen mode glMatrixMode(GL_PROJECTION); glPushMatrix(); @@ -375,46 +384,46 @@ void SoStringLabel::GLRender(SoGLRenderAction *action) glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); - - state->pop(); -} - -// ------------------------------------------------------ - -SO_NODE_SOURCE(SoFrameLabel); - -void SoFrameLabel::initClass() -{ - SO_NODE_INIT_CLASS(SoFrameLabel, SoImage, "Image"); -} - -SoFrameLabel::SoFrameLabel() -{ - SO_NODE_CONSTRUCTOR(SoFrameLabel); - SO_NODE_ADD_FIELD(string, ("")); - SO_NODE_ADD_FIELD(textColor, (SbVec3f(1.0f,1.0f,1.0f))); - SO_NODE_ADD_FIELD(backgroundColor, (SbVec3f(0.0f,0.333f,1.0f))); - SO_NODE_ADD_FIELD(justification, (LEFT)); - SO_NODE_ADD_FIELD(name, ("Helvetica")); - SO_NODE_ADD_FIELD(size, (12)); - SO_NODE_ADD_FIELD(frame, (TRUE)); - //SO_NODE_ADD_FIELD(image, (SbVec2s(0,0), 0, NULL)); -} - -void SoFrameLabel::notify(SoNotList * list) -{ - SoField *f = list->getLastField(); - if (f == &this->string || - f == &this->textColor || - f == &this->backgroundColor || - f == &this->justification || - f == &this->name || - f == &this->size || - f == &this->frame) { - drawImage(); - } - inherited::notify(list); -} + + state->pop(); +} + +// ------------------------------------------------------ + +SO_NODE_SOURCE(SoFrameLabel); + +void SoFrameLabel::initClass() +{ + SO_NODE_INIT_CLASS(SoFrameLabel, SoImage, "Image"); +} + +SoFrameLabel::SoFrameLabel() +{ + SO_NODE_CONSTRUCTOR(SoFrameLabel); + SO_NODE_ADD_FIELD(string, ("")); + SO_NODE_ADD_FIELD(textColor, (SbVec3f(1.0f,1.0f,1.0f))); + SO_NODE_ADD_FIELD(backgroundColor, (SbVec3f(0.0f,0.333f,1.0f))); + SO_NODE_ADD_FIELD(justification, (LEFT)); + SO_NODE_ADD_FIELD(name, ("Helvetica")); + SO_NODE_ADD_FIELD(size, (12)); + SO_NODE_ADD_FIELD(frame, (TRUE)); + //SO_NODE_ADD_FIELD(image, (SbVec2s(0,0), 0, NULL)); +} + +void SoFrameLabel::notify(SoNotList * list) +{ + SoField *f = list->getLastField(); + if (f == &this->string || + f == &this->textColor || + f == &this->backgroundColor || + f == &this->justification || + f == &this->name || + f == &this->size || + f == &this->frame) { + drawImage(); + } + inherited::notify(list); +} void SoFrameLabel::drawImage() { @@ -475,24 +484,24 @@ void SoFrameLabel::drawImage() Gui::BitmapFactory().convert(image, sfimage); this->image = sfimage; } - -/** - * Renders the open edges only. - */ -void SoFrameLabel::GLRender(SoGLRenderAction *action) -{ - inherited::GLRender(action); -#if 0 - QGLWidget* window; - SoState * state = action->getState(); - state->push(); - SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR); - SoGLWidgetElement::get(state, window); - if (!window) { - state->pop(); - return; - } - + +/** + * Renders the open edges only. + */ +void SoFrameLabel::GLRender(SoGLRenderAction *action) +{ + inherited::GLRender(action); +#if 0 + QGLWidget* window; + SoState * state = action->getState(); + state->push(); + SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR); + SoGLWidgetElement::get(state, window); + if (!window) { + state->pop(); + return; + } + // Enter in 2D screen mode glMatrixMode(GL_PROJECTION); glPushMatrix(); @@ -549,12 +558,12 @@ void SoFrameLabel::GLRender(SoGLRenderAction *action) glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); - - state->pop(); -#endif -} - -// ------------------------------------------------------ + + state->pop(); +#endif +} + +// ------------------------------------------------------ SO_NODE_SOURCE(TranslateManip); From aa6c15d8d7bda5d4c6940ae50131d2d495a190ec Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 1 Jun 2013 18:15:46 +0200 Subject: [PATCH 067/160] Remove path --- src/Gui/DownloadItem.ui | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Gui/DownloadItem.ui b/src/Gui/DownloadItem.ui index b6dd8b34b..7a6cbf774 100644 --- a/src/Gui/DownloadItem.ui +++ b/src/Gui/DownloadItem.ui @@ -135,7 +135,6 @@ - From 5fe7f6bf7cbda7ab4dde292e2d363886c8169319 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 2 Jun 2013 15:12:41 +0200 Subject: [PATCH 068/160] Fix thumbnailer script --- package/debian/mime/freecad-thumbnailer | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/package/debian/mime/freecad-thumbnailer b/package/debian/mime/freecad-thumbnailer index a1081feb2..1a7debdb4 100755 --- a/package/debian/mime/freecad-thumbnailer +++ b/package/debian/mime/freecad-thumbnailer @@ -1,11 +1,16 @@ #!/usr/bin/python -import sys, zipfile, md5 +import sys, zipfile import getopt -import gnomevfs +from urlparse import urlparse +from urlparse import unquote opt,par = getopt.getopt(sys.argv[1:],'-s:') -inpfile = gnomevfs.get_local_path_from_uri(par[0]) +uri = urlparse(par[0]) +if uri.scheme != "file": + sys.exit(1) + +inpfile = unquote(uri.path) outfile = par[1] try: From 0bebfcc50f4329796759692db39132e073ecfd95 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 3 Jun 2013 01:11:26 +0200 Subject: [PATCH 069/160] Add FreeCAD icons with different sizes --- src/Gui/CMakeLists.txt | 7 ++++++- src/Gui/Icons/freecad-icon-16.png | Bin 0 -> 862 bytes src/Gui/Icons/freecad-icon-32.png | Bin 0 -> 1930 bytes src/Gui/Icons/freecad-icon-64.png | Bin 0 -> 4414 bytes 4 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 src/Gui/Icons/freecad-icon-16.png create mode 100644 src/Gui/Icons/freecad-icon-32.png create mode 100644 src/Gui/Icons/freecad-icon-64.png diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index ea63ba08c..0a3a86c7c 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -892,7 +892,12 @@ else(WIN32) INSTALL(TARGETS FreeCADGui LIBRARY DESTINATION lib ) - INSTALL(FILES Icons/freecad.xpm Icons/freecad-doc.png + INSTALL(FILES Icons/freecad.xpm + Icons/freecad-icon-16.png + Icons/freecad-icon-32.png + Icons/freecad-icon-64.png + Icons/freecad.svg + Icons/freecad-doc.png DESTINATION ${CMAKE_INSTALL_DATADIR} ) endif(WIN32) diff --git a/src/Gui/Icons/freecad-icon-16.png b/src/Gui/Icons/freecad-icon-16.png new file mode 100644 index 0000000000000000000000000000000000000000..188653a47d461529968f7f1a7f74b10239989a23 GIT binary patch literal 862 zcmV-k1EKthP)5r00004b3#c}2nYxW zd4mK(%;unJVie7l3UQV3|BD+x-C@RR96 zFEImA3%U$+3Wz|>=e0@i+?~V#1^@?e1Ok6|(6nbp@DUN&F(|Sn_MZ+A0Y}h)kZUN^ z6-2>PsQ6s;diz!m@A{>3Gdm9K0}v6Ts(u?_0k+UI!W&l_UwW7?F6#Z;Tr1l5fS3OI zawxUGfBR^3`c!R1Wc!E}TmLGNeIpXsGp3F4jE%Gb*bs3f`)SepD%ziV^X}27hjUlb zslg4&c(gl;_3#q|fvz!T$&4ogMRX< zgZ)N)vOoP;s#aTO)zIeHTyX&wf4ii$W5@pi7_cmO<(}X=B8G4C*Rtip^wRo`8zK{j z-}~Xl)cNNEfnd0^CwU~a@v#Rbv}Ub@pZtv0;!(Suh0s(uc(RrG+1``r7=Co;z`$@M zJ8@#+#?-kNRMXc1?8xZ5X7#P3+BMWe=fD`n(~lSg5Ky4*J10xlTD9W+k=yew)q2Y~ zouT-0WTsNx0<}Yl$_WkVG{7~w}?)x4}gcF-S2}U1( zUy)T-tnX#FZbLbfr+jsX>glQtx(onNP0xs=4p+*_=S`tZ$KdWQvU2wGTHT{sw^3gq zn(VT4rOOajB;IoE-n;(DU0y0qjZc^7o47R#{WFuJc=kN%`B=^_0DH2g zzrQ`>U-c|sTu*WUc(o7p=ES|Nru#9C(izk_OIP1Imhy+F9{T`y_cJsWj{}IR{@@~07*qoM6N<$g0hF5rT_o{ literal 0 HcmV?d00001 diff --git a/src/Gui/Icons/freecad-icon-32.png b/src/Gui/Icons/freecad-icon-32.png new file mode 100644 index 0000000000000000000000000000000000000000..7ddae937de343b603056ad6caf0a3e14c2f96c3f GIT binary patch literal 1930 zcmV;52X**~P)`|L5L2vpc)q_3p+>Vmpu8jha_ULP%oA zc{pi-6j4M0#iEZ7kW@u{C?AM~pjD|5AR$zcK!SW~#6zN`R7ijdX-nGFacw6}LmIh> z2$3B(5656yzb${?s{kapcD{CI-0AQx%d3e|D3rqLv0c0I8Z>vXwDG;hsJZw z(NF-^zG?ID;&&}>Dh3ozScpRahzcM|K!mDCv+M=|ib`M%AYi};y3Q0Qt`+|k;s*fC zjwAsRfT)biu0k#W5CP03S&0ABxC;P?aBzg2s^?TWQB8p0nlk-&05w@J6c|+nDn|HU z0#F%Z0T2}`g+!_TT$}xrPA7?W>;)(ZP@cK}^$!V94pspX<#AYn3Y?xV{jhHRqEWx> zaU;IOx5owr(e4$@J=uRBARJr*E)m|C3QC<{@yZjR0r(7fB`*Ys1V-ZirX3H|8TE}A zed`bT?6nJz05}>BM6^4x5Y+q<2tt+_-}{G`k4pTeG`n-i-RVGx2PY4UhhKUU3P*HU2` z=SYYofKx%S_x={s7w;)xi1FMwRpf*TQQsWf&!p?&{dG9o{fiPafivNaZr zzI70VJxu`aTL2(j|5}-d?ly(l(7k-?CzmyC-lKBYFMjIU>A!TS=sqW!Zm{m!|JkHf zXTftl2r01Uz~RK`z?)Cy$FI9}t$UKbO2f_<5!ByRhr(#QwgeOkUK!6Z<^fkm_T^)# zCDMvTk=nA8?riT&6{p8gzpNR|fbaW|Qh-26E^UI*{+XzqD@N^n5rupaQVC$iPBDIkOZ+!?@`$}#u-b%7>CX^Sm`WFi9HACE~`REG!w5rKQ2%jUK3{_)1!C%QHs z_<|XUnux|DFbsvUp({B5rx&v0gO`1w44qoNF_Br{VG2PILO=+DKXJte2gl~BD`pj_ zs6d#%%jwdd9~28e8F{DAmQp|}0mD!j?0?Pw^AEl`GIaLTS99Z|TW3awJFlO6{l^2( z|1j&!j8`+wv?`E1OtiC&sB3mlEteqF0~IA^8vsB6*c>5J=C_+Rcf^n-dqA#gSqCd-8B7Ko z#{~lzAG+)y@K4PRJ`3U6FFVttdxcs`K@e0gkOJb(0BfTbAY=m2xuEW<8A~~4YGurG z14!wC1OW^Lz6L3S0GVD4Kns;&DDpfXzE=idAIM&1+`cpeA;#3aS+(C7Gv4&g$k;nC z7n03uWA!W60AOgXp*)53>bn!!v7284&_8z>qAp1$Jq&9(JlBT~G;sS;5$~T50PzX} z?-}Oa-uVC_2k1-M29<}=p-90PESsKc84d;g7O z%l4QNPe2f1)jfxj@16YBvxar=5$!v#fMk-)c$Z4ICS~)kxMREJC#eXq)<9$;9Igt$ zb9_PTbC~zK`P;W)Y6T$(fQeSo_*xl-~D?LbQKc#FtnuTPWmg=b&PQ-1TV$ z!K2K*$BA}6jL8c}(YP-Gpww_)&St;+{u2D=Z(wHdFtS&VAn?A<+}|^s*sds^kn=u4 zfB+cjvH96~N*H^dhK2)e|A_glR|>GrfQ*fy_46qR6Ubf##?L&*?#YK1u4QOFUaa09 z(nxh4MZ@ODkXk2jt0#-;!9&dbFaG}kXvanf^)^VjU}T~7N0@sjKWN@R0TFcjrq2tb Qn*aa+07*qoM6N<$g8F%bA^-pY literal 0 HcmV?d00001 diff --git a/src/Gui/Icons/freecad-icon-64.png b/src/Gui/Icons/freecad-icon-64.png new file mode 100644 index 0000000000000000000000000000000000000000..227f83edfc35a51531116519d431962144f89169 GIT binary patch literal 4414 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

Date: Tue, 4 Jun 2013 21:16:28 +0200 Subject: [PATCH 070/160] Use TypeId in Draft --- src/Mod/Draft/Draft.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index cd9adf39a..18b79ef2b 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -167,13 +167,13 @@ def getType(obj): return "Sketch" if obj.isDerivedFrom("Part::Feature"): return "Part" - if (obj.Type == "App::Annotation"): + if (obj.TypeId == "App::Annotation"): return "Annotation" if obj.isDerivedFrom("Mesh::Feature"): return "Mesh" if obj.isDerivedFrom("Points::Feature"): return "Points" - if (obj.Type == "App::DocumentObjectGroup"): + if (obj.TypeId == "App::DocumentObjectGroup"): return "Group" return "Unknown" From 3664455182ad46ad323e70960e99d9189ce11148 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 5 Jun 2013 13:35:09 +0200 Subject: [PATCH 071/160] Fix deadlock issue --- src/Mod/Sandbox/App/DocumentProtectorPy.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mod/Sandbox/App/DocumentProtectorPy.cpp b/src/Mod/Sandbox/App/DocumentProtectorPy.cpp index 86f16ac06..7110935fb 100644 --- a/src/Mod/Sandbox/App/DocumentProtectorPy.cpp +++ b/src/Mod/Sandbox/App/DocumentProtectorPy.cpp @@ -118,6 +118,7 @@ int DocumentProtectorPy::setattr(const char * attr, const Py::Object & value) throw Py::RuntimeError(s_out.str()); } else { + Base::PyGILStateRelease unlock; return Py::PythonExtension::setattr(attr, value); } } @@ -227,6 +228,7 @@ int DocumentObjectProtectorPy::setattr(const char * attr, const Py::Object & val s_out << "No such attribute '" << attr << "'"; throw Py::AttributeError(s_out.str()); } + Base::PyGILStateRelease unlock; std::auto_ptr copy(static_cast (prop->getTypeId().createInstance())); copy->setPyObject(value.ptr()); From 75767272e949f99f56fc20491fdd73c65d148b23 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 5 Jun 2013 14:03:30 +0200 Subject: [PATCH 072/160] + Update debian files --- package/debian/changelog | 54 ++++++++++++ package/debian/control | 21 ++--- package/debian/dirs | 6 ++ package/debian/freecad.desktop | 2 +- package/debian/freecad.sharedmimeinfo | 2 +- package/debian/menu | 2 +- package/debian/mime/freecad.thumbnailer | 4 + package/debian/rules | 104 ++++++++---------------- package/debian/source/format | 2 +- package/debian/source/lintian-overrides | 6 +- 10 files changed, 115 insertions(+), 88 deletions(-) create mode 100644 package/debian/dirs create mode 100644 package/debian/mime/freecad.thumbnailer diff --git a/package/debian/changelog b/package/debian/changelog index 88e234be9..6ff7e60de 100644 --- a/package/debian/changelog +++ b/package/debian/changelog @@ -1,3 +1,18 @@ +freecad (0.13-1precise2) precise; urgency=low + + * Fix hard dependency on libgl1-mesa-glx preventing installation on + Ubuntu 12.04.2 with LTSEnablementStack. Removal of shlibs.local file + and libgl1-mesa-dev deleted from BuildDeps. + * Removed version number from libsoqt4-dev BD. + + -- Normand Chamberland Sun, 05 May 2013 18:31:47 -0400 + +freecad (0.13-1precise1) precise; urgency=low + + * New release for Ubuntu 12.04 (precise) + + -- Normand Chamberland Sun, 06 May 2012 14:38:12 -0400 + freecad (0.11.3729.dfsg-2) unstable; urgency=low * Add gfortran and libopencascade-visualization-dev to BD @@ -29,6 +44,25 @@ freecad (0.11.3729.dfsg-1) unstable; urgency=low -- "Adam C. Powell, IV" Tue, 12 Apr 2011 23:40:30 -0400 +freecad (0.10.3247.dfsg-2ubuntu3) natty; urgency=low + + * Fix build failure with ld --as-needed. + + -- Matthias Klose Wed, 15 Dec 2010 01:12:39 +0100 + +freecad (0.10.3247.dfsg-2ubuntu2) natty; urgency=low + + * Rebuild with python 2.7 as the python default. + + -- Matthias Klose Thu, 09 Dec 2010 16:46:45 +0000 + +freecad (0.10.3247.dfsg-2ubuntu1) natty; urgency=low + + * Merge from debian unstable. Remaining changes: + - build on libqtwebkit-dev for qtwebkit transition + + -- Bhavani Shankar Wed, 20 Oct 2010 08:40:53 +0530 + freecad (0.10.3247.dfsg-2) unstable; urgency=low * control: @@ -43,6 +77,20 @@ freecad (0.10.3247.dfsg-2) unstable; urgency=low -- Teemu Ikonen Wed, 18 Aug 2010 19:34:36 +0200 +freecad (0.10.3247.dfsg-1ubuntu2) maverick; urgency=low + + * Rebuild on libqtwebkit-dev for qtwebkit transition + + -- Jonathan Riddell Wed, 21 Jul 2010 10:06:31 +0100 + +freecad (0.10.3247.dfsg-1ubuntu1) maverick; urgency=low + + * Merge from Debian unstable, remaining changes: + - debian/control: Build-Depends on libqt4-webkit-dev due to + QtWebKit is no longer part of libqt4-dev (LP: #604078) + + -- Artur Rona Sat, 10 Jul 2010 21:06:47 +0200 + freecad (0.10.3247.dfsg-1) unstable; urgency=low * New upstream version (closes: #582627) @@ -57,6 +105,12 @@ freecad (0.10.3247.dfsg-1) unstable; urgency=low -- Teemu Ikonen Mon, 05 Jul 2010 15:07:49 +0200 +freecad (0.9.2646.5.dfsg-1ubuntu1) maverick; urgency=low + + * Add build-dep on libqt4-webkit-dev to fix FTBFS with Qt 4.7 + + -- Scott Kitterman Sat, 19 Jun 2010 00:37:12 -0400 + freecad (0.9.2646.5.dfsg-1) unstable; urgency=low * Add 'dfsg' extension to upstream version, upstream sources are unchanged. diff --git a/package/debian/control b/package/debian/control index 6e539444f..b2909693e 100644 --- a/package/debian/control +++ b/package/debian/control @@ -5,25 +5,26 @@ Maintainer: Debian Science Maintainers , "Adam C. Powell, IV" , Anton Gladky Vcs-Browser: http://git.debian.org/?p=debian-science/packages/freecad.git Vcs-Git: git://git.debian.org/git/debian-science/packages/freecad.git -Homepage: http://juergen-riegel.net/FreeCAD/Docu/index.php?title=Main_Page -Build-Depends: debhelper (>= 7.0.50~), autotools-dev, libtool, automake, - autoconf, libboost-dev, libboost-date-time-dev, libboost-filesystem-dev, +Homepage: https://sourceforge.net/apps/mediawiki/free-cad/index.php?title=Main_Page +Build-Depends: debhelper (>= 7.0.50~), cmake, + libboost-dev, libboost-date-time-dev, libboost-filesystem-dev, libboost-graph-dev, libboost-iostreams-dev, libboost-program-options-dev, libboost-regex-dev, libboost-serialization-dev, libboost-signals-dev, - libboost-python-dev, python-dev, python-support, + libboost-thread-dev, libboost-python-dev, python-dev, python-support, libqt4-dev, libxt-dev, libxext-dev, libxmu-dev, libxi-dev, libx11-dev, - libcoin60-dev, libsoqt4-dev (>= 1.4.2~svn20090224), libeigen3-dev, libgl1-mesa-dev, - zlib1g-dev, libxerces-c2-dev, libopencascade-foundation-dev, libopencascade-modeling-dev, + libcoin60-dev, libsoqt4-dev, libeigen3-dev, + zlib1g-dev, libxerces-c2-dev, libopencascade-foundation-dev, + libopencascade-modeling-dev, libopencascade-ocaf-dev, libopencascade-visualization-dev, python-cxx-dev, libswscale-dev, - libzipios++-dev, swig, gfortran, libqtwebkit-dev -Standards-Version: 3.9.2 + libzipios++-dev, swig, gfortran, f2c, libqtwebkit-dev, libspnav-dev, libfreetype6-dev +Standards-Version: 3.9.1 Package: freecad Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends} -Recommends: python-pivy python-matplotlib +Recommends: python-pivy, python Suggests: freecad-doc -Description: Extensible Open Source CAx program (alpha) +Description: Extensible Open Source CAx program (beta) FreeCAD is an Open Source CAx RAD based on OpenCasCade, Qt and Python. It features some key concepts like macro recording, workbenches, ability to run as a server and dynamically loadable application extensions and diff --git a/package/debian/dirs b/package/debian/dirs new file mode 100644 index 000000000..e71d501d4 --- /dev/null +++ b/package/debian/dirs @@ -0,0 +1,6 @@ +usr/share/icons/hicolor/16x16/apps +usr/share/icons/hicolor/32x32/apps +usr/share/icons/hicolor/64x64/apps +usr/share/icons/hicolor/scalable/apps +usr/share/pixmaps + diff --git a/package/debian/freecad.desktop b/package/debian/freecad.desktop index 7e0b9e53e..9ef688f95 100644 --- a/package/debian/freecad.desktop +++ b/package/debian/freecad.desktop @@ -10,7 +10,7 @@ Exec=/usr/bin/freecad %F Path=/usr/lib/freecad Terminal=false Type=Application -Icon=/usr/share/freecad/freecad.xpm +Icon=freecad Categories=Graphics;Science;Engineering StartupNotify=true GenericName[de_DE]=Feature-basierter parametrischer Modellierer diff --git a/package/debian/freecad.sharedmimeinfo b/package/debian/freecad.sharedmimeinfo index 91a2b10ed..6d5e93e7d 100644 --- a/package/debian/freecad.sharedmimeinfo +++ b/package/debian/freecad.sharedmimeinfo @@ -1,7 +1,7 @@ - + FreeCAD document files diff --git a/package/debian/menu b/package/debian/menu index c939246be..fcfa2169f 100644 --- a/package/debian/menu +++ b/package/debian/menu @@ -2,5 +2,5 @@ section="Applications/Science/Engineering"\ title="FreeCAD"\ command="/usr/bin/freecad"\ - icon="/usr/share/freecad/freecad.xpm" + icon="/usr/share/pixmaps/freecad.xpm" diff --git a/package/debian/mime/freecad.thumbnailer b/package/debian/mime/freecad.thumbnailer new file mode 100644 index 000000000..e54d9a7a1 --- /dev/null +++ b/package/debian/mime/freecad.thumbnailer @@ -0,0 +1,4 @@ +[Thumbnailer Entry] +TryExec=/usr/bin/freecad-thumbnailer +Exec=/usr/bin/freecad-thumbnailer -s %s %u %o +MimeType=application/x-extension-fcstd; diff --git a/package/debian/rules b/package/debian/rules index 72ac81266..566bad443 100755 --- a/package/debian/rules +++ b/package/debian/rules @@ -4,7 +4,7 @@ # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 -MODULES = Part Mesh MeshPart PartDesign Sketcher Points Raytracing Image Drawing ReverseEngineering Complete Fem Robot Import Inspection Arch +# For testing: fakeroot debian/rules binary # These are used for cross-compiling and for saving the configure script # from having to guess our platform (since we know it already) @@ -19,58 +19,32 @@ else CFLAGS += -O2 endif -patch-stamp: - touch $@ - -configure: autogen.sh patch-stamp +configure: dh_testdir - for autotools_mod_file in `find . -name Makefile.in` aclocal.m4 \ - configure m4/libtool.m4 m4/ltmain.sh m4/ltoptions.m4 \ - m4/ltversion.m4 m4/lt~obsolete.m4; do \ - cp -a $$autotools_mod_file $$autotools_mod_file.setaside; \ - done - chmod u+x autogen.sh - ./autogen.sh - -config.status: configure - dh_testdir - ./configure --with-occ-include=/usr/include/opencascade \ ---with-occ-lib=/usr/lib \ ---host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) \ ---prefix=/usr/lib/freecad --mandir=/usr/share/man \ ---infodir=/usr/share/info --datadir=/usr/share/freecad \ ---includedir=/usr/include/freecad --docdir=/usr/share/doc/freecad \ -CFLAGS="$(CFLAGS)" LDFLAGS="-Wl,-z,defs" - touch src/Build/Version.h + cmake . \ +-DFREECAD_BUILD_DEBIAN=ON \ +-DCMAKE_INSTALL_PREFIX=/usr/lib/freecad \ +-DCMAKE_INSTALL_MANDIR=/usr/share/man \ +-DCMAKE_INSTALL_INFODIR=/usr/share/info \ +-DCMAKE_INSTALL_DATADIR=/usr/share/freecad \ +-DCMAKE_INSTALL_INCLUDEDIR=/usr/include/freecad \ +-DCMAKE_INSTALL_DOCDIR=/usr/share/doc/freecad build: build-stamp -build-stamp: config.status +build-stamp: configure dh_testdir $(MAKE) touch $@ clean: - mv src/Build/Version.h src/Build/Version.h.old dh clean - mv src/Build/Version.h.old src/Build/Version.h rm -f build-stamp find -name '*.pyc' | xargs rm -f find -name 'moc_*.cpp' | xargs rm -f - find -name '*.lo' | xargs rm -f - find -name '*.deps' | xargs rm -rf - find -name '*.libs' | xargs rm -rf - rm -f stamp-h1 config.log libtool 71 - if [ -e Makefile.in.setaside ]; then \ - for autotools_mod_file in `find . -name Makefile.in` aclocal.m4 \ - configure m4/libtool.m4 m4/ltmain.sh m4/ltoptions.m4 \ - m4/ltversion.m4 m4/lt~obsolete.m4; do \ - mv -f $$autotools_mod_file.setaside $$autotools_mod_file; \ - done; fi - dh clean - rm -f patch-stamp - #quilt pop -a - #rm -rf .pc/ + find -name 'ui_*.h' | xargs rm -f + find -name 'CMakeFiles' | xargs rm -rf + rm -f stamp-h1 install: build install-stamp install-stamp: @@ -78,44 +52,32 @@ install-stamp: dh_testroot dh_prep dh_installdirs - $(MAKE) install DESTDIR=$(CURDIR)/debian/tmp/freecad - # Remove testing modules we don't want to have in the deb - rm -rf debian/tmp/freecad/usr/lib/freecad/Mod/_TEMPLATE_ - rm -rf debian/tmp/freecad/usr/lib/freecad/Mod/TemplatePyMod + $(MAKE) install/fast DESTDIR=$(CURDIR)/debian/tmp/freecad # install the core system dh_install -pfreecad debian/tmp/freecad/usr/share/freecad/* usr/share/freecad/ - #dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/share usr/lib/freecad + # Desktop icons + dh_install -pfreecad debian/tmp/freecad/usr/share/freecad/freecad.xpm usr/share/pixmaps + install -m 644 debian/tmp/freecad/usr/share/freecad/freecad-icon-16.png debian/freecad/usr/share/icons/hicolor/16x16/apps/freecad.png + install -m 644 debian/tmp/freecad/usr/share/freecad/freecad-icon-32.png debian/freecad/usr/share/icons/hicolor/32x32/apps/freecad.png + install -m 644 debian/tmp/freecad/usr/share/freecad/freecad-icon-64.png debian/freecad/usr/share/icons/hicolor/64x64/apps/freecad.png + install -m 644 debian/tmp/freecad/usr/share/freecad/freecad.svg debian/freecad/usr/share/icons/hicolor/scalable/apps/freecad.svg + dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/bin usr/lib/freecad - dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/lib/FreeCAD.so usr/lib/freecad/lib - dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/lib/lib*.so.* usr/lib/freecad/lib + dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/lib usr/lib/freecad + dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod usr/lib/freecad dh_install debian/freecad.desktop usr/share/applications - dh_installman debian/freecad.1 + dh_installman debian/freecad.1 debian/mime/freecad-thumbnailer.1 dh_installchangelogs ChangeLog.txt - # install the modules - $(foreach MODULE,$(MODULES), \ - dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/$(MODULE)/$(MODULE)*.so usr/lib/freecad/Mod/$(MODULE); \ - dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/$(MODULE)/lib*.so.* usr/lib/freecad/Mod/$(MODULE); \ - dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/$(MODULE)/*.py usr/lib/freecad/Mod/$(MODULE);) - # special treating of PartDesign module - dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/PartDesign/Scripts/*.py usr/lib/freecad/Mod/PartDesign/Scripts;) - # special treating of Draft module - dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/Draft/*.py usr/lib/freecad/Mod/Draft - dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/Draft/draftlibs/*.py usr/lib/freecad/Mod/Draft/draftlibs - # special treating of Test module - dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/Test/lib*.so.* usr/lib/freecad/Mod/Test - dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/Test/*.py usr/lib/freecad/Mod/Test - dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/Test/QtUnitGui.so usr/lib/freecad/Mod/Test - - dh_install -pfreecad-dev debian/tmp/freecad/usr/include/* usr/include - dh_install -pfreecad-dev debian/tmp/freecad/usr/lib/freecad/lib/lib*.so usr/lib/freecad/lib - $(foreach MODULE,$(MODULES), \ - dh_install -pfreecad-dev debian/tmp/freecad/usr/lib/freecad/Mod/$(MODULE)/lib*.la usr/lib/freecad/Mod/$(MODULE); \ - dh_install -pfreecad-dev debian/tmp/freecad/usr/lib/freecad/Mod/$(MODULE)/lib*.so usr/lib/freecad/Mod/$(MODULE);) - # special treating of Arch module - dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/Arch/*.py usr/lib/freecad/Mod/Arch - + # install the headers + #dh_install -pfreecad-dev debian/tmp/freecad/usr/include/* usr/include # install the help system dh_install -pfreecad-doc debian/tmp/freecad/usr/share/doc/* usr/share/doc/ + # install MIME stuff + dh_install debian/mime/freecad-thumbnailer usr/bin + dh_install debian/mime/freecad.thumbnailer usr/share/thumbnailers + dh_install debian/mime/freecad.schemas etc/gconf/schemas + dh_gconf -pfreecad + dh_installmime touch install-stamp override_dh_compress: diff --git a/package/debian/source/format b/package/debian/source/format index 163aaf8d8..d3827e75a 100644 --- a/package/debian/source/format +++ b/package/debian/source/format @@ -1 +1 @@ -3.0 (quilt) +1.0 diff --git a/package/debian/source/lintian-overrides b/package/debian/source/lintian-overrides index a7a5da0c9..0a52f43ba 100644 --- a/package/debian/source/lintian-overrides +++ b/package/debian/source/lintian-overrides @@ -1,3 +1,3 @@ -# Lintian thinks uploader Adam Powell's name violates policy -freecad source: uploader-address-missing "Adam C. Powell -freecad source: uploader-not-full-name IV" +# Lintian thinks uploader Adam Powell's name violates policy +freecad source: uploader-address-missing "Adam C. Powell +freecad source: uploader-not-full-name IV" From c2adf81ea6cafeb4fc44e3ac423a030728adfad1 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 5 Jun 2013 15:31:09 +0200 Subject: [PATCH 073/160] + Make FreeCAD default app to open FCStd files, allow to define different mimetype icons --- package/debian/mime/freecad-thumbnailer | 5 +++-- package/debian/rules | 4 +++- src/Gui/CMakeLists.txt | 1 + src/Gui/Icons/freecad-icon-48.png | Bin 0 -> 2900 bytes 4 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 src/Gui/Icons/freecad-icon-48.png diff --git a/package/debian/mime/freecad-thumbnailer b/package/debian/mime/freecad-thumbnailer index 1a7debdb4..e93508e23 100755 --- a/package/debian/mime/freecad-thumbnailer +++ b/package/debian/mime/freecad-thumbnailer @@ -24,8 +24,9 @@ try: if image in files: image=zfile.read(image) else: - freecad=open("/usr/share/freecad/freecad-doc.png") - image=freecad.read() + #freecad=open("/usr/share/freecad/freecad-doc.png") + #image=freecad.read() + sys.exit(1) thumb=open(outfile,"wb") thumb.write(image) diff --git a/package/debian/rules b/package/debian/rules index 566bad443..52bdb1356 100755 --- a/package/debian/rules +++ b/package/debian/rules @@ -59,9 +59,11 @@ install-stamp: dh_install -pfreecad debian/tmp/freecad/usr/share/freecad/freecad.xpm usr/share/pixmaps install -m 644 debian/tmp/freecad/usr/share/freecad/freecad-icon-16.png debian/freecad/usr/share/icons/hicolor/16x16/apps/freecad.png install -m 644 debian/tmp/freecad/usr/share/freecad/freecad-icon-32.png debian/freecad/usr/share/icons/hicolor/32x32/apps/freecad.png + install -m 644 debian/tmp/freecad/usr/share/freecad/freecad-icon-32.png debian/freecad/usr/share/icons/hicolor/48x48/apps/freecad.png install -m 644 debian/tmp/freecad/usr/share/freecad/freecad-icon-64.png debian/freecad/usr/share/icons/hicolor/64x64/apps/freecad.png install -m 644 debian/tmp/freecad/usr/share/freecad/freecad.svg debian/freecad/usr/share/icons/hicolor/scalable/apps/freecad.svg - + install -m 644 debian/tmp/freecad/usr/share/freecad/freecad-doc.png debian/freecad/usr/share/icons/hicolor/64x64/mimetypes/application-x-extension-fcstd.png + dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/bin usr/lib/freecad dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/lib usr/lib/freecad dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod usr/lib/freecad diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 0a3a86c7c..104e4486b 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -895,6 +895,7 @@ else(WIN32) INSTALL(FILES Icons/freecad.xpm Icons/freecad-icon-16.png Icons/freecad-icon-32.png + Icons/freecad-icon-48.png Icons/freecad-icon-64.png Icons/freecad.svg Icons/freecad-doc.png diff --git a/src/Gui/Icons/freecad-icon-48.png b/src/Gui/Icons/freecad-icon-48.png new file mode 100644 index 0000000000000000000000000000000000000000..66eb0320f49b755afe2019ee3dc51f7ba8307ed3 GIT binary patch literal 2900 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 Date: Wed, 5 Jun 2013 15:47:00 +0200 Subject: [PATCH 074/160] + Delete unused files --- package/debian/fcstd-thumbnailer.desktop | 9 --- package/debian/freecad.thumbnailer | 4 -- package/debian/occ-with-libs.patch | 78 ------------------------ package/debian/shlibs.local | 2 - 4 files changed, 93 deletions(-) delete mode 100644 package/debian/fcstd-thumbnailer.desktop delete mode 100644 package/debian/freecad.thumbnailer delete mode 100644 package/debian/occ-with-libs.patch delete mode 100644 package/debian/shlibs.local diff --git a/package/debian/fcstd-thumbnailer.desktop b/package/debian/fcstd-thumbnailer.desktop deleted file mode 100644 index 13f982f3f..000000000 --- a/package/debian/fcstd-thumbnailer.desktop +++ /dev/null @@ -1,9 +0,0 @@ - -[Desktop Entry] -Version=1.0 -Encoding=UTF-8 -Type=X-Thumbnailer -Name=FreeCAD Thumbnailer -MimeType=application/x-extension-fcstd; -X-Thumbnailer-Exec=/usr/bin/freecad-thumbnailer %u %o %s -GenericName=FreeCADThumbnailer diff --git a/package/debian/freecad.thumbnailer b/package/debian/freecad.thumbnailer deleted file mode 100644 index 3f78b3821..000000000 --- a/package/debian/freecad.thumbnailer +++ /dev/null @@ -1,4 +0,0 @@ -[Thumbnailer Entry] -TryExec=freecad-thumbnailer -Exec=freecad-thumbnailer -s %s %u %o -MimeType=application/x-extension-fcstd; diff --git a/package/debian/occ-with-libs.patch b/package/debian/occ-with-libs.patch deleted file mode 100644 index b32642cf7..000000000 --- a/package/debian/occ-with-libs.patch +++ /dev/null @@ -1,78 +0,0 @@ -Index: debian/rules -=================================================================== ---- debian/rules (revision 1523) -+++ debian/rules (working copy) -@@ -11,6 +11,10 @@ - - MODULES = Part Mesh Points Raytracing Image Drawing Test - -+# Preliminary only as long as no official debian package for -+# OpenCascade is available -+DESTOCCDIR=$(shell pwd)/debian/freecad/usr/lib/freecad/lib -+ - # These are used for cross-compiling and for saving the configure script - # from having to guess our platform (since we know it already) - DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) -@@ -85,6 +89,33 @@ - dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/lib/FreeCAD.so usr/lib/freecad/lib - dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/lib/lib*.so.* usr/lib/freecad/lib - -+# Preliminary only as long as no official debian package for -+# OpenCascade is available -+ install -m777 /usr/lib/libTKernel-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKMath-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKG2d-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKG3d-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKGeomBase-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKBRep-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKGeomAlgo-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKTopAlgo-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKPrim-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKBO-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKBool-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKShHealing-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKXSBase-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKSTEPBase-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKSTEPAttr-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKSTEP209-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKSTEP-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKFillet-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKOffset-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKIGES-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKMesh-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKHLR-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libTKSTL-6.2.so $(DESTOCCDIR) -+ install -m777 /usr/lib/libSoQt4.so.20 $(DESTOCCDIR) -+ - # install the modules - $(foreach MODULE,$(MODULES), \ - dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/$(MODULE)/$(MODULE)*.so usr/lib/freecad/Mod/$(MODULE); \ -Index: debian/shlibs.local -=================================================================== ---- debian/shlibs.local (revision 0) -+++ debian/shlibs.local (revision 0) -@@ -0,0 +1,24 @@ -+libTKernel 6.2 -+libTKMath 6.2 -+libTKG2d 6.2 -+libTKG3d 6.2 -+libTKGeomBase 6.2 -+libTKBRep 6.2 -+libTKGeomAlgo 6.2 -+libTKTopAlgo 6.2 -+libTKPrim 6.2 -+libTKBO 6.2 -+libTKBool 6.2 -+libTKShHealing 6.2 -+libTKXSBase 6.2 -+libTKSTEPAttr 6.2 -+libTKSTEPBase 6.2 -+libTKSTEP209 6.2 -+libTKSTEP 6.2 -+libTKFillet 6.2 -+libTKOffset 6.2 -+libTKIGES 6.2 -+libTKMesh 6.2 -+libTKHLR 6.2 -+libTKSTL 6.2 -+libSoQt4 20 diff --git a/package/debian/shlibs.local b/package/debian/shlibs.local deleted file mode 100644 index e7cacaa24..000000000 --- a/package/debian/shlibs.local +++ /dev/null @@ -1,2 +0,0 @@ -libGL 1 libgl1-mesa-glx (>= 7.7.1-1) -libSoQt4 20 libsoqt4-20 (>= 1.4.2~svn20090224) From 3adb55edbf56d57bff9e577b72e92e97f09173f5 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 5 Jun 2013 15:48:38 +0200 Subject: [PATCH 075/160] + Delete unused files --- package/debian/patch/debian_testing.patch | 33 ---------------------- package/debian/patch/ubuntu_intrepid.patch | 25 ---------------- package/debian/patch/ubuntu_jaunty.patch | 25 ---------------- 3 files changed, 83 deletions(-) delete mode 100644 package/debian/patch/debian_testing.patch delete mode 100644 package/debian/patch/ubuntu_intrepid.patch delete mode 100644 package/debian/patch/ubuntu_jaunty.patch diff --git a/package/debian/patch/debian_testing.patch b/package/debian/patch/debian_testing.patch deleted file mode 100644 index d49cc25ee..000000000 --- a/package/debian/patch/debian_testing.patch +++ /dev/null @@ -1,33 +0,0 @@ -Index: control -=================================================================== ---- control (revision 2213) -+++ control (working copy) -@@ -4,21 +4,21 @@ - Maintainer: Werner Mayer - Homepage: http://sourceforge.net/projects/free-cad - Build-Depends: debhelper (>= 5), autotools-dev, libc6-dev (>= 2.1.3), -- libstdc++6, libboost-dev, libboost-date-time-dev, libboost-filesystem-dev, -- libboost-graph-dev, libboost-iostreams-dev, libboost-program-options-dev, -- libboost-regex-dev, libboost-serialization-dev, libboost-signals-dev, -- zlib1g-dev, libxerces27-dev | libxerces-c2-dev, -+ libstdc++6, libboost1.37-dev, libboost-date-time1.37-dev, libboost-filesystem1.37-dev, -+ libboost-graph1.37-dev, libboost-iostreams1.37-dev, libboost-program-options1.37-dev, -+ libboost-regex1.37-dev, libboost-serialization1.37-dev, libboost-signals1.37-dev, -+ zlib1g-dev, libxerces-c28 | libxerces-c2-dev, - libxt-dev, libxmu-dev, libxi-dev, libx11-dev, libxext-dev, -- libqt4-dev, libsoqt4-dev, libcoin40-dev, libgl1-mesa-dev, -+ libqt4-dev, libsoqt4-dev, libcoin60-dev, libgl1-mesa-dev, - python2.5-dev, python, python-central (>= 0.5.6), -- libgts-dev, libcv-dev, libopencascade-dev -+ libgts-dev, libcv-dev, libopencascade-foundation-dev, libopencascade-modeling-dev - Standards-Version: 3.7.3 - XS-Python-Version: current - - Package: freecad - Architecture: any - Section: science --Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}, python -+Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}, python, python-pivy - XB-Python-Version: ${python:Versions} - Conflicts: freecad (<= 0.6.472-1) - Suggests: gnochm | kchmviewer | kchmviewer-nokde | xchm, python-opencv diff --git a/package/debian/patch/ubuntu_intrepid.patch b/package/debian/patch/ubuntu_intrepid.patch deleted file mode 100644 index 5cab88b9b..000000000 --- a/package/debian/patch/ubuntu_intrepid.patch +++ /dev/null @@ -1,25 +0,0 @@ -Index: debian/control -=================================================================== ---- debian/control (Revision 1881) -+++ debian/control (Arbeitskopie) -@@ -4,15 +4,15 @@ - Maintainer: Werner Mayer - Homepage: http://sourceforge.net/projects/free-cad - Build-Depends: debhelper (>= 5), autotools-dev, libc6-dev (>= 2.1.3), -- libstdc++6, libboost-dev, libboost-date-time-dev, libboost-filesystem-dev, -- libboost-graph-dev, libboost-iostreams-dev, libboost-program-options-dev, -- libboost-regex-dev, libboost-serialization-dev, libboost-signals-dev, -- zlib1g-dev, libxerces27-dev | libxerces-c2-dev, -+ libstdc++6, libboost1.35-dev, libboost-date-time1.35-dev, libboost-filesystem1.35-dev, -+ libboost-graph1.35-dev, libboost-iostreams1.35-dev, libboost-program-options1.35-dev, -+ libboost-regex1.35-dev, libboost-serialization1.35-dev, libboost-signals1.35-dev, -+ libboost-system1.35-dev, zlib1g-dev, libxerces27-dev | libxerces-c2-dev, - libxt-dev, libxmu-dev, libxi-dev, libx11-dev, libxext-dev, - libqt4-dev, libsoqt4-dev, libcoin40-dev, libgl1-mesa-dev, - python2.5-dev, python, python-central (>= 0.5.6), - libgts-dev, libcv-dev, libopencascade-dev --Standards-Version: 3.7.3 -+Standards-Version: 3.8.0 - XS-Python-Version: current - - Package: freecad diff --git a/package/debian/patch/ubuntu_jaunty.patch b/package/debian/patch/ubuntu_jaunty.patch deleted file mode 100644 index 397655d87..000000000 --- a/package/debian/patch/ubuntu_jaunty.patch +++ /dev/null @@ -1,25 +0,0 @@ -Index: debian/control -=================================================================== ---- debian/control (Revision 1879) -+++ debian/control (Arbeitskopie) -@@ -4,15 +4,15 @@ - Maintainer: Werner Mayer - Homepage: http://sourceforge.net/projects/free-cad - Build-Depends: debhelper (>= 5), autotools-dev, libc6-dev (>= 2.1.3), -- libstdc++6, libboost-dev, libboost-date-time-dev, libboost-filesystem-dev, -- libboost-graph-dev, libboost-iostreams-dev, libboost-program-options-dev, -- libboost-regex-dev, libboost-serialization-dev, libboost-signals-dev, -- zlib1g-dev, libxerces27-dev | libxerces-c2-dev, -+ libstdc++6, libboost1.35-dev, libboost-date-time1.35-dev, libboost-filesystem1.35-dev, -+ libboost-graph1.35-dev, libboost-iostreams1.35-dev, libboost-program-options1.35-dev, -+ libboost-regex1.35-dev, libboost-serialization1.35-dev, libboost-signals1.35-dev, -+ libboost-system1.35-dev, zlib1g-dev, libxerces27-dev | libxerces-c2-dev, - libxt-dev, libxmu-dev, libxi-dev, libx11-dev, libxext-dev, - libqt4-dev, libsoqt4-dev, libcoin40-dev, libgl1-mesa-dev, - python2.5-dev, python, python-central (>= 0.5.6), - libgts-dev, libcv-dev, libopencascade-dev --Standards-Version: 3.7.3 -+Standards-Version: 3.8.0 - XS-Python-Version: current - - Package: freecad From 9ab75d4aa535ad99e30536dbc3c11cf4f33206a1 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 5 Jun 2013 16:48:38 +0200 Subject: [PATCH 076/160] + Update packaging script --- package/makedebian.sh | 46 +++++++------------------------------------ 1 file changed, 7 insertions(+), 39 deletions(-) diff --git a/package/makedebian.sh b/package/makedebian.sh index 6b8f15811..bb4a5affb 100755 --- a/package/makedebian.sh +++ b/package/makedebian.sh @@ -16,65 +16,33 @@ # http://www.grymoire.com/Unix/Sed.html # global settings -REV_FILE=./revision.m4 TMP_PATH=/tmp MAJ=0 -MIN=12 -ALIAS="Vulcan" +MIN=13 # go to root directory CUR_DIR=$PWD verz=`dirname $(readlink -f ${0})` cd $verz && cd .. -# let's import OLD_REV (if there) -if [ -f ./.last_revision ]; then - . ./.last_revision -else - OLD_REV=0 -fi - -if svn --xml info >/dev/null 2>&1; then - REV=`svn --xml info | tr -d '\r\n' | sed -e 's/.*.*/\1/'` - LCD=`svn --xml info | tr -d '\r\n' | sed -e 's/.*\([0-9\-]*\)\T\([0-9\:]*\)\..*<\/date>.*<\/commit>.*/\1 \2/'` - URL=`svn --xml info | tr -d '\r\n' | sed -e 's/.*\(.*\)<\/url>.*/\1/'` -elif svn --version --quiet >/dev/null 2>&1; then - REV=`svn info | grep "^Revision:" | cut -d" " -f2` - LCD=`svn info | grep "^Last Changed Date:" | cut -d" " -f4,5` - URL=`svn info | grep "^URL:" | cut -d" " -f2` +# http://blog.marcingil.com/2011/11/creating-build-numbers-using-git-commits/ +if git log -1 >/dev/null 2>&1; then + REV=`git rev-list HEAD | wc -l | sed -e 's/ *//g' | xargs -n1 printf %04d` else REV=0 - LCD="" - URL="" fi -if [ "x$REV" != "x$OLD_REV" -o ! -r $REV_FILE ]; then - echo "m4_define([FREECAD_MAJOR], $MAJ)" > $REV_FILE - echo "m4_define([FREECAD_MINOR], $MIN)" >> $REV_FILE - echo "m4_define([FREECAD_MICRO], $REV)" >> $REV_FILE - - #echo "#define FCVersionMajor \"$MAJ\"" > src/Build/Version.h - #echo "#define FCVersionMinor \"$MIN\"" >> src/Build/Version.h - #echo "#define FCVersionName \"$ALIAS\"" >> src/Build/Version.h - #echo "#define FCRevision \"$REV\"" >> src/Build/Version.h - #echo "#define FCRepositoryURL \"$URL\"" >> src/Build/Version.h - #echo "#define FCCurrentDateT \"$LCD\"\n" >> src/Build/Version.h - touch src/Build/Version.h.in -fi - -echo "OLD_REV=$REV" > ./.last_revision - SRC_DIR=$PWD # Prepare source tarball and unpack it in build directory cd $CUR_DIR -make dist +make dist-git +cd $verz && cd .. rm -rf $TMP_PATH/freecad-$REV mkdir $TMP_PATH/freecad-$REV -mv FreeCAD-$MAJ.$MIN.$REV.tar.gz $TMP_PATH/freecad-$REV/freecad_$MAJ.$MIN.$REV.orig.tar.gz +mv freecad-$MAJ.$MIN.$REV.tar.gz $TMP_PATH/freecad-$REV/freecad_$MAJ.$MIN.$REV.orig.tar.gz cd $TMP_PATH/freecad-$REV tar -xzf freecad_$MAJ.$MIN.$REV.orig.tar.gz -mv FreeCAD-$MAJ.$MIN.$REV freecad-$MAJ.$MIN.$REV cd freecad-$MAJ.$MIN.$REV rm -rf src/CXX rm -rf src/zipios++ From 3e5ee466a868dfaaa1c7da575de343dd6b1e441f Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 5 Jun 2013 17:39:47 +0200 Subject: [PATCH 077/160] + Partial merge with Debian package --- package/debian/freecad-dev.install | 1 + package/debian/freecad-doc.docs | 1 + package/debian/freecad.manpages | 1 + package/debian/scripts/get_git_orig_src.sh | 47 ++++++++++++++++++++++ 4 files changed, 50 insertions(+) create mode 100644 package/debian/freecad-dev.install create mode 100644 package/debian/freecad-doc.docs create mode 100644 package/debian/freecad.manpages create mode 100644 package/debian/scripts/get_git_orig_src.sh diff --git a/package/debian/freecad-dev.install b/package/debian/freecad-dev.install new file mode 100644 index 000000000..ad10d78b2 --- /dev/null +++ b/package/debian/freecad-dev.install @@ -0,0 +1 @@ +usr/include/ usr/include/freecad diff --git a/package/debian/freecad-doc.docs b/package/debian/freecad-doc.docs new file mode 100644 index 000000000..27e5cb820 --- /dev/null +++ b/package/debian/freecad-doc.docs @@ -0,0 +1 @@ +debian/tmp/usr/doc/* diff --git a/package/debian/freecad.manpages b/package/debian/freecad.manpages new file mode 100644 index 000000000..4586a8594 --- /dev/null +++ b/package/debian/freecad.manpages @@ -0,0 +1 @@ +debian/freecad.1 diff --git a/package/debian/scripts/get_git_orig_src.sh b/package/debian/scripts/get_git_orig_src.sh new file mode 100644 index 000000000..f58e8d9d8 --- /dev/null +++ b/package/debian/scripts/get_git_orig_src.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# The script creates a tar.xz tarball from git-repository of freecad-project +# ./get_orig_src.sh commitID - creates a tarball of specified commit +# ./get_orig_src.sh - creates a tarball of the latest version +# Packages, that needs to be installed to use the script: +# atool, git-core + +set -e + +git clone git://free-cad.git.sourceforge.net/gitroot/free-cad/free-cad git_temp_packaging + +cd git_temp_packaging + +if [ $1 ] +then + echo 'Checking out the revision ' $1 + git checkout -b newvers $1 +else + echo 'Using the latest revision' +fi + +GIT_CMT_COUNT=$(git rev-list HEAD | wc -l) + +DEB_VER=0.13.$GIT_CMT_COUNT-dfsg +FOLDER_NAME=freecad-$DEB_VER +TARBALL_NAME=freecad_$DEB_VER.orig.tar.xz + +echo $DEB_VER +echo $FOLDER_NAME +echo $TARBALL_NAME + +python src/Tools/SubWCRev.py + +cd .. + +rm -fr $FOLDER_NAME + +mv git_temp_packaging $FOLDER_NAME +rm -rf $FOLDER_NAME/.git +rm -rf $FOLDER_NAME/src/3rdParty/CxImage +rm -rf $FOLDER_NAME/src/3rdParty/Pivy +rm -rf $FOLDER_NAME/src/3rdParty/Pivy-0.5 + +tar Jcvf $TARBALL_NAME $FOLDER_NAME + +rm -fr $FOLDER_NAME From 8fd1f35b4497b10b155303f9d5ae805330713eeb Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 5 Jun 2013 23:50:04 +0200 Subject: [PATCH 078/160] + Fix debian packaging --- package/debian/dirs | 2 ++ package/debian/freecad-dev.install | 1 - package/makedebian.sh | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) delete mode 100644 package/debian/freecad-dev.install diff --git a/package/debian/dirs b/package/debian/dirs index e71d501d4..4efc3d33b 100644 --- a/package/debian/dirs +++ b/package/debian/dirs @@ -1,6 +1,8 @@ usr/share/icons/hicolor/16x16/apps usr/share/icons/hicolor/32x32/apps +usr/share/icons/hicolor/48x48/apps usr/share/icons/hicolor/64x64/apps usr/share/icons/hicolor/scalable/apps +usr/share/icons/hicolor/64x64/mimetypes usr/share/pixmaps diff --git a/package/debian/freecad-dev.install b/package/debian/freecad-dev.install deleted file mode 100644 index ad10d78b2..000000000 --- a/package/debian/freecad-dev.install +++ /dev/null @@ -1 +0,0 @@ -usr/include/ usr/include/freecad diff --git a/package/makedebian.sh b/package/makedebian.sh index bb4a5affb..e1809b34d 100755 --- a/package/makedebian.sh +++ b/package/makedebian.sh @@ -44,8 +44,8 @@ mv freecad-$MAJ.$MIN.$REV.tar.gz $TMP_PATH/freecad-$REV/freecad_$MAJ.$MIN.$REV.o cd $TMP_PATH/freecad-$REV tar -xzf freecad_$MAJ.$MIN.$REV.orig.tar.gz cd freecad-$MAJ.$MIN.$REV -rm -rf src/CXX -rm -rf src/zipios++ +#rm -rf src/CXX +#rm -rf src/zipios++ # Prepare debian folder and set the revision number in debian/changelog # for package versioning From 6ee5dfe535f41fe30c0b556fb6e6e59dd85d5ecf Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 5 Jun 2013 23:58:40 +0200 Subject: [PATCH 079/160] + Support Ubuntu 12.04 --- package/debian/diff/freecad_precise.diff | 1018 ++++++++++++++++++++++ 1 file changed, 1018 insertions(+) create mode 100644 package/debian/diff/freecad_precise.diff diff --git a/package/debian/diff/freecad_precise.diff b/package/debian/diff/freecad_precise.diff new file mode 100644 index 000000000..a8fda14b0 --- /dev/null +++ b/package/debian/diff/freecad_precise.diff @@ -0,0 +1,1018 @@ +--- freecad-0.13.orig/debian/changelog ++++ freecad-0.13/debian/changelog +@@ -0,0 +1,281 @@ ++freecad (0.13-1precise2) precise; urgency=low ++ ++ * Fix hard dependency on libgl1-mesa-glx preventing installation on ++ Ubuntu 12.04.2 with LTSEnablementStack. Removal of shlibs.local file ++ and libgl1-mesa-dev deleted from BuildDeps. ++ * Removed version number from libsoqt4-dev BD. ++ ++ -- Normand Chamberland Sun, 05 May 2013 18:31:47 -0400 ++ ++freecad (0.13-1precise1) precise; urgency=low ++ ++ * New release for Ubuntu 12.04 (precise) ++ ++ -- Normand Chamberland Sun, 06 May 2012 14:38:12 -0400 ++ ++freecad (0.11.3729.dfsg-2) unstable; urgency=low ++ ++ * Add gfortran and libopencascade-visualization-dev to BD ++ to fix FTBFS (closes: #622694) ++ * Add libqtwebkit-dev to BD (closes: #618241) ++ * Delete quilt from BD and corresponding changes in rules. ++ * Add description to freecad-occ650.patch ++ * Delete encoding string from .desktop ++ * Fix some spelling errors, pointed out by lintian. ++ ++ -- Anton Gladky Thu, 14 Apr 2011 10:23:25 +0100 ++ ++freecad (0.11.3729.dfsg-1) unstable; urgency=low ++ ++ [ Denis Barbier ] ++ * Merge OpenCASCADE 6.5.0 compatibility patch (closes: #617545). ++ ++ [ Adam C. Powell, IV ] ++ * New upstream (closes: #622213, #618241). ++ * Changed to source format 3.0 (quilt). ++ * Added patch target which forces autotools to run, and automake and autoconf ++ are now in Build-Depends (closes: #607181). ++ * Set aside src/Build/Version.h to prevent build problems. ++ * Does not install .la files (closes: #621298). ++ * Boost 1.46 compatibility patch (closes: #621877). ++ * Set aside files which autotools modifies so clean works. ++ * Added libtool to Build-Depends (thanks: PICCA Frédéric-Emmanuel). ++ * Bumped Standards-Version, no changes needed. ++ ++ -- "Adam C. Powell, IV" Tue, 12 Apr 2011 23:40:30 -0400 ++ ++freecad (0.10.3247.dfsg-2ubuntu3) natty; urgency=low ++ ++ * Fix build failure with ld --as-needed. ++ ++ -- Matthias Klose Wed, 15 Dec 2010 01:12:39 +0100 ++ ++freecad (0.10.3247.dfsg-2ubuntu2) natty; urgency=low ++ ++ * Rebuild with python 2.7 as the python default. ++ ++ -- Matthias Klose Thu, 09 Dec 2010 16:46:45 +0000 ++ ++freecad (0.10.3247.dfsg-2ubuntu1) natty; urgency=low ++ ++ * Merge from debian unstable. Remaining changes: ++ - build on libqtwebkit-dev for qtwebkit transition ++ ++ -- Bhavani Shankar Wed, 20 Oct 2010 08:40:53 +0530 ++ ++freecad (0.10.3247.dfsg-2) unstable; urgency=low ++ ++ * control: ++ - Update to standars-version 3.9.0. ++ - Remove libblas-dev, libatlas-dev from build-deps. ++ * Add debian/shlibs.local file containing the the correct binary dep ++ to libsoqt4-20 (closes: #575239). ++ * copyright: Add a verbatim copy of Tiddlywiki BSD license. Fixes ++ the lintian warning copyright-refers-to-deprecated-bsd-license-file. ++ * Add kFreeBSD portability fixes. Thanks to Petr Salinger ++ for the patch (closes: #592461). ++ ++ -- Teemu Ikonen Wed, 18 Aug 2010 19:34:36 +0200 ++ ++freecad (0.10.3247.dfsg-1ubuntu2) maverick; urgency=low ++ ++ * Rebuild on libqtwebkit-dev for qtwebkit transition ++ ++ -- Jonathan Riddell Wed, 21 Jul 2010 10:06:31 +0100 ++ ++freecad (0.10.3247.dfsg-1ubuntu1) maverick; urgency=low ++ ++ * Merge from Debian unstable, remaining changes: ++ - debian/control: Build-Depends on libqt4-webkit-dev due to ++ QtWebKit is no longer part of libqt4-dev (LP: #604078) ++ ++ -- Artur Rona Sat, 10 Jul 2010 21:06:47 +0200 ++ ++freecad (0.10.3247.dfsg-1) unstable; urgency=low ++ ++ * New upstream version (closes: #582627) ++ * Add debian/source/format file with contents "1.0". ++ * Use freecad.xpm as icon in menu and desktop files. ++ * copyright: Add licensing information for new files in this release. ++ * src/Base/Makefile.in, src/Gui/Makefile.in: Do not remove *.tab.c files ++ in make distclean target. ++ * control: ++ - Add build-dep to libeigen2-dev. ++ - Update to standards-version 3.8.4. ++ ++ -- Teemu Ikonen Mon, 05 Jul 2010 15:07:49 +0200 ++ ++freecad (0.9.2646.5.dfsg-1ubuntu1) maverick; urgency=low ++ ++ * Add build-dep on libqt4-webkit-dev to fix FTBFS with Qt 4.7 ++ ++ -- Scott Kitterman Sat, 19 Jun 2010 00:37:12 -0400 ++ ++freecad (0.9.2646.5.dfsg-1) unstable; urgency=low ++ ++ * Add 'dfsg' extension to upstream version, upstream sources are unchanged. ++ * Remove libgl1-mesa-dev build-dep, rely on libcoin to pull in GL libraries. ++ * Change build-dep libatlas-headers to libatlas-dev (closes: #577309). ++ ++ -- Teemu Ikonen Fri, 14 May 2010 17:20:35 +0200 ++ ++freecad (0.9.2646.5-1) unstable; urgency=low ++ ++ * New upstream version (closes: #561696). ++ * Added swig to Build-Depends (closes: #563523, #563772). ++ * Removed python-opencv from Build-Depends and Recommends (closes: #560768). ++ ++ -- Adam C. Powell, IV Mon, 11 Jan 2010 08:48:33 -0500 ++ ++freecad (0.9.2646.4-1) unstable; urgency=low ++ ++ * New upstream version (closes: #559849, #559846). ++ ++ -- Adam C. Powell, IV Fri, 11 Dec 2009 20:21:32 -0500 ++ ++freecad (0.9.2646.3-1) unstable; urgency=low ++ ++ * New upstream version. Removes TiddlySaver.jar, fixes help problems. ++ ++ -- Teemu Ikonen Thu, 03 Dec 2009 19:39:27 +0100 ++ ++freecad (0.9.2646-1) unstable; urgency=low ++ ++ [ Werner Mayer ] ++ * New upstream release ++ * In-source copy of PyCXX has been dropped (closes: #547936) ++ * In-source copy of zipios++ has been dropped (closes: #547941) ++ * Change build-dependency on python2.5-dev to python-dev ++ * Add freecad-doc binary package ++ * Remove Suggestion of a chm viewer, suggest freecad-doc instead ++ ++ [ Teemu Ikonen ] ++ * Add override to dh_compress ++ * Add versioned build-deb to debhelper (>= 7.0.50) ++ * Add build-deps to libzipios++-dev and python-cxx-dev. ++ ++ -- Teemu Ikonen Tue, 17 Nov 2009 14:22:00 +0100 ++ ++freecad (0.8.2237-2) unstable; urgency=low ++ ++ * Added libboost-python-dev to Build-Depends (closes: #549738). ++ * Added myself to uploaders list. ++ * Bumped Standards-Version. ++ ++ -- Adam C. Powell, IV Thu, 12 Nov 2009 12:02:42 -0500 ++ ++freecad (0.8.2237-1) unstable; urgency=low ++ ++ * New Upstream release ++ ++ -- Teemu Ikonen Thu, 16 Jul 2009 18:37:41 +0200 ++ ++freecad (0.7.1658-1) UNRELEASED; urgency=low ++ ++ * New upstream release ++ ++ -- Teemu Ikonen Mon, 20 Oct 2008 15:35:58 +0200 ++ ++freecad (0.7.1514-1) UNRELEASED; urgency=low ++ ++ * New upstream version ++ * Add more stuff to the copyright file ++ * control: add build-dep to python-central ++ ++ -- Teemu Ikonen Wed, 06 Aug 2008 18:25:02 +0200 ++ ++freecad (0.7.1350-1hardy1) UNRELEASED; urgency=low ++ ++ * Package for Ubuntu 8.04 (Hardy Heron) ++ ++ -- Werner Mayer Thu, 29 May 2008 11:11:20 +0200 ++ ++freecad (0.7.1350-1gutsy1) UNRELEASED; urgency=low ++ ++ * Backport to Ubuntu 7.10 (Gutsy Gibbon) ++ ++ -- Werner Mayer Sat, 24 May 2008 01:54:39 +0200 ++ ++freecad (0.7.1350-1feisty1) UNRELEASED; urgency=low ++ ++ * Backport to Ubuntu 7.04 (Feisty Fawn) ++ ++ -- Werner Mayer Sat, 24 May 2008 00:09:08 +0200 ++ ++freecad (0.7.1350-1) UNRELEASED; urgency=low ++ ++ * New upstream release from sf.net ++ * Import to debian-science repository at git.debian.org ++ * control: ++ - Update to standards-version 3.7.3 ++ - Add Vcs-* fields pointing to git.debian.org ++ - Improve descriptions ++ * Convert copyright to (pseudo) machine readable format, audit source ++ * Fix categories in .desktop file ++ * Change Section to Science/Engineering in .doc-base and menu files ++ * rules: do not ignore errors on clean target, add dh_desktop call ++ -- Teemu Ikonen Tue, 05 Aug 2008 18:58:07 +0200 ++ ++freecad (0.7.1344-1ubuntu2) UNRELEASED; urgency=low ++ ++ * New package with fixed self-dependency problem ++ ++ -- Werner Mayer Thu, 22 May 2008 15:34:34 +0200 ++ ++freecad (0.7.1344-1ubuntu1) UNRELEASED; urgency=low ++ ++ * New debian package for Feisty ++ ++ -- Werner Mayer Thu, 22 May 2008 11:04:06 +0200 ++ ++freecad (0.7.1344-1) UNRELEASED; urgency=low ++ ++ * Write patch file to make builds with OpenCASCADE libs inside but with no ++ dependency to libopencascade6.2 ++ ++ -- Werner Mayer Wed, 21 May 2008 10:06:07 +0200 ++ ++freecad (0.7.1343-1) UNRELEASED; urgency=low ++ ++ * Embed required OpenCASCADE libs into this package as long as no official ++ Debian package is available ++ ++ -- Werner Mayer Tue, 20 May 2008 00:40:39 +0200 ++ ++freecad (0.7.1342-1) UNRELEASED; urgency=low ++ ++ * Switch to new versioning scheme of OpenCASCADE packages ++ ++ -- Werner Mayer Mon, 19 May 2008 23:55:31 +0200 ++ ++freecad (0.7.1316-1) UNRELEASED; urgency=low ++ ++ * Support of pivy (Python binding for Coin/SoQt) ++ * Support of PyQt4 ++ * General support of SWIG modules ++ ++ -- Werner Mayer Sat, 26 Apr 2008 13:51:25 +0200 ++ ++freecad (0.7.1031-1) UNRELEASED; urgency=low ++ ++ * Qt4 port finished ++ * Support of Python binding for Qt4 ++ * Support of Python binding for Coin ++ * Support of entirely in Python written modules ++ * Added support of model driven architecture for Python binding ++ * Use boost's signal/slot mechanism to update data ++ ++ -- Werner Mayer Tue, 04 Jan 2008 13:50:37 +0200 ++ ++freecad (0.7.645-1) UNRELEASED; urgency=low ++ ++ * Qt4 port started ++ ++ -- Werner Mayer Tue, 24 Jul 2007 13:04:37 +0200 ++ ++freecad (0.6.472-1) UNRELEASED; urgency=low ++ ++ * Initial Release ++ ++ -- Werner Mayer Tue, 26 Sep 2006 16:55:15 +0200 ++ +--- freecad-0.13.orig/debian/freecad.1 ++++ freecad-0.13/debian/freecad.1 +@@ -0,0 +1,73 @@ ++.\" Hey, EMACS: -*- nroff -*- ++.\" First parameter, NAME, should be all caps ++.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection ++.\" other parameters are allowed: see man(7), man(1) ++.TH FREECAD 1 "July 25, 2007" freecad "Linux User's Manual" ++.\" Please adjust this date whenever revising the manpage. ++.\" ++.\" Some roff macros, for reference: ++.\" .nh disable hyphenation ++.\" .hy enable hyphenation ++.\" .ad l left justify ++.\" .ad b justify to both left and right margins ++.\" .nf disable filling ++.\" .fi enable filling ++.\" .br insert line break ++.\" .sp insert n+1 empty lines ++.\" for manpage-specific macros, see man(7) ++.SH NAME ++freecad \- An extensible Open Source CAx program for Unix/X11 ++.SH SYNOPSIS ++.B freecad ++.RI [ options ] " files" ++.br ++.B freecadcmd ++.RI [ options ] " files" ++.SH DESCRIPTION ++.B FreeCAD ++is an Open Source CAx RAD based on OpenCasCade, Qt and Python. It features ++some key concepts like macro recording, workbenches, ability to run as a ++server and dynamically loadable application extensions and it is designed ++to be platform independent. ++.\" TeX users may be more comfortable with the \fB\fP and ++.\" \fI\fP escape sequences to invode bold face and italics, ++.\" respectively. ++.SH USAGE ++\fBfreecad\fR starts with a GUI while \fBfreecadcmd\fR is only a pure command line version that starts a Python interpreter. ++.SH OPTIONS ++These programs follow the usual GNU command line syntax, with long ++options starting with two dashes (`-'). ++A summary of the options supported by \fBfreecad\fR is included below. ++.SS "Generic options" ++.TP ++\fB\-h, \-\-help\fR ++Show summary of options. ++.TP ++\fB\-v, \-\-version\fR ++Show version of program. ++.TP ++\fB\-c, \-\-console\fR ++Start in console mode. ++.TP ++\fB\-\-response\-file\fR \fIarg\fR ++Can be specified with '@name', too. ++ ++.SS "Configuration" ++.TP ++\fB\-l, \-\-write\-log\fR ++Write a log file. ++.TP ++\fB\-t, \-\-run\-test\fR \fIarg\fR ++Test level. ++.TP ++\fB\-M, \-\-module\-path\fR \fIarg\fR ++Additional module path. ++.TP ++\fB\-P, \-\-python\-path\fR \fIarg\fR ++Additional Python path. ++.SH SEE ALSO ++To get more information about \fBFreeCAD\fR, please visit \fIhttp://juergen\-riegel.net/FreeCAD/Docu/index.php/Main_Page\fR ++.SH BUGS ++To report a bug, please visit \fIhttp://free-cad.sf.net/\fR ++.SH AUTHOR ++This manual page was written by Werner Mayer. +--- freecad-0.13.orig/debian/rules ++++ freecad-0.13/debian/rules +@@ -0,0 +1,98 @@ ++#!/usr/bin/make -f ++# -*- makefile -*- ++ ++# Uncomment this to turn on verbose mode. ++#export DH_VERBOSE=1 ++ ++# For testing: fakeroot debian/rules binary ++ ++# These are used for cross-compiling and for saving the configure script ++# from having to guess our platform (since we know it already) ++DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) ++DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) ++ ++CFLAGS = -Wall -g ++ ++ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) ++ CFLAGS += -O0 ++else ++ CFLAGS += -O2 ++endif ++ ++configure: ++ dh_testdir ++ cmake . \ ++-DFREECAD_BUILD_DEBIAN=ON \ ++-DCMAKE_INSTALL_PREFIX=/usr/lib/freecad \ ++-DCMAKE_INSTALL_MANDIR=/usr/share/man \ ++-DCMAKE_INSTALL_INFODIR=/usr/share/info \ ++-DCMAKE_INSTALL_DATADIR=/usr/share/freecad \ ++-DCMAKE_INSTALL_INCLUDEDIR=/usr/include/freecad \ ++-DCMAKE_INSTALL_DOCDIR=/usr/share/doc/freecad ++ ++build: build-stamp ++ ++build-stamp: configure ++ dh_testdir ++ $(MAKE) ++ touch $@ ++ ++clean: ++ dh clean ++ rm -f build-stamp ++ find -name '*.pyc' | xargs rm -f ++ find -name 'moc_*.cpp' | xargs rm -f ++ find -name 'ui_*.h' | xargs rm -f ++ find -name 'CMakeFiles' | xargs rm -rf ++ rm -f stamp-h1 ++ ++install: build install-stamp ++install-stamp: ++ dh_testdir ++ dh_testroot ++ dh_prep ++ dh_installdirs ++ $(MAKE) install/fast DESTDIR=$(CURDIR)/debian/tmp/freecad ++ # install the core system ++ dh_install -pfreecad debian/tmp/freecad/usr/share/freecad/* usr/share/freecad/ ++ # Desktop icons ++ dh_install -pfreecad debian/tmp/freecad/usr/share/freecad/freecad.xpm usr/share/pixmaps ++ install -m 644 debian/tmp/freecad/usr/share/freecad/freecad-icon-16.png debian/freecad/usr/share/icons/hicolor/16x16/apps/freecad.png ++ install -m 644 debian/tmp/freecad/usr/share/freecad/freecad-icon-32.png debian/freecad/usr/share/icons/hicolor/32x32/apps/freecad.png ++ install -m 644 debian/tmp/freecad/usr/share/freecad/freecad-icon-32.png debian/freecad/usr/share/icons/hicolor/48x48/apps/freecad.png ++ install -m 644 debian/tmp/freecad/usr/share/freecad/freecad-icon-64.png debian/freecad/usr/share/icons/hicolor/64x64/apps/freecad.png ++ install -m 644 debian/tmp/freecad/usr/share/freecad/freecad.svg debian/freecad/usr/share/icons/hicolor/scalable/apps/freecad.svg ++ install -m 644 debian/tmp/freecad/usr/share/freecad/freecad-doc.png debian/freecad/usr/share/icons/hicolor/64x64/mimetypes/application-x-extension-fcstd.png ++ ++ dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/bin usr/lib/freecad ++ dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/lib usr/lib/freecad ++ dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod usr/lib/freecad ++ dh_install debian/freecad.desktop usr/share/applications ++ dh_installman debian/freecad.1 debian/mime/freecad-thumbnailer.1 ++ dh_installchangelogs ChangeLog.txt ++ # install the headers ++ #dh_install -pfreecad-dev debian/tmp/freecad/usr/include/* usr/include ++ # install the help system ++ dh_install -pfreecad-doc debian/tmp/freecad/usr/share/doc/* usr/share/doc/ ++ # install MIME stuff ++ dh_install debian/mime/freecad-thumbnailer usr/bin ++ dh_install debian/mime/freecad.thumbnailer usr/share/thumbnailers ++ dh_install debian/mime/freecad.schemas etc/gconf/schemas ++ dh_gconf -pfreecad ++ dh_installmime ++ touch install-stamp ++ ++override_dh_compress: ++ dh_compress -X.qch -X.qhc ++ ++override_dh_makeshlibs: ++ ++ ++binary-indep: build install ++ dh binary-indep ++ ++binary-arch: build install ++ dh binary-arch ++ ++binary: binary-indep binary-arch ++.PHONY: build clean binary-indep binary-arch binary install +--- freecad-0.13.orig/debian/menu ++++ freecad-0.13/debian/menu +@@ -0,0 +1,6 @@ ++?package(freecad):needs="X11"\ ++ section="Applications/Science/Engineering"\ ++ title="FreeCAD"\ ++ command="/usr/bin/freecad"\ ++ icon="/usr/share/pixmaps/freecad.xpm" ++ +--- freecad-0.13.orig/debian/freecad.manpages ++++ freecad-0.13/debian/freecad.manpages +@@ -0,0 +1 @@ ++debian/freecad.1 +--- freecad-0.13.orig/debian/control ++++ freecad-0.13/debian/control +@@ -0,0 +1,67 @@ ++Source: freecad ++Section: science ++Priority: extra ++Maintainer: Debian Science Maintainers ++Uploaders: Teemu Ikonen , "Adam C. Powell, IV" , Anton Gladky ++Vcs-Browser: http://git.debian.org/?p=debian-science/packages/freecad.git ++Vcs-Git: git://git.debian.org/git/debian-science/packages/freecad.git ++Homepage: https://sourceforge.net/apps/mediawiki/free-cad/index.php?title=Main_Page ++Build-Depends: debhelper (>= 7.0.50~), cmake, ++ libboost-dev, libboost-date-time-dev, libboost-filesystem-dev, ++ libboost-graph-dev, libboost-iostreams-dev, libboost-program-options-dev, ++ libboost-regex-dev, libboost-serialization-dev, libboost-signals-dev, ++ libboost-thread-dev, libboost-python-dev, python-dev, python-support, ++ libqt4-dev, libxt-dev, libxext-dev, libxmu-dev, libxi-dev, libx11-dev, ++ libcoin60-dev, libsoqt4-dev, libeigen3-dev, ++ zlib1g-dev, libxerces-c2-dev, libopencascade-foundation-dev, ++ libopencascade-modeling-dev, libopencascade-ocaf-dev, ++ libopencascade-visualization-dev, python-cxx-dev, libswscale-dev, ++ libzipios++-dev, swig, gfortran, f2c, libqtwebkit-dev, libspnav-dev, libfreetype6-dev ++Standards-Version: 3.9.1 ++ ++Package: freecad ++Architecture: any ++Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends} ++Recommends: python-pivy, python ++Suggests: freecad-doc ++Description: Extensible Open Source CAx program (beta) ++ FreeCAD is an Open Source CAx RAD based on OpenCasCade, Qt and Python. ++ It features some key concepts like macro recording, workbenches, ability ++ to run as a server and dynamically loadable application extensions and ++ it is designed to be platform independent. ++ . ++ Currently, FreeCAD can import and display CAD models in IGES, STEP, and ++ BRep formats and meshes in STL, BMS, AST and Wavefront OBJ formats. ++ Editing and modeling features are currently somewhat limited. ++ ++Package: freecad-dev ++Architecture: any ++Section: libdevel ++Depends: ${shlibs:Depends}, ${misc:Depends}, freecad (= ${binary:Version}) ++Description: FreeCAD development files ++ FreeCAD is an Open Source CAx RAD based on OpenCasCade, Qt and Python. ++ It features some key concepts like macro recording, workbenches, ability ++ to run as a server and dynamically loadable application extensions and ++ it is designed to be platform independent. ++ For more details see http://sourceforge.net/projects/free-cad ++ . ++ This package contains headers and symlinks necessary to ++ develop modules for FreeCAD. ++ ++Package: freecad-doc ++Architecture: all ++Section: doc ++Depends: ${misc:Depends}, qt4-dev-tools ++Description: FreeCAD documentation ++ FreeCAD is an Open Source CAx RAD based on OpenCasCade, Qt and Python. ++ It features some key concepts like macro recording, workbenches, ability ++ to run as a server and dynamically loadable application extensions and ++ it is designed to be platform independent. ++ For more details see http://sourceforge.net/projects/free-cad ++ . ++ This package contains the FreeCAD documentation. ++ . ++ The documentation is provided in Qt's new help format; ++ the new help format version can be viewed in conjunction with the Qt Assistant ++ found in the qt4-dev-tools package. ++ +--- freecad-0.13.orig/debian/freecad.sharedmimeinfo ++++ freecad-0.13/debian/freecad.sharedmimeinfo +@@ -0,0 +1,8 @@ ++ ++ ++ ++ ++ FreeCAD document files ++ ++ ++ +--- freecad-0.13.orig/debian/compat ++++ freecad-0.13/debian/compat +@@ -0,0 +1 @@ ++7 +--- freecad-0.13.orig/debian/freecad.links ++++ freecad-0.13/debian/freecad.links +@@ -0,0 +1,3 @@ ++usr/lib/freecad/bin/FreeCAD usr/bin/freecad ++usr/lib/freecad/bin/FreeCADCmd usr/bin/freecadcmd ++usr/share/man/man1/freecad.1.gz usr/share/man/man1/freecadcmd.1.gz +--- freecad-0.13.orig/debian/freecad-doc.docs ++++ freecad-0.13/debian/freecad-doc.docs +@@ -0,0 +1 @@ ++debian/tmp/usr/doc/* +--- freecad-0.13.orig/debian/dirs ++++ freecad-0.13/debian/dirs +@@ -0,0 +1,8 @@ ++usr/share/icons/hicolor/16x16/apps ++usr/share/icons/hicolor/32x32/apps ++usr/share/icons/hicolor/48x48/apps ++usr/share/icons/hicolor/64x64/apps ++usr/share/icons/hicolor/scalable/apps ++usr/share/icons/hicolor/64x64/mimetypes ++usr/share/pixmaps ++ +--- freecad-0.13.orig/debian/freecad.desktop ++++ freecad-0.13/debian/freecad.desktop +@@ -0,0 +1,18 @@ ++[Desktop Entry] ++Version=1.0 ++Name=FreeCAD ++Name[de]=FreeCAD ++Comment=Feature based Parametric Modeler ++Comment[de]=Feature-basierter parametrischer Modellierer ++GenericName=CAD Application ++GenericName[de]=CAD-Anwendung ++Exec=/usr/bin/freecad %F ++Path=/usr/lib/freecad ++Terminal=false ++Type=Application ++Icon=freecad ++Categories=Graphics;Science;Engineering ++StartupNotify=true ++GenericName[de_DE]=Feature-basierter parametrischer Modellierer ++Comment[de_DE]=Feature-basierter parametrischer Modellierer ++MimeType=application/x-extension-fcstd +--- freecad-0.13.orig/debian/watch ++++ freecad-0.13/debian/watch +@@ -0,0 +1,2 @@ ++version=3 ++http://sf.net/free-cad/freecad_(.+)\.orig\.tar\.gz +--- freecad-0.13.orig/debian/freecad-doc.doc-base ++++ freecad-0.13/debian/freecad-doc.doc-base +@@ -0,0 +1,18 @@ ++Document: freecad-development-documentation ++Title: FreeCAD development documentation ++Author: FreeCAD developers ++Abstract: FreeCAD is a general purpose Open Source 3D ++ CAD/MCAD/CAx/CAE/PLM modeler, aimed directly at mechanical engineering ++ and product design but also fits in a wider range of uses around ++ engineering, such as architecture or other engineering specialties. ++ It is a feature-based parametric modeler with a modular software ++ architecture which makes it easy to provide additional functionality ++ without modifying the core system. ++Section: Science/Engineering ++ ++Format: HTML ++Index: /usr/share/doc/freecad/Start_Page.html ++Files: /usr/share/doc/freecad/*.q* ++ ++Format: PDF ++Files: /usr/share/doc/freecad/kr_16.pdf.gz /usr/share/doc/freecad/kr_210_2.pdf.gz /usr/share/doc/freecad/kr_500_2.pdf.gz +--- freecad-0.13.orig/debian/copyright ++++ freecad-0.13/debian/copyright +@@ -0,0 +1,275 @@ ++Format-Specification: http://dep.debian.net/deps/dep5/ ++Maintainer: Werner Mayer ++X-Packaged-By: Werner Mayer ++X-Packaged-Date: 2006-09-26_16:55:15+02:00 ++Source: http://sourceforge.net/projects/free-cad ++ ++Files: * ++Copyright: 2001-2009 Jürgen Riegel , ++ Werner Mayer ++License: LGPL-2+ ++ This package is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2 of the License, or (at your option) any later version. ++ . ++ This package 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 ++ Lesser General Public License for more details. ++ . ++ You should have received a copy of the GNU Lesser General Public ++ License along with this package; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, US ++ . ++ On Debian systems, the complete text of the GNU Lesser General Public ++ License version 2 can be found in `/usr/share/common-licenses/LGPL-2'. ++ ++Files: src/3rdParty/boost/numeric/bindings/* ++Copyright: 2002-2008 Kresimir Fresl, Karl Meerbergen, Toon Knapen, ++ Andreas Kloeckner, Jeremy Conlin, Thomas Klimpel, Fabien Dekeyser, ++ Quoc-Cuong Pham, Si-Lab b.v.b.a., Joerg Walter ++License: other-boost-1.0 ++ Boost Software License - Version 1.0 - August 17th, 2003 ++ . ++ Permission is hereby granted, free of charge, to any person or organization ++ obtaining a copy of the software and accompanying documentation covered by ++ this license (the "Software") to use, reproduce, display, distribute, ++ execute, and transmit the Software, and to prepare derivative works of the ++ Software, and to permit third-parties to whom the Software is furnished to ++ do so, all subject to the following: ++ . ++ The copyright notices in the Software and this entire statement, including ++ the above license grant, this restriction and the following disclaimer, ++ must be included in all copies of the Software, in whole or in part, and ++ all derivative works of the Software, unless such copies or derivative ++ works are solely in the form of machine-executable object code generated by ++ a source language processor. ++ . ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT ++ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE ++ FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ++ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ DEALINGS IN THE SOFTWARE. ++ ++Files: src/3rdParty/boost/numeric/bindings/lapack/lapack.hpp, ++ src/3rdParty/boost/numeric/bindings/traits/std_valarray.hpp ++Copyright: 2003 Toon Knapen, Kresimir Fresl, Karl Meerbergen ++License: other ++ * Permission to copy, modify, use and distribute this software ++ * for any non-commercial or commercial purpose is granted provided ++ * that this license appear on all copies of the software source code. ++ * ++ * Authors assume no responsibility whatsoever for its use and makes ++ * no guarantees about its quality, correctness or reliability. ++ * ++ * KF acknowledges the support of the Faculty of Civil Engineering, ++ * University of Zagreb, Croatia. ++ ++Files: src/Base/Base64.* ++Copyright: 2004-2008 Rene Nyffenegger ++License: other ++ This source code is provided 'as-is', without any express or implied ++ warranty. In no event will the author be held liable for any damages ++ arising from the use of this software. ++ . ++ Permission is granted to anyone to use this software for any purpose, ++ including commercial applications, and to alter it and redistribute it ++ freely, subject to the following restrictions: ++ . ++ 1. The origin of this source code must not be misrepresented; you must not ++ claim that you wrote the original source code. If you use this source code ++ in a product, an acknowledgment in the product documentation would be ++ appreciated but is not required. ++ . ++ 2. Altered source versions must be plainly marked as such, and must not be ++ misrepresented as being the original source code. ++ . ++ 3. This notice may not be removed or altered from any source distribution. ++ ++Files: src/Base/fdstream.hpp ++Copyright: 2001 Nicolai M. Josuttis ++License: other ++ Permission to copy, use, modify, sell and distribute this software ++ is granted provided this copyright notice appears in all copies. ++ This software is provided "as is" without express or implied ++ warranty, and with no claim as to its suitability for any purpose. ++ ++Files: src/Base/gzstream.* ++Copyright: 2001 Deepak Bandyopadhyay, Lutz Kettner ++License: LGPL-2.1+ ++ ++Files: src/Base/PyTools.* ++Copyright: 1996-2000 Mark Lutz, and O'Reilly and Associates. ++License: other ++ Permission to use, copy, modify, and distribute this software ++ for any purpose and without fee is hereby granted. This software ++ is provided on an as is basis, without warranties of any kind. ++ ++Files: src/Doc/Start_Page.html ++Copyright: 2004-2009 UnaMesa Association ++License: BSD ++ Copyright (c) UnaMesa Association 2004-2009 ++ . ++ Redistribution and use in source and binary forms, with or without ++ modification, are permitted provided that the following conditions are ++ met: ++ . ++ Redistributions of source code must retain the above copyright notice, ++ this list of conditions and the following disclaimer. ++ . ++ Redistributions in binary form must reproduce the above copyright notice, ++ this list of conditions and the following disclaimer in the documentation ++ and/or other materials provided with the distribution. ++ . ++ Neither the name of the UnaMesa Association nor the names of its ++ contributors may be used to endorse or promote products derived from this ++ software without specific prior written permission. ++ . ++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS ++ IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ++ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ++ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++Files: src/Doc/Start_Page.html ++Copyright: 2009 John Resig ++License: GPL-2 or MIT ++ On Debian systems, the complete text of the GNU General Public License ++ version 2 can be found in '/usr/share/common-licenses/GPL-2'. ++ ++License: MIT ++ Permission is hereby granted, free of charge, to any person obtaining ++ a copy of this software and associated documentation files (the ++ "Software"), to deal in the Software without restriction, including ++ without limitation the rights to use, copy, modify, merge, publish, ++ distribute, sublicense, and/or sell copies of the Software, and to ++ permit persons to whom the Software is furnished to do so, subject to ++ the following conditions: ++ . ++ The above copyright notice and this permission notice shall be ++ included in all copies or substantial portions of the Software. ++ . ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ++ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ++ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ++ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ ++Files: src/Doc/Start_Page.html ++Copyright: 2009 The Dojo Foundation, http://sizzlejs.com/ ++License: GPL-2 or MIT or BSD ++ ++Files: src/Gui/iisTaskPanel/src/* ++Copyright: http://www.ii-system.com ++License: LGPL ++ ++Files: src/Mod/Draft/* ++Copyright: Yorik van Havre, Werner Mayer, Martin Burbaum ++License: GPL-2+ ++ ++Files: src/Mod/Draft/draftlibs/dxf* ++Copyright: 2005-2008 Ed Blake, Remigiusz Fiedler, Stani Michiels ++License: GPL-2+ ++ ++Files: src/Mod/Draft/WorkingPlane.py ++Copyright: 2009-2010 Ken Cline ++License: GPL-2+ ++ ++Files: src/Base/BoundBox.h, src/Base/Swap.*, src/Base/Vector3D.*, ++ src/Base/ViewProj.h, src/Base/Matrix.*, src/Base/Tools2D.*, ++ src/Mod/Mesh/App/Core/* ++Copyright: 2005 Imetric 3D GmbH ++License: LGPL-2+ ++ ++Files: src/Mod/Mesh/App/Core/Projection.cpp, src/Mod/Mesh/App/Core/Projection.h, ++ src/Mod/Mesh/App/Core/Triangulation.cpp, src/Mod/Mesh/App/Core/Triangulation.h ++Copyright: 2005 Werner Mayer ++License: LGPL-2+ ++ ++Files: src/Mod/Mesh/App/Core/Builder.h, src/Mod/Mesh/App/Core/SetOperations.* ++Copyright: 2005 Berthold Grupp ++License: LGPL-2+ ++ ++Files: src/Mod/Mesh/BuildRegularGeoms.py ++Copyright: 2005 Berthold Grupp ++License: LGPL ++ ++Files: src/Mod/Image/App/ImageBase.*, src/Mod/Image/Gui/GLImageBox.*, ++ src/Mod/Image/Gui/ImageView.*, src/Mod/Image/Gui/XpmImages.h ++Copyright: 2004 Imetric 3D GmbH ++License: LGPL-2+ ++ ++Files: src/Mod/Mesh/App/Core/tritritest.h ++Copyright: 1997 Tomas Moller ++License: other ++ tritritest.h has no licensing information, but Tomas Moller replied ++ the following, when asked about it: ++ . ++ The code is is free to use for anyone and any projects, but I give no ++ warranties. ++ ++Files: src/Mod/Mesh/App/WildMagic4/* ++Copyright: 1998-2007 David Eberly http://www.geometrictools.com ++License: LGPL-2.1+ ++ ++Files: src/Mod/Part/App/edgecluster.* ++Copyright: 2010 Joachim Zettler ++License: LGPL-2+ ++ ++Files: src/Mod/Raytracing/App/resources/* ++Copyright: 2005 Georg Wiora , ++ Juergen Riegel ++License: LGPL-2+ ++ ++Files: src/Mod/Sketcher/App/sketchflat/* ++Copyright: 2008 Jonathan Westhues ++License: GPL-3+ ++ On Debian systems, the complete text of the GNU General Public License ++ version 3 can be found in '/usr/share/common-licenses/GPL-3'. ++ ++Files: src/Mod/Sketcher/App/sketchsolve_cp/* ++Copyright: 2009 Jonathan George ++License: BSD ++ ++Files: src/Mod/Test/unittestgui.py ++Copyright: 1999-2001 Steve Purcell ++License: PSF ++ This module is free software, and you may redistribute it and/or modify ++ it under the same terms as Python itself, so long as this copyright message ++ and disclaimer are retained in their original form. ++ . ++ IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, ++ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF ++ THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH ++ DAMAGE. ++ . ++ THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT ++ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, ++ AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, ++ SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. ++ ++Files: src/Mod/Part/MakeBottle.py, src/Tools/* ++Copyright: 2002-2008 Jürgen Riegel , ++ Werner Mayer ++License: GPL-2+ ++ ++Files: src/Tools/generateBase/generateDS.py ++Copyright: 2003 Dave Kuhlman ++License: MIT ++ ++Files: debian/* ++Copyright: 2007-2009 Werner Mayer , ++ Teemu Ikonen ++License: LGPL-2+ +--- freecad-0.13.orig/debian/source/format ++++ freecad-0.13/debian/source/format +@@ -0,0 +1 @@ ++1.0 +--- freecad-0.13.orig/debian/source/lintian-overrides ++++ freecad-0.13/debian/source/lintian-overrides +@@ -0,0 +1,3 @@ ++# Lintian thinks uploader Adam Powell's name violates policy ++freecad source: uploader-address-missing "Adam C. Powell ++freecad source: uploader-not-full-name IV" +--- freecad-0.13.orig/debian/mime/freecad-thumbnailer ++++ freecad-0.13/debian/mime/freecad-thumbnailer +@@ -0,0 +1,37 @@ ++#!/usr/bin/python ++ ++import sys, zipfile ++import getopt ++from urlparse import urlparse ++from urlparse import unquote ++ ++opt,par = getopt.getopt(sys.argv[1:],'-s:') ++uri = urlparse(par[0]) ++if uri.scheme != "file": ++ sys.exit(1) ++ ++inpfile = unquote(uri.path) ++outfile = par[1] ++ ++try: ++ zfile=zipfile.ZipFile(inpfile) ++ files=zfile.namelist() ++ # check for meta-file if it's really a FreeCAD document ++ if files[0] != "Document.xml": ++ sys.exit(1) ++ ++ image="thumbnails/Thumbnail.png" ++ if image in files: ++ image=zfile.read(image) ++ else: ++ #freecad=open("/usr/share/freecad/freecad-doc.png") ++ #image=freecad.read() ++ sys.exit(1) ++ ++ thumb=open(outfile,"wb") ++ thumb.write(image) ++ thumb.close() ++ ++except: ++ sys.exit(1) ++ +--- freecad-0.13.orig/debian/mime/freecad.thumbnailer ++++ freecad-0.13/debian/mime/freecad.thumbnailer +@@ -0,0 +1,4 @@ ++[Thumbnailer Entry] ++TryExec=/usr/bin/freecad-thumbnailer ++Exec=/usr/bin/freecad-thumbnailer -s %s %u %o ++MimeType=application/x-extension-fcstd; +--- freecad-0.13.orig/debian/mime/freecad-thumbnailer.1 ++++ freecad-0.13/debian/mime/freecad-thumbnailer.1 +@@ -0,0 +1,20 @@ ++.TH FREECAD 1 "August 04, 2008" freecad "Linux User's Manual" ++.SH NAME ++freecad-thumbnailer \- A thumbnailer for FreeCAD project files ++.SH SYNOPSIS ++\fBfreecad-thumbnailer\fP [ -s \fIsize\fP ] \fIinput file\fP \fIoutput file\fP ++.SH DESCRIPTION ++\fBfreecad-thumbnailer\fP ++is a Python script that extracts an embedded thumbnail from a FreeCAD project file. ++If no thumbnail is embedded then nothing happens. According to the specification of ++freedesktop.org the thumbnail image is a PNG file. The required \fBinput file\fP argument ++specifies the project file where the thumbnail should be extracted from and the ++\fBoutput file\fP specifies the file where the thumbnail should be written to. ++.SH OPTIONS ++.TP ++\fB-s \fIsize\fR ++Specify the size of the image in pixel. ++.SH "SEE ALSO" ++freecad(1), freecadcmd(1) ++.SH AUTHOR ++This manual page was written by Werner Mayer. +--- freecad-0.13.orig/debian/mime/freecad.schemas ++++ freecad-0.13/debian/mime/freecad.schemas +@@ -0,0 +1,30 @@ ++ ++ ++ ++ ++ /schemas/desktop/gnome/thumbnailers/application@x-extension-fcstd/enable ++ /desktop/gnome/thumbnailers/application@x-extension-fcstd/enable ++ freecad ++ bool ++ true ++ ++ Enable thumbnailing of FreeCAD documents. ++ Enable thumbnailing of FreeCAD documents. ++ ++ ++ ++ ++ ++ /schemas/desktop/gnome/thumbnailers/application@x-extension-fcstd/command ++ /desktop/gnome/thumbnailers/application@x-extension-fcstd/command ++ freecad ++ string ++ /usr/bin/freecad-thumbnailer -s %s %u %o ++ ++ Thumbnail command for documents from FreeCAD. ++ Valid command plus arguments for freecad-thumbnailer. ++ ++ ++ ++ ++ From 32117fb980e89745a59c90f02705ffe2eee82bd6 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 11 Jun 2013 17:28:21 +0200 Subject: [PATCH 080/160] Prepare Windows build to use FreeType --- README.Win32 | 4 + cMake/UseLibPack8x.cmake | 18 ++++- cMake/UseLibPackCustom.cmake | 134 ++++++++++++++++++-------------- src/Mod/Draft/Draft.py | 7 -- src/Mod/Draft/DraftTools.py | 13 ++-- src/Mod/Part/App/AppPartPy.cpp | 8 +- src/Mod/Part/App/CMakeLists.txt | 12 +-- src/Mod/Part/App/FT2FC.cpp | 8 +- 8 files changed, 114 insertions(+), 90 deletions(-) diff --git a/README.Win32 b/README.Win32 index 6d379daf9..a91ad5885 100644 --- a/README.Win32 +++ b/README.Win32 @@ -83,3 +83,7 @@ because it contains some Fortran code. project. 9. Build the file vcf2c.lib with "nmake -f makefile.vc" and add it to the MEFISTO2 project as additional library. The linker errors should now go away. + +* FreeType + +http://stackoverflow.com/questions/6207176/compiling-freetype-to-dll-as-opposed-to-static-library diff --git a/cMake/UseLibPack8x.cmake b/cMake/UseLibPack8x.cmake index 4b774a1d5..0d6961d6d 100644 --- a/cMake/UseLibPack8x.cmake +++ b/cMake/UseLibPack8x.cmake @@ -394,5 +394,19 @@ SET(EIGEN3_INCLUDE_DIR ${FREECAD_LIBPACK_DIR}/include/eigen3) set(EIGEN3_FOUND TRUE) - - +# FreeType +if(FREECAD_USE_FREETYPE) + set(FREETYPE_LIBRARIES + optimized ${FREECAD_LIBPACK_DIR}/lib/freetype.lib + debug ${FREECAD_LIBPACK_DIR}/lib/freetyped.lib + ) + set(FREETYPE_INCLUDE_DIRS + ${FREECAD_LIBPACK_DIR}/include/FreeType-2.4.12 + ) + set(FREETYPE_VERSION_STRING + "2.4.12" + ) + set(FREETYPE_FOUND + TRUE + ) +endif(FREECAD_USE_FREETYPE) diff --git a/cMake/UseLibPackCustom.cmake b/cMake/UseLibPackCustom.cmake index 3747af21f..986ca9fd4 100644 --- a/cMake/UseLibPackCustom.cmake +++ b/cMake/UseLibPackCustom.cmake @@ -323,72 +323,72 @@ set(NGLIB_DEBUG_LIBRARIES #set(OCC_INCLUDE_DIR C:/Projects/LibPack/oce-0.10.0/include/oce) #set(OCC_LIBRARY_DIR C:/Projects/LibPack/oce-0.10.0/Win64/lib) #set(OCC_LIBRARIES -# ${OCC_LIBRARY_DIR}/TKFillet.lib -# ${OCC_LIBRARY_DIR}/TKMesh.lib -# ${OCC_LIBRARY_DIR}/TKernel.lib -# ${OCC_LIBRARY_DIR}/TKG2d.lib -# ${OCC_LIBRARY_DIR}/TKG3d.lib -# ${OCC_LIBRARY_DIR}/TKMath.lib -# ${OCC_LIBRARY_DIR}/TKIGES.lib -# ${OCC_LIBRARY_DIR}/TKSTL.lib -# ${OCC_LIBRARY_DIR}/TKShHealing.lib -# ${OCC_LIBRARY_DIR}/TKXSBase.lib -# ${OCC_LIBRARY_DIR}/TKBool.lib -# ${OCC_LIBRARY_DIR}/TKBO.lib -# ${OCC_LIBRARY_DIR}/TKBRep.lib -# ${OCC_LIBRARY_DIR}/TKTopAlgo.lib -# ${OCC_LIBRARY_DIR}/TKGeomAlgo.lib -# ${OCC_LIBRARY_DIR}/TKGeomBase.lib -# ${OCC_LIBRARY_DIR}/TKOffset.lib -# ${OCC_LIBRARY_DIR}/TKPrim.lib -# ${OCC_LIBRARY_DIR}/TKSTEP.lib -# ${OCC_LIBRARY_DIR}/TKSTEPBase.lib -# ${OCC_LIBRARY_DIR}/TKSTEPAttr.lib -# ${OCC_LIBRARY_DIR}/TKHLR.lib -# ${OCC_LIBRARY_DIR}/TKFeat.lib +# ${OCC_LIBRARY_DIR}/TKFillet.lib +# ${OCC_LIBRARY_DIR}/TKMesh.lib +# ${OCC_LIBRARY_DIR}/TKernel.lib +# ${OCC_LIBRARY_DIR}/TKG2d.lib +# ${OCC_LIBRARY_DIR}/TKG3d.lib +# ${OCC_LIBRARY_DIR}/TKMath.lib +# ${OCC_LIBRARY_DIR}/TKIGES.lib +# ${OCC_LIBRARY_DIR}/TKSTL.lib +# ${OCC_LIBRARY_DIR}/TKShHealing.lib +# ${OCC_LIBRARY_DIR}/TKXSBase.lib +# ${OCC_LIBRARY_DIR}/TKBool.lib +# ${OCC_LIBRARY_DIR}/TKBO.lib +# ${OCC_LIBRARY_DIR}/TKBRep.lib +# ${OCC_LIBRARY_DIR}/TKTopAlgo.lib +# ${OCC_LIBRARY_DIR}/TKGeomAlgo.lib +# ${OCC_LIBRARY_DIR}/TKGeomBase.lib +# ${OCC_LIBRARY_DIR}/TKOffset.lib +# ${OCC_LIBRARY_DIR}/TKPrim.lib +# ${OCC_LIBRARY_DIR}/TKSTEP.lib +# ${OCC_LIBRARY_DIR}/TKSTEPBase.lib +# ${OCC_LIBRARY_DIR}/TKSTEPAttr.lib +# ${OCC_LIBRARY_DIR}/TKHLR.lib +# ${OCC_LIBRARY_DIR}/TKFeat.lib #) #set(OCC_OCAF_LIBRARIES -# ${OCC_LIBRARY_DIR}/TKCAF.lib -# ${OCC_LIBRARY_DIR}/TKXCAF.lib -# ${OCC_LIBRARY_DIR}/TKLCAF.lib -# ${OCC_LIBRARY_DIR}/TKXDESTEP.lib -# ${OCC_LIBRARY_DIR}/TKXDEIGES.lib +# ${OCC_LIBRARY_DIR}/TKCAF.lib +# ${OCC_LIBRARY_DIR}/TKXCAF.lib +# ${OCC_LIBRARY_DIR}/TKLCAF.lib +# ${OCC_LIBRARY_DIR}/TKXDESTEP.lib +# ${OCC_LIBRARY_DIR}/TKXDEIGES.lib #) set(OCC_INCLUDE_DIR ${FREECAD_LIBPACK_DIR}/include/OpenCascade-6.3.0) set(OCC_LIBRARY_DIR ${FREECAD_LIBPACK_DIR}/lib) set(OCC_LIBRARIES - TKFillet - TKMesh - TKernel - TKG2d - TKG3d - TKMath - TKIGES - TKSTL - TKShHealing - TKXSBase - TKBool - TKBO - TKBRep - TKTopAlgo - TKGeomAlgo - TKGeomBase - TKOffset - TKPrim - TKSTEP - TKSTEPBase - TKSTEPAttr - TKHLR - TKFeat + TKFillet + TKMesh + TKernel + TKG2d + TKG3d + TKMath + TKIGES + TKSTL + TKShHealing + TKXSBase + TKBool + TKBO + TKBRep + TKTopAlgo + TKGeomAlgo + TKGeomBase + TKOffset + TKPrim + TKSTEP + TKSTEPBase + TKSTEPAttr + TKHLR + TKFeat ) set(OCC_OCAF_LIBRARIES - TKCAF - TKXCAF - TKLCAF - TKXDESTEP - TKXDEIGES - TKMeshVS - TKAdvTools + TKCAF + TKXCAF + TKLCAF + TKXDESTEP + TKXDEIGES + TKMeshVS + TKAdvTools ) set(OCC_FOUND TRUE) @@ -402,5 +402,19 @@ set(ODE_INCLUDE_DIRS ${FREECAD_LIBPACK_DIR}/include/ode-0.11.1) set(ODE_LIBRARIES ${FREECAD_LIBPACK_DIR}/lib/ode_double.lib) set(ODE_FOUND TRUE) - - +# FreeType +if(FREECAD_USE_FREETYPE) + set(FREETYPE_LIBRARIES + optimized ${FREECAD_LIBPACK_DIR}/lib/freetype.lib + debug ${FREECAD_LIBPACK_DIR}/lib/freetyped.lib + ) + set(FREETYPE_INCLUDE_DIRS + ${FREECAD_LIBPACK_DIR}/include/FreeType-2.4.12 + ) + set(FREETYPE_VERSION_STRING + "2.4.12" + ) + set(FREETYPE_FOUND + TRUE + ) +endif(FREECAD_USE_FREETYPE) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 18b79ef2b..270a6a441 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -1699,13 +1699,6 @@ def makeShapeString(String,FontFile,Size = 100,Tracking = 0): into a Compound Shape''' # temporary code - import platform - if not (platform.system() == 'Linux'): -# if (platform.system() == 'Linux'): - FreeCAD.Console.PrintWarning("Sorry, ShapeString is not yet implemented for your platform.\n") - return (None) - # temporary code - obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython","ShapeString") _ShapeString(obj) obj.String = String diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index 33fb5d6ca..89cd5df9d 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -1795,7 +1795,7 @@ class ShapeString(Creator): def GetResources(self): return {'Pixmap' : 'Draft_ShapeString', 'Accel' : "S, S", - 'MenuShapeString': QtCore.QT_TRANSLATE_NOOP("Draft_ShapeString", "ShapeString"), + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_ShapeString", "Shape from text..."), 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_ShapeString", "Creates text string in shapes.")} def Activated(self): @@ -1817,12 +1817,11 @@ class ShapeString(Creator): "creates object in the current doc" # print "debug: D_T ShapeString.createObject type(self.SString): " str(type(self.SString)) # temporary code - import platform - if not (platform.system() == 'Linux'): -# if (platform.system() == 'Linux'): - FreeCAD.Console.PrintWarning("Sorry, ShapeString is not yet fully implemented for your platform.\n") - self.finish() - return + #import platform + #if not (platform.system() == 'Linux'): + # FreeCAD.Console.PrintWarning("Sorry, ShapeString is not yet fully implemented for your platform.\n") + # self.finish() + # return # temporary code dquote = '"' diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index edd96dfaf..5973e0659 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -342,17 +342,17 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) &track)) { Base::Console().Message("** makeWireString bad args.\n"); return NULL; - } + } if (PyString_Check(intext)) { PyObject *p = Base::PyAsUnicodeObject(PyString_AsString(intext)); if (!p) { Base::Console().Message("** makeWireString can't convert PyString.\n"); return NULL; - } + } pysize = PyUnicode_GetSize(p); unichars = PyUnicode_AS_UNICODE(p); - } + } else if (PyUnicode_Check(intext)) { pysize = PyUnicode_GetSize(intext); unichars = PyUnicode_AS_UNICODE(intext); @@ -376,7 +376,7 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) return (CharList); } -#else +#else static PyObject * makeWireString(PyObject *self, PyObject *args) { diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index aaf1fb612..e337bebb9 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -4,9 +4,9 @@ else(MSVC) add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H) endif(MSVC) -if(FREECAD_USE_FREETYPE) - add_definitions(-DFCUseFreeType) -endif(FREECAD_USE_FREETYPE) +if(FREETYPE_FOUND) + add_definitions(-DFCUseFreeType) +endif(FREETYPE_FOUND) include_directories( ${CMAKE_BINARY_DIR}/src @@ -28,12 +28,12 @@ set(Part_LIBS FreeCADApp ) -if(FREECAD_USE_FREETYPE) +if(FREETYPE_FOUND) set(Part_LIBS ${Part_LIBS} - ${FREETYPE_LIBRARY} + ${FREETYPE_LIBRARIES} ) -endif(FREECAD_USE_FREETYPE) +endif(FREETYPE_FOUND) generate_from_xml(ArcPy) generate_from_xml(ArcOfCirclePy) diff --git a/src/Mod/Part/App/FT2FC.cpp b/src/Mod/Part/App/FT2FC.cpp index cc3c7c3f3..f1986e3f7 100644 --- a/src/Mod/Part/App/FT2FC.cpp +++ b/src/Mod/Part/App/FT2FC.cpp @@ -330,11 +330,11 @@ FT_Vector getKerning(FT_Face FTFont, UNICHAR lc, UNICHAR rc) { if(error) { ErrorMsg << "FT_Get_Kerning failed: " << error; throw std::runtime_error(ErrorMsg.str()); - } + } retXY.x = ftKern.x; retXY.y = ftKern.y; return(retXY); - } +} // Make a TopoDS_Wire from a list of TopoDS_Edges TopoShapeWirePy* edgesToWire(std::vector Edges) { @@ -350,7 +350,7 @@ TopoShapeWirePy* edgesToWire(std::vector Edges) { TopoShapeWirePy* newwire = new TopoShapeWirePy(new TopoShape (occwire)); return(newwire); - } +} -#endif //#ifdef FCUseFreeType \ No newline at end of file +#endif //#ifdef FCUseFreeType From 7e792ef7619c5c0c26ee89428421faf6c70a6509 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 11 Jun 2013 22:31:15 +0200 Subject: [PATCH 081/160] Use PropertyFile for fonts --- src/Mod/Draft/Draft.py | 2 +- src/Mod/Part/App/AppPartPy.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 270a6a441..91c8ad942 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -3727,7 +3727,7 @@ class _ShapeString(_DraftObject): def __init__(self, obj): _DraftObject.__init__(self,obj,"ShapeString") obj.addProperty("App::PropertyString","String","Base","Text string") - obj.addProperty("App::PropertyString","FontFile","Base","Font file name") + obj.addProperty("App::PropertyFile","FontFile","Base","Font file name") obj.addProperty("App::PropertyFloat","Size","Base","Height of text") obj.addProperty("App::PropertyInteger","Tracking","Base", "Inter-character spacing") diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index 5973e0659..e9286a326 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -329,7 +329,6 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) float height; int track = 0; - const char* text; Py_UNICODE *unichars; Py_ssize_t pysize; From 2282b72025e4d7e926bb5721bf9da4da698c6ebc Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 12 Jun 2013 17:01:55 +0200 Subject: [PATCH 082/160] 0001143: Boolean Cut Fails with Extruded Shapestring --- src/Mod/Draft/Draft.py | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 91c8ad942..0065f6659 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -3764,13 +3764,34 @@ class _ShapeString(_DraftObject): # whitespace (ex: ' ') has no faces. This breaks OpenSCAD2Dgeom... if CharFaces: # s = OpenSCAD2Dgeom.Overlappingfaces(CharFaces).makeshape() - s = self.makeGlyph(CharFaces) + #s = self.makeGlyph(CharFaces) + s = self.makeFaces(char) SSChars.append(s) shape = Part.Compound(SSChars) fp.Shape = shape if plm: fp.Placement = plm - + + def makeFaces(self, wireChar): + import Part + compFaces=[] + wirelist=sorted(wireChar,key=(lambda shape: shape.BoundBox.DiagonalLength),reverse=True) + wire2Face = [wirelist[0]] + face = Part.Face(wirelist[0]) + for w in wirelist[1:]: + p = w.Vertexes[0].Point + u,v = face.Surface.parameter(p) + if face.isPartOfDomain(u,v): + if face.Orientation == w.Orientation: + w.reverse() + wire2Face.append(w) + else: + compFaces.append(Part.Face(w)) + face = Part.Face(wire2Face) + compFaces.append(face) + ret = Part.Compound(compFaces) + return ret + def makeGlyph(self, facelist): ''' turn list of simple contour faces into a compound shape representing a glyph ''' ''' remove cuts, fuse overlapping contours, retain islands ''' @@ -3799,7 +3820,11 @@ class _ShapeString(_DraftObject): else: # partial overlap - (font designer error?) result = result.fuse(face) - glyphfaces = [result] + #glyphfaces = [result] + wl = result.Wires + for w in wl: + w.fixWire() + glyphfaces = [Part.Face(wl)] glyphfaces.extend(islands) ret = Part.Compound(glyphfaces) # should we fuse these instead of making compound? return ret From 00b4fd364af7c83db873a2d72a1008b3ad47292d Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 12 Jun 2013 23:15:13 +0200 Subject: [PATCH 083/160] Show status of downloading file --- src/Gui/DownloadItem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Gui/DownloadItem.cpp b/src/Gui/DownloadItem.cpp index 216a08e09..46d226967 100644 --- a/src/Gui/DownloadItem.cpp +++ b/src/Gui/DownloadItem.cpp @@ -502,8 +502,8 @@ void DownloadItem::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) void DownloadItem::updateInfoLabel() { - if (m_reply->error() == QNetworkReply::NoError) - return; + //if (m_reply->error() == QNetworkReply::NoError) + // return; qint64 bytesTotal = progressBar->maximum(); bool running = !downloadedSuccessfully(); From b36ffe63fd98e5cfb32f461af685c88a3339b253 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 12 Jun 2013 23:15:53 +0200 Subject: [PATCH 084/160] Activate OSD signals on Linux --- src/Mod/Drawing/App/ProjectionAlgos.cpp | 3 --- src/Mod/Part/App/AppPart.cpp | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Mod/Drawing/App/ProjectionAlgos.cpp b/src/Mod/Drawing/App/ProjectionAlgos.cpp index 38ca1f48d..d35412613 100644 --- a/src/Mod/Drawing/App/ProjectionAlgos.cpp +++ b/src/Mod/Drawing/App/ProjectionAlgos.cpp @@ -120,9 +120,6 @@ void ProjectionAlgos::execute(void) brep_hlr->Add(Input); try { -#if defined(__GNUC__) && defined (FC_OS_LINUX) - Base::SignalException se; -#endif gp_Ax2 transform(gp_Pnt(0,0,0),gp_Dir(Direction.x,Direction.y,Direction.z)); HLRAlgo_Projector projector( transform ); brep_hlr->Projector(projector); diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp index ac22ca8cc..b405fc561 100644 --- a/src/Mod/Part/App/AppPart.cpp +++ b/src/Mod/Part/App/AppPart.cpp @@ -13,6 +13,7 @@ #ifndef _PreComp_ # include # include +# include # include #endif @@ -101,6 +102,9 @@ void PartExport initPart() App::GetApplication().addImportType("STEP with colors (*.step *.stp)","ImportGui"); App::GetApplication().addExportType("STEP with colors (*.step *.stp)","ImportGui"); #endif +#endif +#if defined(FC_OS_LINUX) + OSD::SetSignal(); #endif PyObject* partModule = Py_InitModule3("Part", Part_methods, module_part_doc); /* mod name, table ptr */ From b97266a3412a28fa8d5245025427be3fd18355f5 Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 13 Jun 2013 12:14:24 +0200 Subject: [PATCH 085/160] #0001143: Boolean Cut Fails with Extruded Shapestring --- src/Mod/Draft/Draft.py | 17 ++++++-- src/Mod/Part/App/TopoShapeFacePy.xml | 5 +++ src/Mod/Part/App/TopoShapeFacePyImp.cpp | 58 +++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 0065f6659..2e47c83fe 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -3782,12 +3782,23 @@ class _ShapeString(_DraftObject): p = w.Vertexes[0].Point u,v = face.Surface.parameter(p) if face.isPartOfDomain(u,v): - if face.Orientation == w.Orientation: - w.reverse() + f = Part.Face(w) + if face.Orientation == f.Orientation: + if f.Surface.Axis * face.Surface.Axis < 0: + w.reverse() + else: + if f.Surface.Axis * face.Surface.Axis > 0: + w.reverse() wire2Face.append(w) else: - compFaces.append(Part.Face(w)) + f = Part.Face(w) + if f.Surface.Axis.z < 0.0: + f.reverse() + compFaces.append(f) face = Part.Face(wire2Face) + face.validate() + if face.Surface.Axis.z < 0.0: + face.reverse() compFaces.append(face) ret = Part.Compound(compFaces) return ret diff --git a/src/Mod/Part/App/TopoShapeFacePy.xml b/src/Mod/Part/App/TopoShapeFacePy.xml index 8d18c4a04..8c8bb25a4 100644 --- a/src/Mod/Part/App/TopoShapeFacePy.xml +++ b/src/Mod/Part/App/TopoShapeFacePy.xml @@ -59,6 +59,11 @@ Make a half-space solid by this face and a reference point. + + + Validate the face. + + Set the tolerance for the face. diff --git a/src/Mod/Part/App/TopoShapeFacePyImp.cpp b/src/Mod/Part/App/TopoShapeFacePyImp.cpp index b0460a580..00e86fddd 100644 --- a/src/Mod/Part/App/TopoShapeFacePyImp.cpp +++ b/src/Mod/Part/App/TopoShapeFacePyImp.cpp @@ -25,6 +25,7 @@ #ifndef _PreComp_ # include # include +# include # include # include # include @@ -49,6 +50,10 @@ # include # include # include +# include +# include +# include +# include #endif #include @@ -445,6 +450,59 @@ PyObject* TopoShapeFacePy::makeHalfSpace(PyObject *args) } } +PyObject* TopoShapeFacePy::validate(PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return 0; + + try { + const TopoDS_Face& face = TopoDS::Face(getTopoShapePtr()->_Shape); + BRepCheck_Analyzer aChecker(face); + if (!aChecker.IsValid()) { + TopoDS_Wire outerwire = ShapeAnalysis::OuterWire(face); + TopTools_IndexedMapOfShape myMap; + myMap.Add(outerwire); + + TopExp_Explorer xp(face,TopAbs_WIRE); + ShapeFix_Wire fix; + fix.SetFace(face); + fix.Load(outerwire); + fix.Perform(); + BRepBuilderAPI_MakeFace mkFace(fix.WireAPIMake()); + while (xp.More()) { + if (!myMap.Contains(xp.Current())) { + fix.Load(TopoDS::Wire(xp.Current())); + fix.Perform(); + mkFace.Add(fix.WireAPIMake()); + } + xp.Next(); + } + + aChecker.Init(mkFace.Face()); + if (!aChecker.IsValid()) { + ShapeFix_Shape fix(mkFace.Face()); + fix.SetPrecision(Precision::Confusion()); + fix.SetMaxTolerance(Precision::Confusion()); + fix.SetMaxTolerance(Precision::Confusion()); + fix.Perform(); + fix.FixWireTool()->Perform(); + fix.FixFaceTool()->Perform(); + getTopoShapePtr()->_Shape = fix.Shape(); + } + else { + getTopoShapePtr()->_Shape = mkFace.Face(); + } + } + + Py_Return; + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + PyErr_SetString(PyExc_Exception, e->GetMessageString()); + return 0; + } +} + Py::Object TopoShapeFacePy::getSurface() const { const TopoDS_Face& f = TopoDS::Face(getTopoShapePtr()->_Shape); From 88a05de6ba8027bc23a9d80b81bb2fb18707e1c5 Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 13 Jun 2013 14:37:01 +0200 Subject: [PATCH 086/160] #0001143: Boolean Cut Fails with Extruded Shapestring --- src/Mod/Draft/Draft.py | 56 ++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 2e47c83fe..d8f5edbeb 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -2001,7 +2001,7 @@ def upgrade(objects,delete=False,force=None): loneedges = [] meshes = [] for ob in objects: - if ob.Type == "App::DocumentObjectGroup": + if ob.TypeId == "App::DocumentObjectGroup": groups.append(ob) elif ob.isDerivedFrom("Part::Feature"): parts.append(ob) @@ -3776,30 +3776,38 @@ class _ShapeString(_DraftObject): import Part compFaces=[] wirelist=sorted(wireChar,key=(lambda shape: shape.BoundBox.DiagonalLength),reverse=True) - wire2Face = [wirelist[0]] - face = Part.Face(wirelist[0]) - for w in wirelist[1:]: - p = w.Vertexes[0].Point - u,v = face.Surface.parameter(p) - if face.isPartOfDomain(u,v): - f = Part.Face(w) - if face.Orientation == f.Orientation: - if f.Surface.Axis * face.Surface.Axis < 0: - w.reverse() + fixedwire = [] + for w in wirelist: + compEdges = Part.Compound(w.Edges) + compEdges = compEdges.connectEdgesToWires() + fixedwire.append(compEdges.Wires[0]) + wirelist = fixedwire + + sep_wirelist = [] + while len(wirelist) > 0: + wire2Face = [wirelist[0]] + face = Part.Face(wirelist[0]) + for w in wirelist[1:]: + p = w.Vertexes[0].Point + u,v = face.Surface.parameter(p) + if face.isPartOfDomain(u,v): + f = Part.Face(w) + if face.Orientation == f.Orientation: + if f.Surface.Axis * face.Surface.Axis < 0: + w.reverse() + else: + if f.Surface.Axis * face.Surface.Axis > 0: + w.reverse() + wire2Face.append(w) else: - if f.Surface.Axis * face.Surface.Axis > 0: - w.reverse() - wire2Face.append(w) - else: - f = Part.Face(w) - if f.Surface.Axis.z < 0.0: - f.reverse() - compFaces.append(f) - face = Part.Face(wire2Face) - face.validate() - if face.Surface.Axis.z < 0.0: - face.reverse() - compFaces.append(face) + sep_wirelist.append(w) + wirelist = sep_wirelist + sep_wirelist = [] + face = Part.Face(wire2Face) + face.validate() + if face.Surface.Axis.z < 0.0: + face.reverse() + compFaces.append(face) ret = Part.Compound(compFaces) return ret From 5a04adebe478a24d60fab9de81494113c982e984 Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 13 Jun 2013 22:30:46 +0200 Subject: [PATCH 087/160] #0000862: Draft toolbar doesn't disappear when switching workbenches --- src/Mod/Arch/InitGui.py | 2 ++ src/Mod/Draft/DraftSnap.py | 9 ++++++++- src/Mod/Draft/InitGui.py | 9 +++++++-- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/Mod/Arch/InitGui.py b/src/Mod/Arch/InitGui.py index 1f5f2386d..7e0cd8361 100644 --- a/src/Mod/Arch/InitGui.py +++ b/src/Mod/Arch/InitGui.py @@ -118,6 +118,8 @@ class ArchWorkbench(Workbench): def Deactivated(self): if hasattr(FreeCADGui,"draftToolBar"): FreeCADGui.draftToolBar.Deactivated() + if hasattr(FreeCADGui,"Snapper"): + FreeCADGui.Snapper.hide() Msg("Arch workbench deactivated\n") def ContextMenu(self, recipient): diff --git a/src/Mod/Draft/DraftSnap.py b/src/Mod/Draft/DraftSnap.py index bedb71f13..9b2d8ad9e 100644 --- a/src/Mod/Draft/DraftSnap.py +++ b/src/Mod/Draft/DraftSnap.py @@ -851,7 +851,7 @@ class Snapper: "builds the Snap toolbar" self.toolbar = QtGui.QToolBar(None) self.toolbar.setObjectName("Draft Snap") - self.toolbar.setWindowTitle("Draft Snap") + self.toolbar.setWindowTitle(QtCore.QCoreApplication.translate("Workbench", "Draft Snap")) self.toolbarButtons = [] self.masterbutton = QtGui.QPushButton(None) self.masterbutton.setIcon(QtGui.QIcon(":/icons/Snap_Lock.svg")) @@ -933,10 +933,17 @@ class Snapper: bt = mw.findChild(QtGui.QToolBar,"Draft Snap") if not bt: mw.addToolBar(self.toolbar) + self.toolbar.setParent(mw) self.toolbar.show() + self.toolbar.toggleViewAction().setVisible(True) if FreeCADGui.ActiveDocument: self.setTrackers() + def hide(self): + if hasattr(self,"toolbar"): + self.toolbar.hide() + self.toolbar.toggleViewAction().setVisible(True) + def setGrid(self): "sets the grid, if visible" if self.grid and (not self.forceGridOff): diff --git a/src/Mod/Draft/InitGui.py b/src/Mod/Draft/InitGui.py index add28732a..57fbca4db 100644 --- a/src/Mod/Draft/InitGui.py +++ b/src/Mod/Draft/InitGui.py @@ -68,6 +68,9 @@ class DraftWorkbench (Workbench): ToolTip = "The Draft module is used for basic 2D CAD Drafting" def Initialize(self): + def QT_TRANSLATE_NOOP(scope, text): + return text + # run self-tests depsOK = False try: @@ -115,8 +118,8 @@ class DraftWorkbench (Workbench): "Draft_SelectGroup","Draft_SelectPlane","Draft_ToggleSnap", "Draft_ShowSnapBar","Draft_ToggleGrid"] self.lineList = ["Draft_UndoLine","Draft_FinishLine","Draft_CloseLine"] - self.appendToolbar(str(DraftTools.translate("draft","Draft creation tools")),self.cmdList) - self.appendToolbar(str(DraftTools.translate("draft","Draft modification tools")),self.modList) + self.appendToolbar(QT_TRANSLATE_NOOP("Workbench","Draft creation tools"),self.cmdList) + self.appendToolbar(QT_TRANSLATE_NOOP("Workbench","Draft modification tools"),self.modList) self.appendMenu(str(DraftTools.translate("draft","&Draft")),self.cmdList+self.modList) self.appendMenu([str(DraftTools.translate("draft","&Draft")),str(DraftTools.translate("draft","Context tools"))],self.treecmdList) self.appendMenu([str(DraftTools.translate("draft","&Draft")),str(DraftTools.translate("draft","Wire tools"))],self.lineList) @@ -131,6 +134,8 @@ class DraftWorkbench (Workbench): def Deactivated(self): if hasattr(FreeCADGui,"draftToolBar"): FreeCADGui.draftToolBar.Deactivated() + if hasattr(FreeCADGui,"Snapper"): + FreeCADGui.Snapper.hide() Msg("Draft workbench deactivated\n") def ContextMenu(self, recipient): From 90292ecaafc951ad47882576668cfc1ad088b355 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 14 Jun 2013 14:33:02 +0200 Subject: [PATCH 088/160] Create minidump file if FreeCAD crashes on Windows --- src/Main/MainGui.cpp | 106 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/src/Main/MainGui.cpp b/src/Main/MainGui.cpp index 03407c52d..fdb417da2 100644 --- a/src/Main/MainGui.cpp +++ b/src/Main/MainGui.cpp @@ -161,6 +161,10 @@ private: QDomDocument domDocument; }; +#if defined(_MSC_VER) +void InitMiniDumpWriter(const std::string&); +#endif + #if defined (FC_OS_LINUX) || defined(FC_OS_BSD) QString myDecoderFunc(const QByteArray &localFileName) { @@ -224,6 +228,12 @@ int main( int argc, char ** argv ) // Inits the Application App::Application::init(argc,argv); +#if defined(_MSC_VER) + // create a dump file when the application crashes + std::string dmpfile = App::Application::getUserAppDataDir(); + dmpfile += "crash.dmp"; + InitMiniDumpWriter(dmpfile); +#endif Gui::Application::initApplication(); Base::Interpreter().replaceStdOutput(); } @@ -325,3 +335,99 @@ int main( int argc, char ** argv ) return 0; } + +#if defined(_MSC_VER) +#include +#include + +typedef BOOL (__stdcall *tMDWD)( + IN HANDLE hProcess, + IN DWORD ProcessId, + IN HANDLE hFile, + IN MINIDUMP_TYPE DumpType, + IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL + IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL + IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL + ); + +static tMDWD s_pMDWD; +static HMODULE s_hDbgHelpMod; +static MINIDUMP_TYPE s_dumpTyp = MiniDumpNormal; +static std::string s_szMiniDumpFileName; // initialize with whatever appropriate... + +static LONG __stdcall MyCrashHandlerExceptionFilter(EXCEPTION_POINTERS* pEx) +{ +#ifdef _M_IX86 + if (pEx->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) + { + // be sure that we have enought space... + static char MyStack[1024*128]; + // it assumes that DS and SS are the same!!! (this is the case for Win32) + // change the stack only if the selectors are the same (this is the case for Win32) + //__asm push offset MyStack[1024*128]; + //__asm pop esp; + __asm mov eax,offset MyStack[1024*128]; + __asm mov esp,eax; + } +#endif + bool bFailed = true; + HANDLE hFile; + hFile = CreateFile(s_szMiniDumpFileName.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + MINIDUMP_EXCEPTION_INFORMATION stMDEI; + stMDEI.ThreadId = GetCurrentThreadId(); + stMDEI.ExceptionPointers = pEx; + stMDEI.ClientPointers = TRUE; + // try to create an miniDump: + if (s_pMDWD( + GetCurrentProcess(), + GetCurrentProcessId(), + hFile, + s_dumpTyp, + &stMDEI, + NULL, + NULL + )) + { + bFailed = false; // suceeded + } + CloseHandle(hFile); + } + + if (bFailed) + { + return EXCEPTION_CONTINUE_SEARCH; + } + + // Optional display an error message + // FatalAppExit(-1, ("Application failed!")); + + + // or return one of the following: + // - EXCEPTION_CONTINUE_SEARCH + // - EXCEPTION_CONTINUE_EXECUTION + // - EXCEPTION_EXECUTE_HANDLER + return EXCEPTION_CONTINUE_SEARCH; // this will trigger the "normal" OS error-dialog +} + +void InitMiniDumpWriter(const std::string& filename) +{ + if (s_hDbgHelpMod != NULL) + return; + s_szMiniDumpFileName = filename; + + // Initialize the member, so we do not load the dll after the exception has occured + // which might be not possible anymore... + s_hDbgHelpMod = LoadLibrary(("dbghelp.dll")); + if (s_hDbgHelpMod != NULL) + s_pMDWD = (tMDWD) GetProcAddress(s_hDbgHelpMod, "MiniDumpWriteDump"); + + // Register Unhandled Exception-Filter: + SetUnhandledExceptionFilter(MyCrashHandlerExceptionFilter); + + // Additional call "PreventSetUnhandledExceptionFilter"... + // See also: "SetUnhandledExceptionFilter" and VC8 (and later) + // http://blog.kalmbachnet.de/?postid=75 +} +#endif From 6a88bcd87051ec583ff115bd240e65cdc86add7f Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Fri, 14 Jun 2013 11:19:58 -0300 Subject: [PATCH 089/160] 0001138: Use TypeId in Draft & Arch --- src/Mod/Draft/Draft.py | 30 +++++++++++++++--------------- src/Mod/Draft/DraftGui.py | 2 +- src/Mod/Draft/importDXF.py | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index d8f5edbeb..26fb53e01 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -210,7 +210,7 @@ def getGroupNames(): glist = [] doc = FreeCAD.ActiveDocument for obj in doc.Objects: - if obj.Type == "App::DocumentObjectGroup": + if obj.TypeId == "App::DocumentObjectGroup": glist.append(obj.Name) return glist @@ -680,61 +680,61 @@ def makeText(stringslist,point=Vector(0,0,0),screen=False): def makeCopy(obj,force=None,reparent=False): '''makeCopy(object): returns an exact copy of an object''' if (getType(obj) == "Rectangle") or (force == "Rectangle"): - newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) + newobj = FreeCAD.ActiveDocument.addObject(obj.TypeId,getRealName(obj.Name)) _Rectangle(newobj) if gui: _ViewProviderRectangle(newobj.ViewObject) elif (getType(obj) == "Dimension") or (force == "Dimension"): - newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) + newobj = FreeCAD.ActiveDocument.addObject(obj.TypeId,getRealName(obj.Name)) _Dimension(newobj) if gui: _ViewProviderDimension(newobj.ViewObject) elif (getType(obj) == "Wire") or (force == "Wire"): - newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) + newobj = FreeCAD.ActiveDocument.addObject(obj.TypeId,getRealName(obj.Name)) _Wire(newobj) if gui: _ViewProviderWire(newobj.ViewObject) elif (getType(obj) == "Circle") or (force == "Circle"): - newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) + newobj = FreeCAD.ActiveDocument.addObject(obj.TypeId,getRealName(obj.Name)) _Circle(newobj) if gui: _ViewProviderDraft(newobj.ViewObject) elif (getType(obj) == "Polygon") or (force == "Polygon"): - newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) + newobj = FreeCAD.ActiveDocument.addObject(obj.TypeId,getRealName(obj.Name)) _Polygon(newobj) if gui: _ViewProviderDraft(newobj.ViewObject) elif (getType(obj) == "BSpline") or (force == "BSpline"): - newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) + newobj = FreeCAD.ActiveDocument.addObject(obj.TypeId,getRealName(obj.Name)) _BSpline(newobj) if gui: _ViewProviderBSpline(newobj.ViewObject) elif (getType(obj) == "Block") or (force == "BSpline"): - newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) + newobj = FreeCAD.ActiveDocument.addObject(obj.TypeId,getRealName(obj.Name)) _Block(newobj) if gui: _ViewProviderDraftPart(newobj.ViewObject) elif (getType(obj) == "Structure") or (force == "Structure"): import ArchStructure - newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) + newobj = FreeCAD.ActiveDocument.addObject(obj.TypeId,getRealName(obj.Name)) ArchStructure._Structure(newobj) if gui: ArchStructure._ViewProviderStructure(newobj.ViewObject) elif (getType(obj) == "Wall") or (force == "Wall"): import ArchWall - newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) + newobj = FreeCAD.ActiveDocument.addObject(obj.TypeId,getRealName(obj.Name)) ArchWall._Wall(newobj) if gui: ArchWall._ViewProviderWall(newobj.ViewObject) elif (getType(obj) == "Window") or (force == "Window"): import ArchWindow - newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) + newobj = FreeCAD.ActiveDocument.addObject(obj.TypeId,getRealName(obj.Name)) ArchWindow._Window(newobj) if gui: Archwindow._ViewProviderWindow(newobj.ViewObject) elif (getType(obj) == "Cell") or (force == "Cell"): import ArchCell - newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) + newobj = FreeCAD.ActiveDocument.addObject(obj.TypeId,getRealName(obj.Name)) ArchCell._Cell(newobj) if gui: ArchCell._ViewProviderCell(newobj.ViewObject) @@ -758,7 +758,7 @@ def makeCopy(obj,force=None,reparent=False): parents = obj.InList if parents: for par in parents: - if par.Type == "App::DocumentObjectGroup": + if par.TypeId == "App::DocumentObjectGroup": par.addObject(newobj) else: for prop in par.PropertiesList: @@ -1067,7 +1067,7 @@ def scale(objectslist,delta=Vector(1,1,1),center=Vector(0,0,0),copy=False,legacy newobj.Points = p elif (obj.isDerivedFrom("Part::Feature")): newobj.Shape = sh - elif (obj.Type == "App::Annotation"): + elif (obj.TypeId == "App::Annotation"): factor = delta.x * delta.y * delta.z * obj.ViewObject.FontSize obj.ViewObject.Fontsize = factor if copy: formatObject(newobj,obj) @@ -1752,7 +1752,7 @@ def heal(objlist=None,delete=True,reparent=True): for obj in objlist: dtype = getType(obj) - ftype = obj.Type + ftype = obj.TypeId if ftype in ["Part::FeaturePython","App::FeaturePython","Part::Part2DObjectPython"]: if obj.ViewObject.Proxy == 1 and dtype in ["Unknown","Part"]: got = True diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py index 1ea342253..d50773561 100644 --- a/src/Mod/Draft/DraftGui.py +++ b/src/Mod/Draft/DraftGui.py @@ -868,7 +868,7 @@ class DraftToolBar: b = float(self.color.blue()/255.0) col = (r,g,b,0.0) for i in FreeCADGui.Selection.getSelection(): - if (i.Type == "App::Annotation"): + if (i.TypeId == "App::Annotation"): i.ViewObject.TextColor=col else: if "LineColor" in i.ViewObject.PropertiesList: diff --git a/src/Mod/Draft/importDXF.py b/src/Mod/Draft/importDXF.py index 7c19cc0a5..7ee157a06 100644 --- a/src/Mod/Draft/importDXF.py +++ b/src/Mod/Draft/importDXF.py @@ -143,7 +143,7 @@ def calcBulge(v1,bulge,v2): def getGroup(ob,exportList): "checks if the object is part of a group" for i in exportList: - if (i.Type == "App::DocumentObjectGroup"): + if (i.TypeId == "App::DocumentObjectGroup"): for j in i.Group: if (j == ob): return i.Label From f0d9cdbc12f5e30714d96d8aec2448e00cba5bef Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Fri, 14 Jun 2013 12:04:59 -0300 Subject: [PATCH 090/160] Draft: Small fix for malfuncioning pivy --- src/Mod/Draft/DraftTools.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index 89cd5df9d..981cbe1c2 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -242,9 +242,12 @@ class DraftTool: self.ui.sourceCmd = self self.ui.setTitle(name) self.ui.show() - rot = self.view.getCameraNode().getField("orientation").getValue() - upv = Vector(rot.multVec(coin.SbVec3f(0,1,0)).getValue()) - plane.setup(DraftVecUtils.neg(self.view.getViewDirection()), Vector(0,0,0), upv) + try: + rot = self.view.getCameraNode().getField("orientation").getValue() + upv = Vector(rot.multVec(coin.SbVec3f(0,1,0)).getValue()) + plane.setup(DraftVecUtils.neg(self.view.getViewDirection()), Vector(0,0,0), upv) + except: + pass self.node = [] self.pos = [] self.constrain = None From ca2cbc3be4af1b3aa3993540e715194e3a8fc034 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 14 Jun 2013 23:09:25 +0200 Subject: [PATCH 091/160] Trick to download files if logged in at SF --- src/Gui/MainWindow.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index 3c003b7ea..10ffda39b 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -1402,6 +1402,7 @@ void MainWindow::dragEnterEvent (QDragEnterEvent * e) // Here we must allow uri drafs and check them in dropEvent const QMimeData* data = e->mimeData(); if (data->hasUrls()) { +#if 0 #ifdef QT_NO_OPENSSL QList urls = data->urls(); for (QList::ConstIterator it = urls.begin(); it != urls.end(); ++it) { @@ -1410,6 +1411,7 @@ void MainWindow::dragEnterEvent (QDragEnterEvent * e) return; } } +#endif #endif e->accept(); } @@ -1559,11 +1561,16 @@ void MainWindow::loadUrls(App::Document* doc, const QList& url) else if (it->scheme().toLower() == QLatin1String("http")) { Gui::Dialog::DownloadManager::getInstance()->download(*it); } -#ifndef QT_NO_OPENSSL +//#ifndef QT_NO_OPENSSL else if (it->scheme().toLower() == QLatin1String("https")) { - Gui::Dialog::DownloadManager::getInstance()->download(*it); + QUrl url = *it; + if (it->hasEncodedQueryItem(QByteArray("sid"))) { + url.removeEncodedQueryItem(QByteArray("sid")); + url.setScheme(QLatin1String("http")); + } + Gui::Dialog::DownloadManager::getInstance()->download(url); } -#endif +//#endif else if (it->scheme().toLower() == QLatin1String("ftp")) { Gui::Dialog::DownloadManager::getInstance()->download(*it); } From 6a9594d4c0a7d00fa946ef7571764cf5c098f325 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 15 Jun 2013 15:32:06 +0200 Subject: [PATCH 092/160] Don't show attribute 'Type' in call tips any more --- src/Base/BaseClassPy.xml | 6 ------ src/Base/BaseClassPyImp.cpp | 16 ++++++++-------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/Base/BaseClassPy.xml b/src/Base/BaseClassPy.xml index 661816822..4d2122047 100644 --- a/src/Base/BaseClassPy.xml +++ b/src/Base/BaseClassPy.xml @@ -24,12 +24,6 @@ Returns all descentences - - - Is the type of the FreeCAD object with module domain (deprecated use TypeId) - - - Is the type of the FreeCAD object with module domain diff --git a/src/Base/BaseClassPyImp.cpp b/src/Base/BaseClassPyImp.cpp index 879123c71..1ff47646c 100644 --- a/src/Base/BaseClassPyImp.cpp +++ b/src/Base/BaseClassPyImp.cpp @@ -68,13 +68,6 @@ PyObject* BaseClassPy::getAllDerivedFrom(PyObject *args) return Py::new_reference_to(res); } -Py::String BaseClassPy::getType(void) const -{ - PyErr_SetString(PyExc_DeprecationWarning, "Use 'TypeId' instead"); - PyErr_Print(); - return Py::String(std::string(getBaseClassPtr()->getTypeId().getName())); -} - Py::String BaseClassPy::getTypeId(void) const { return Py::String(std::string(getBaseClassPtr()->getTypeId().getName())); @@ -85,8 +78,15 @@ Py::Int BaseClassPy::getModule(void) const return Py::Int(); } -PyObject *BaseClassPy::getCustomAttributes(const char* /*attr*/) const +PyObject *BaseClassPy::getCustomAttributes(const char* attr) const { + // this attribute is marked 'deprecated' but to keep old code working we + // handle it here. In a future version this will be removed. + if (strcmp(attr, "Type") == 0) { + PyErr_SetString(PyExc_DeprecationWarning, "Use 'TypeId' instead"); + PyErr_Print(); + return Py::new_reference_to(Py::String(std::string(getBaseClassPtr()->getTypeId().getName()))); + } return 0; } From 31fbfd33ef41dd10111ce8eabf0d4ce8652149d4 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sat, 15 Jun 2013 15:39:29 -0300 Subject: [PATCH 093/160] 0001151: Draft loads Part module at start + Fixed loading of Part module at startup + Minor cleaning around --- src/Mod/Arch/InitGui.py | 37 +++++++++++++++++++--------------- src/Mod/Draft/DraftGui.py | 2 +- src/Mod/Draft/DraftSnap.py | 5 ++--- src/Mod/Draft/DraftTrackers.py | 3 ++- src/Mod/Draft/InitGui.py | 37 ++++++++++++++++++++-------------- src/Mod/Draft/importSVG.py | 3 ++- 6 files changed, 50 insertions(+), 37 deletions(-) diff --git a/src/Mod/Arch/InitGui.py b/src/Mod/Arch/InitGui.py index 7e0cd8361..94f34788a 100644 --- a/src/Mod/Arch/InitGui.py +++ b/src/Mod/Arch/InitGui.py @@ -59,13 +59,14 @@ class ArchWorkbench(Workbench): " *@!!!!!$=* ", " =>!!$& ", " -+ ", - " "};""" + " "};""" MenuText = "Arch" ToolTip = "Architecture workbench" - + def Initialize(self): import DraftTools,DraftGui,Arch_rc,Arch,Draft_rc + from DraftTools import translate # arch tools self.archtools = ["Arch_Wall","Arch_Structure", @@ -91,23 +92,24 @@ class ArchWorkbench(Workbench): "Draft_ShowSnapBar","Draft_ToggleGrid","Draft_UndoLine", "Draft_FinishLine","Draft_CloseLine"] - self.appendToolbar(str(DraftTools.translate("arch","Arch tools")),self.archtools) - self.appendToolbar(str(DraftTools.translate("arch","Draft tools")),self.drafttools) - self.appendToolbar(str(DraftTools.translate("arch","Draft mod tools")),self.draftmodtools) - self.appendMenu([str(DraftTools.translate("arch","&Architecture")),str(DraftTools.translate("arch","Conversion Tools"))],self.meshtools) - self.appendMenu([str(DraftTools.translate("arch","&Architecture")),str(DraftTools.translate("arch","Calculation Tools"))],self.calctools) - self.appendMenu(str(DraftTools.translate("arch","&Architecture")),self.archtools) - self.appendMenu(str(DraftTools.translate("arch","&Draft")),self.drafttools+self.draftmodtools) - self.appendMenu([str(DraftTools.translate("arch","&Draft")),str(DraftTools.translate("arch","Context Tools"))],self.draftcontexttools) + self.appendToolbar(str(translate("arch","Arch tools")),self.archtools) + self.appendToolbar(str(translate("arch","Draft tools")),self.drafttools) + self.appendToolbar(str(translate("arch","Draft mod tools")),self.draftmodtools) + self.appendMenu([str(translate("arch","&Architecture")),str(translate("arch","Conversion Tools"))],self.meshtools) + self.appendMenu([str(translate("arch","&Architecture")),str(translate("arch","Calculation Tools"))],self.calctools) + self.appendMenu(str(translate("arch","&Architecture")),self.archtools) + self.appendMenu(str(translate("arch","&Draft")),self.drafttools+self.draftmodtools) + self.appendMenu([str(translate("arch","&Draft")),str(translate("arch","Context Tools"))],self.draftcontexttools) FreeCADGui.addIconPath(":/icons") FreeCADGui.addLanguagePath(":/translations") FreeCADGui.addPreferencePage(":/ui/archprefs-base.ui","Arch") - if not hasattr(FreeCADGui.draftToolBar,"loadedPreferences"): - FreeCADGui.addPreferencePage(":/ui/userprefs-base.ui","Draft") - FreeCADGui.addPreferencePage(":/ui/userprefs-import.ui","Draft") - FreeCADGui.draftToolBar.loadedPreferences = True + if hasattr(FreeCADGui,"draftToolBar"): + if not hasattr(FreeCADGui.draftToolBar,"loadedPreferences"): + FreeCADGui.addPreferencePage(":/ui/userprefs-base.ui","Draft") + FreeCADGui.addPreferencePage(":/ui/userprefs-import.ui","Draft") + FreeCADGui.draftToolBar.loadedPreferences = True Log ('Loading Arch module... done\n') - + def Activated(self): if hasattr(FreeCADGui,"draftToolBar"): FreeCADGui.draftToolBar.Activated() @@ -121,7 +123,7 @@ class ArchWorkbench(Workbench): if hasattr(FreeCADGui,"Snapper"): FreeCADGui.Snapper.hide() Msg("Arch workbench deactivated\n") - + def ContextMenu(self, recipient): self.appendContextMenu("Draft context tools",self.draftcontexttools) @@ -129,9 +131,12 @@ class ArchWorkbench(Workbench): return "Gui::PythonWorkbench" FreeCADGui.addWorkbench(ArchWorkbench) + +# add import/export types FreeCAD.addImportType("Industry Foundation Classes (*.ifc)","importIFC") FreeCAD.addExportType("Wavefront OBJ - Arch module (*.obj)","importOBJ") FreeCAD.addExportType("WebGL file (*.html)","importWebGL") + # check for pycollada try: import collada diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py index d50773561..1e44d34d0 100644 --- a/src/Mod/Draft/DraftGui.py +++ b/src/Mod/Draft/DraftGui.py @@ -33,7 +33,7 @@ Report to Draft.py for info import FreeCAD, FreeCADGui, os, Draft, sys try: - from PyQt4 import QtCore,QtGui,QtSvg + from PyQt4 import QtCore,QtGui,QtSvg except: FreeCAD.Console.PrintMessage("Error: Python-qt4 package must be installed on your system to use the Draft module.") diff --git a/src/Mod/Draft/DraftSnap.py b/src/Mod/Draft/DraftSnap.py index 9b2d8ad9e..792f1c8be 100644 --- a/src/Mod/Draft/DraftSnap.py +++ b/src/Mod/Draft/DraftSnap.py @@ -27,7 +27,6 @@ __url__ = "http://free-cad.sourceforge.net" import FreeCAD, FreeCADGui, math, Draft, DraftGui, DraftTrackers, DraftVecUtils -from DraftGui import todo,getMainWindow from FreeCAD import Vector from pivy import coin from PyQt4 import QtCore,QtGui @@ -118,7 +117,7 @@ class Snapper: if not hasattr(self,"toolbar"): self.makeSnapToolBar() - mw = getMainWindow() + mw = DraftGui.getMainWindow() bt = mw.findChild(QtGui.QToolBar,"Draft Snap") if not bt: mw.addToolBar(self.toolbar) @@ -929,7 +928,7 @@ class Snapper: "shows the toolbar and the grid" if not hasattr(self,"toolbar"): self.makeSnapToolBar() - mw = getMainWindow() + mw = DraftGui.getMainWindow() bt = mw.findChild(QtGui.QToolBar,"Draft Snap") if not bt: mw.addToolBar(self.toolbar) diff --git a/src/Mod/Draft/DraftTrackers.py b/src/Mod/Draft/DraftTrackers.py index 189819ca4..570883c06 100644 --- a/src/Mod/Draft/DraftTrackers.py +++ b/src/Mod/Draft/DraftTrackers.py @@ -28,7 +28,6 @@ __url__ = "http://free-cad.sourceforge.net" import FreeCAD,FreeCADGui,math,Draft, DraftVecUtils from FreeCAD import Vector from pivy import coin -from DraftGui import todo class Tracker: "A generic Draft Tracker, to be used by other specific trackers" @@ -52,9 +51,11 @@ class Tracker: self.switch.addChild(node) self.switch.whichChild = -1 self.Visible = False + from DraftGui import todo todo.delay(self._insertSwitch, self.switch) def finalize(self): + from DraftGui import todo todo.delay(self._removeSwitch, self.switch) self.switch = None diff --git a/src/Mod/Draft/InitGui.py b/src/Mod/Draft/InitGui.py index 57fbca4db..1b2e7732f 100644 --- a/src/Mod/Draft/InitGui.py +++ b/src/Mod/Draft/InitGui.py @@ -62,8 +62,8 @@ class DraftWorkbench (Workbench): ".&&.++***,,)))!!", "#==+)!!!!!!!!!!!", " ##+)!!!!!!!!!!!", - " *,,,,,,,,,,,,"};""" - + " *,,,,,,,,,,,,"};""" + MenuText = "Draft" ToolTip = "The Draft module is used for basic 2D CAD Drafting" @@ -92,19 +92,18 @@ class DraftWorkbench (Workbench): depsOK = True if not depsOK: return - + + # import Draft tools, icons and macros menu try: - import os,macros,DraftTools,DraftGui,Draft_rc + import os,macros,Draft_rc,DraftTools, DraftGui + from DraftTools import translate FreeCADGui.addLanguagePath(":/translations") FreeCADGui.addIconPath(":/icons") - if not hasattr(FreeCADGui.draftToolBar,"loadedPreferences"): - FreeCADGui.addPreferencePage(":/ui/userprefs-base.ui","Draft") - FreeCADGui.addPreferencePage(":/ui/userprefs-import.ui","Draft") - FreeCADGui.draftToolBar.loadedPreferences = True - self.appendMenu(["&Macro",str(DraftTools.translate("draft","Installed Macros"))],macros.macrosList) - Log ('Loading Draft module...done\n') + self.appendMenu(["&Macro",str(translate("draft","Installed Macros"))],macros.macrosList) except: pass + + # setup menus self.cmdList = ["Draft_Line","Draft_Wire","Draft_Circle","Draft_Arc","Draft_Ellipse", "Draft_Polygon","Draft_Rectangle", "Draft_Text", "Draft_Dimension", "Draft_BSpline","Draft_Point", @@ -120,10 +119,16 @@ class DraftWorkbench (Workbench): self.lineList = ["Draft_UndoLine","Draft_FinishLine","Draft_CloseLine"] self.appendToolbar(QT_TRANSLATE_NOOP("Workbench","Draft creation tools"),self.cmdList) self.appendToolbar(QT_TRANSLATE_NOOP("Workbench","Draft modification tools"),self.modList) - self.appendMenu(str(DraftTools.translate("draft","&Draft")),self.cmdList+self.modList) - self.appendMenu([str(DraftTools.translate("draft","&Draft")),str(DraftTools.translate("draft","Context tools"))],self.treecmdList) - self.appendMenu([str(DraftTools.translate("draft","&Draft")),str(DraftTools.translate("draft","Wire tools"))],self.lineList) - + self.appendMenu(str(translate("draft","&Draft")),self.cmdList+self.modList) + self.appendMenu([str(translate("draft","&Draft")),str(translate("draft","Context tools"))],self.treecmdList) + self.appendMenu([str(translate("draft","&Draft")),str(translate("draft","Wire tools"))],self.lineList) + if hasattr(FreeCADGui,"draftToolBar"): + if not hasattr(FreeCADGui.draftToolBar,"loadedPreferences"): + FreeCADGui.addPreferencePage(":/ui/userprefs-base.ui","Draft") + FreeCADGui.addPreferencePage(":/ui/userprefs-import.ui","Draft") + FreeCADGui.draftToolBar.loadedPreferences = True + Log ('Loading Draft module...done\n') + def Activated(self): if hasattr(FreeCADGui,"draftToolBar"): FreeCADGui.draftToolBar.Activated() @@ -159,6 +164,8 @@ class DraftWorkbench (Workbench): # ability to turn off the Draft workbench (since it is also all included in Arch) if not FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft").GetBool("hideDraftWorkbench"): FreeCADGui.addWorkbench(DraftWorkbench) + +# add Import/Export types App.addImportType("Autodesk DXF (*.dxf)","importDXF") App.addImportType("SVG as geometry (*.svg)","importSVG") App.addImportType("Open CAD Format (*.oca *.gcad)","importOCA") @@ -167,7 +174,7 @@ App.addExportType("Autodesk DXF (*.dxf)","importDXF") App.addExportType("Flattened SVG (*.svg)","importSVG") App.addExportType("Open CAD Format (*.oca)","importOCA") -# DWG support +# add DWG support import importDWG if importDWG.getTeighaConverter(): App.addImportType("Autodesk DWG (*.dwg)","importDWG") diff --git a/src/Mod/Draft/importSVG.py b/src/Mod/Draft/importSVG.py index 3d4b3b55b..4eb5f3752 100644 --- a/src/Mod/Draft/importSVG.py +++ b/src/Mod/Draft/importSVG.py @@ -38,7 +38,7 @@ currently unsupported: use, image # implement inherting fill style from group # handle relative units -import xml.sax, string, FreeCAD, os, math, re, Draft, DraftVecUtils, DraftGeomUtils +import xml.sax, string, FreeCAD, os, math, re, Draft, DraftVecUtils from FreeCAD import Vector try: import FreeCADGui @@ -283,6 +283,7 @@ def makewire(path,checkclosed=False,donttry=False): #ToDo Do not catch all exceptions if not donttry: try: + import DraftGeomUtils sh = Part.Wire(DraftGeomUtils.sortEdges(path)) #sh = Part.Wire(path) isok = (not checkclosed) or sh.isClosed() From 2dce90b9b0ab2a6b2851ee49b4d3a6f916a8d9bb Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 15 Jun 2013 22:26:21 +0200 Subject: [PATCH 094/160] #0001150: Abort on startup --- src/Mod/Part/App/AppPart.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp index b405fc561..2f5c49189 100644 --- a/src/Mod/Part/App/AppPart.cpp +++ b/src/Mod/Part/App/AppPart.cpp @@ -103,9 +103,13 @@ void PartExport initPart() App::GetApplication().addExportType("STEP with colors (*.step *.stp)","ImportGui"); #endif #endif -#if defined(FC_OS_LINUX) - OSD::SetSignal(); -#endif + // This is highly experimental and we should keep an eye on it + // if we have mysterious crashes + // The argument must be 'Standard_False' to avoid FPE caused by + // Python's cmath module. +//#if defined(FC_OS_LINUX) + OSD::SetSignal(Standard_False); +//#endif PyObject* partModule = Py_InitModule3("Part", Part_methods, module_part_doc); /* mod name, table ptr */ Base::Console().Log("Loading Part module... done\n"); From d14d5cb2e44c6b89bc0e2f79af5d443922895059 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 15 Jun 2013 23:07:26 +0200 Subject: [PATCH 095/160] #0001093: Improvements for Brep Inventor nodes (disabled atm) --- src/Mod/Part/Gui/AppPartGui.cpp | 1 + src/Mod/Part/Gui/CMakeLists.txt | 2 + src/Mod/Part/Gui/SoBrepFaceSet.cpp | 987 +++++++++++++++++++++++++++ src/Mod/Part/Gui/SoBrepFaceSet.h | 128 ++++ src/Mod/Part/Gui/ViewProviderExt.cpp | 1 + 5 files changed, 1119 insertions(+) create mode 100644 src/Mod/Part/Gui/SoBrepFaceSet.cpp create mode 100644 src/Mod/Part/Gui/SoBrepFaceSet.h diff --git a/src/Mod/Part/Gui/AppPartGui.cpp b/src/Mod/Part/Gui/AppPartGui.cpp index 889e46fce..8a368bf64 100644 --- a/src/Mod/Part/Gui/AppPartGui.cpp +++ b/src/Mod/Part/Gui/AppPartGui.cpp @@ -25,6 +25,7 @@ #include #include "SoBrepShape.h" +#include "SoBrepFaceSet.h" #include "SoFCShapeObject.h" #include "ViewProvider.h" #include "ViewProviderExt.h" diff --git a/src/Mod/Part/Gui/CMakeLists.txt b/src/Mod/Part/Gui/CMakeLists.txt index 9d9d482eb..c2d457ba2 100644 --- a/src/Mod/Part/Gui/CMakeLists.txt +++ b/src/Mod/Part/Gui/CMakeLists.txt @@ -128,6 +128,8 @@ SET(PartGui_SRCS SoFCShapeObject.h SoBrepShape.cpp SoBrepShape.h + SoBrepFaceSet.cpp + SoBrepFaceSet.h ViewProvider.cpp ViewProvider.h ViewProviderExt.cpp diff --git a/src/Mod/Part/Gui/SoBrepFaceSet.cpp b/src/Mod/Part/Gui/SoBrepFaceSet.cpp new file mode 100644 index 000000000..7818e35ae --- /dev/null +++ b/src/Mod/Part/Gui/SoBrepFaceSet.cpp @@ -0,0 +1,987 @@ +/*************************************************************************** + * Copyright (c) 2011 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., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" +#if 0 +#ifndef _PreComp_ +# ifdef FC_OS_WIN32 +# include +# endif +# ifdef FC_OS_MACOSX +# include +# else +# include +# endif +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include +#include +#include + + +#include "SoBrepFaceSet.h" + + +using namespace PartGui; + + +SO_NODE_SOURCE(SoBrepFaceSet); + +void SoBrepFaceSet::initClass() +{ + SO_NODE_INIT_CLASS(SoBrepFaceSet, SoIndexedFaceSet, "IndexedFaceSet"); +} + +SoBrepFaceSet::SoBrepFaceSet() +{ + SO_NODE_CONSTRUCTOR(SoBrepFaceSet); + SO_NODE_ADD_FIELD(partIndex, (-1)); + SO_NODE_ADD_FIELD(highlightIndex, (-1)); + SO_NODE_ADD_FIELD(selectionIndex, (-1)); + selectionIndex.setNum(0); +} + + +SoBrepFaceSet::~SoBrepFaceSet() +{ +} + + +void SoBrepFaceSet::doAction(SoAction* action) +{ + if (action->getTypeId() == Gui::SoHighlightElementAction::getClassTypeId()) { + Gui::SoHighlightElementAction* hlaction = static_cast(action); + if (!hlaction->isHighlighted()) { + this->highlightIndex = -1; + return; + } + + const SoDetail* detail = hlaction->getElement(); + if (detail) { + if (detail->isOfType(SoFaceDetail::getClassTypeId())) { + int index = static_cast(detail)->getPartIndex(); + this->highlightIndex.setValue(index); + this->highlightColor = hlaction->getColor(); + } + else { + this->highlightIndex = -1; + return; + } + } + } + else if (action->getTypeId() == Gui::SoSelectionElementAction::getClassTypeId()) { + Gui::SoSelectionElementAction* selaction = static_cast(action); + this->selectionColor = selaction->getColor(); + if (selaction->getType() == Gui::SoSelectionElementAction::All) { + int num = this->partIndex.getNum(); + this->selectionIndex.setNum(num); + int32_t* v = this->selectionIndex.startEditing(); + for (int i=0; iselectionIndex.finishEditing(); + return; + } + else if (selaction->getType() == Gui::SoSelectionElementAction::None) { + this->selectionIndex.setNum(0); + return; + } + + const SoDetail* detail = selaction->getElement(); + if (detail) { + if (!detail->isOfType(SoFaceDetail::getClassTypeId())) { + return; + } + + int index = static_cast(detail)->getPartIndex(); + switch (selaction->getType()) { + case Gui::SoSelectionElementAction::Append: + { + int start = this->selectionIndex.getNum(); + this->selectionIndex.set1Value(start, index); + } + break; + case Gui::SoSelectionElementAction::Remove: + { + int start = this->selectionIndex.find(index); + this->selectionIndex.deleteValues(start,1); + } + break; + default: + break; + } + } + } + + inherited::doAction(action); +} + +void SoBrepFaceSet::GLRender(SoGLRenderAction *action) +{ + SoState * state = action->getState(); + + SoMaterialBundle mb(action); + Binding mbind = this->findMaterialBinding(state); + + SoTextureCoordinateBundle tb(action, TRUE, FALSE); + SbBool doTextures = tb.needCoordinates(); + + int32_t hl_idx = this->highlightIndex.getValue(); + int32_t num_selected = this->selectionIndex.getNum(); + + if (this->coordIndex.getNum() < 3) + return; + if (num_selected > 0) + renderSelection(action); + if (hl_idx >= 0) + renderHighlight(action); + + // When setting transparency shouldGLRender() handles the rendering and returns false. + // Therefore generatePrimitives() needs to be re-implemented to handle the materials + // correctly. + if (!this->shouldGLRender(action)) + return; + +#ifdef RENDER_GLARRAYS + if (!doTextures && index_array.size() && hl_idx < 0 && num_selected <= 0) { + if (mbind == 0) { + mb.sendFirst(); // only one material -> apply it! + renderSimpleArray(); + return; + } + else if (mbind == 1) { + renderColoredArray(&mb); + return; + } + } +#endif + + Binding nbind = this->findNormalBinding(state); + + const SoCoordinateElement * coords; + const SbVec3f * normals; + const int32_t * cindices; + int numindices; + const int32_t * nindices; + const int32_t * tindices; + const int32_t * mindices; + const int32_t * pindices; + int numparts; + SbBool normalCacheUsed; + + SbBool sendNormals = !mb.isColorOnly() || tb.isFunction(); + + this->getVertexData(state, coords, normals, cindices, + nindices, tindices, mindices, numindices, + sendNormals, normalCacheUsed); + + mb.sendFirst(); // make sure we have the correct material + + // just in case someone forgot + if (!mindices) mindices = cindices; + if (!nindices) nindices = cindices; + pindices = this->partIndex.getValues(0); + numparts = this->partIndex.getNum(); + + renderShape(static_cast(coords), cindices, numindices, + pindices, numparts, normals, nindices, &mb, mindices, &tb, tindices, nbind, mbind, doTextures?1:0); + + // Disable caching for this node + SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DONT_AUTO_CACHE); + + // Workaround for #0000433 +//#if !defined(FC_OS_WIN32) + if (hl_idx >= 0) + renderHighlight(action); + if (num_selected > 0) + renderSelection(action); +//#endif +} + +void SoBrepFaceSet::GLRenderBelowPath(SoGLRenderAction * action) +{ + inherited::GLRenderBelowPath(action); +} + + // this macro actually makes the code below more readable :-) +#define DO_VERTEX(idx) \ + if (mbind == PER_VERTEX) { \ + pointDetail.setMaterialIndex(matnr); \ + vertex.setMaterialIndex(matnr++); \ + } \ + else if (mbind == PER_VERTEX_INDEXED) { \ + pointDetail.setMaterialIndex(*mindices); \ + vertex.setMaterialIndex(*mindices++); \ + } \ + if (nbind == PER_VERTEX) { \ + pointDetail.setNormalIndex(normnr); \ + currnormal = &normals[normnr++]; \ + vertex.setNormal(*currnormal); \ + } \ + else if (nbind == PER_VERTEX_INDEXED) { \ + pointDetail.setNormalIndex(*nindices); \ + currnormal = &normals[*nindices++]; \ + vertex.setNormal(*currnormal); \ + } \ + if (tb.isFunction()) { \ + vertex.setTextureCoords(tb.get(coords->get3(idx), *currnormal)); \ + if (tb.needIndices()) pointDetail.setTextureCoordIndex(tindices ? *tindices++ : texidx++); \ + } \ + else if (tbind != NONE) { \ + pointDetail.setTextureCoordIndex(tindices ? *tindices : texidx); \ + vertex.setTextureCoords(tb.get(tindices ? *tindices++ : texidx++)); \ + } \ + vertex.setPoint(coords->get3(idx)); \ + pointDetail.setCoordinateIndex(idx); \ + this->shapeVertex(&vertex); + +void SoBrepFaceSet::generatePrimitives(SoAction * action) +{ + //TODO +#if 0 + inherited::generatePrimitives(action); +#else + //This is highly experimental!!! + + if (this->coordIndex.getNum() < 3) return; + + SoState * state = action->getState(); + + if (this->vertexProperty.getValue()) { + state->push(); + this->vertexProperty.getValue()->doAction(action); + } + + Binding mbind = this->findMaterialBinding(state); + Binding nbind = this->findNormalBinding(state); + + const SoCoordinateElement * coords; + const SbVec3f * normals; + const int32_t * cindices; + int numindices; + const int32_t * nindices; + const int32_t * tindices; + const int32_t * mindices; + SbBool doTextures; + SbBool sendNormals; + SbBool normalCacheUsed; + + sendNormals = TRUE; // always generate normals + + this->getVertexData(state, coords, normals, cindices, + nindices, tindices, mindices, numindices, + sendNormals, normalCacheUsed); + + SoTextureCoordinateBundle tb(action, FALSE, FALSE); + doTextures = tb.needCoordinates(); + + if (!sendNormals) nbind = OVERALL; + else if (normalCacheUsed && nbind == PER_VERTEX) { + nbind = PER_VERTEX_INDEXED; + } + else if (normalCacheUsed && nbind == PER_FACE_INDEXED) { + nbind = PER_FACE; + } + + if (this->getNodeType() == SoNode::VRML1) { + // For VRML1, PER_VERTEX means per vertex in shape, not PER_VERTEX + // on the state. + if (mbind == PER_VERTEX) { + mbind = PER_VERTEX_INDEXED; + mindices = cindices; + } + if (nbind == PER_VERTEX) { + nbind = PER_VERTEX_INDEXED; + nindices = cindices; + } + } + + Binding tbind = NONE; + if (doTextures) { + if (tb.isFunction() && !tb.needIndices()) { + tbind = NONE; + tindices = NULL; + } + // FIXME: just call inherited::areTexCoordsIndexed() instead of + // the if-check? 20020110 mortene. + else if (SoTextureCoordinateBindingElement::get(state) == + SoTextureCoordinateBindingElement::PER_VERTEX) { + tbind = PER_VERTEX; + tindices = NULL; + } + else { + tbind = PER_VERTEX_INDEXED; + if (tindices == NULL) tindices = cindices; + } + } + + if (nbind == PER_VERTEX_INDEXED && nindices == NULL) { + nindices = cindices; + } + if (mbind == PER_VERTEX_INDEXED && mindices == NULL) { + mindices = cindices; + } + + int texidx = 0; + TriangleShape mode = POLYGON; + TriangleShape newmode; + const int32_t *viptr = cindices; + const int32_t *viendptr = viptr + numindices; + const int32_t *piptr = this->partIndex.getValues(0); + int num_partindices = this->partIndex.getNum(); + const int32_t *piendptr = piptr + num_partindices; + int32_t v1, v2, v3, v4, v5 = 0, pi; // v5 init unnecessary, but kills a compiler warning. + + SoPrimitiveVertex vertex; + SoPointDetail pointDetail; + SoFaceDetail faceDetail; + + vertex.setDetail(&pointDetail); + + SbVec3f dummynormal(0,0,1); + const SbVec3f *currnormal = &dummynormal; + if (normals) currnormal = normals; + vertex.setNormal(*currnormal); + + int matnr = 0; + int normnr = 0; + int trinr = 0; + pi = piptr < piendptr ? *piptr++ : -1; + while (pi == 0) { + // It may happen that a part has no triangles + pi = piptr < piendptr ? *piptr++ : -1; + if (mbind == PER_PART) + matnr++; + else if (mbind == PER_PART_INDEXED) + mindices++; + } + + while (viptr + 2 < viendptr) { + v1 = *viptr++; + v2 = *viptr++; + v3 = *viptr++; + if (v1 < 0 || v2 < 0 || v3 < 0) { + break; + } + v4 = viptr < viendptr ? *viptr++ : -1; + if (v4 < 0) newmode = TRIANGLES; + else { + v5 = viptr < viendptr ? *viptr++ : -1; + if (v5 < 0) newmode = QUADS; + else newmode = POLYGON; + } + if (newmode != mode) { + if (mode != POLYGON) this->endShape(); + mode = newmode; + this->beginShape(action, mode, &faceDetail); + } + else if (mode == POLYGON) this->beginShape(action, POLYGON, &faceDetail); + + // vertex 1 can't use DO_VERTEX + if (mbind == PER_PART) { + if (trinr == 0) { + pointDetail.setMaterialIndex(matnr); + vertex.setMaterialIndex(matnr++); + } + } + else if (mbind == PER_PART_INDEXED) { + if (trinr == 0) { + pointDetail.setMaterialIndex(*mindices); + vertex.setMaterialIndex(*mindices++); + } + } + else if (mbind == PER_VERTEX || mbind == PER_FACE) { + pointDetail.setMaterialIndex(matnr); + vertex.setMaterialIndex(matnr++); + } + else if (mbind == PER_VERTEX_INDEXED || mbind == PER_FACE_INDEXED) { + pointDetail.setMaterialIndex(*mindices); + vertex.setMaterialIndex(*mindices++); + } + if (nbind == PER_VERTEX || nbind == PER_FACE) { + pointDetail.setNormalIndex(normnr); + currnormal = &normals[normnr++]; + vertex.setNormal(*currnormal); + } + else if (nbind == PER_FACE_INDEXED || nbind == PER_VERTEX_INDEXED) { + pointDetail.setNormalIndex(*nindices); + currnormal = &normals[*nindices++]; + vertex.setNormal(*currnormal); + } + + if (tb.isFunction()) { + vertex.setTextureCoords(tb.get(coords->get3(v1), *currnormal)); + if (tb.needIndices()) pointDetail.setTextureCoordIndex(tindices ? *tindices++ : texidx++); + } + else if (tbind != NONE) { + pointDetail.setTextureCoordIndex(tindices ? *tindices : texidx); + vertex.setTextureCoords(tb.get(tindices ? *tindices++ : texidx++)); + } + pointDetail.setCoordinateIndex(v1); + vertex.setPoint(coords->get3(v1)); + this->shapeVertex(&vertex); + + DO_VERTEX(v2); + DO_VERTEX(v3); + + if (mode != TRIANGLES) { + DO_VERTEX(v4); + if (mode == POLYGON) { + DO_VERTEX(v5); + v1 = viptr < viendptr ? *viptr++ : -1; + while (v1 >= 0) { + DO_VERTEX(v1); + v1 = viptr < viendptr ? *viptr++ : -1; + } + this->endShape(); + } + } + faceDetail.incFaceIndex(); + if (mbind == PER_VERTEX_INDEXED) { + mindices++; + } + if (nbind == PER_VERTEX_INDEXED) { + nindices++; + } + if (tindices) tindices++; + + trinr++; + if (pi == trinr) { + pi = piptr < piendptr ? *piptr++ : -1; + while (pi == 0) { + // It may happen that a part has no triangles + pi = piptr < piendptr ? *piptr++ : -1; + if (mbind == PER_PART) + matnr++; + else if (mbind == PER_PART_INDEXED) + mindices++; + } + trinr = 0; + } + } + if (mode != POLYGON) this->endShape(); + + if (normalCacheUsed) { + this->readUnlockNormalCache(); + } + + if (this->vertexProperty.getValue()) { + state->pop(); + } +#endif +} + +#undef DO_VERTEX + +void SoBrepFaceSet::renderHighlight(SoGLRenderAction *action) +{ + SoState * state = action->getState(); + state->push(); + + SoLazyElement::setEmissive(state, &this->highlightColor); + SoOverrideElement::setEmissiveColorOverride(state, this, TRUE); +#if 0 // disables shading effect + // sendNormals will be FALSE + SoLazyElement::setDiffuse(state, this,1, &this->highlightColor,&this->colorpacker); + SoOverrideElement::setDiffuseColorOverride(state, this, TRUE); + SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR); +#endif + + Binding mbind = this->findMaterialBinding(state); + Binding nbind = this->findNormalBinding(state); + + const SoCoordinateElement * coords; + const SbVec3f * normals; + const int32_t * cindices; + int numindices; + const int32_t * nindices; + const int32_t * tindices; + const int32_t * mindices; + const int32_t * pindices; + SbBool doTextures; + SbBool normalCacheUsed; + + SoMaterialBundle mb(action); + SoTextureCoordinateBundle tb(action, TRUE, FALSE); + doTextures = tb.needCoordinates(); + SbBool sendNormals = !mb.isColorOnly() || tb.isFunction(); + + this->getVertexData(state, coords, normals, cindices, + nindices, tindices, mindices, numindices, + sendNormals, normalCacheUsed); + + mb.sendFirst(); // make sure we have the correct material + + int32_t id = this->highlightIndex.getValue(); + + // just in case someone forgot + if (!mindices) mindices = cindices; + if (!nindices) nindices = cindices; + pindices = this->partIndex.getValues(0); + + // coords + int length = (int)pindices[id]*4; + int start=0; + for (int i=0;i(coords), &(cindices[start]), length, + &(pindices[id]), 1, normals, nindices, &mb, mindices, &tb, tindices, nbind, mbind, doTextures?1:0); + state->pop(); +} + +void SoBrepFaceSet::renderSelection(SoGLRenderAction *action) +{ + int numSelected = this->selectionIndex.getNum(); + const int32_t* selected = this->selectionIndex.getValues(0); + if (numSelected == 0) return; + + SoState * state = action->getState(); + state->push(); + + SoLazyElement::setEmissive(state, &this->selectionColor); + SoOverrideElement::setEmissiveColorOverride(state, this, TRUE); +#if 0 // disables shading effect + SoLazyElement::setDiffuse(state, this,1, &this->selectionColor,&this->colorpacker); + SoOverrideElement::setDiffuseColorOverride(state, this, TRUE); + SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR); +#endif + + Binding mbind = this->findMaterialBinding(state); + Binding nbind = this->findNormalBinding(state); + + const SoCoordinateElement * coords; + const SbVec3f * normals; + const int32_t * cindices; + int numindices; + const int32_t * nindices; + const int32_t * tindices; + const int32_t * mindices; + const int32_t * pindices; + SbBool doTextures; + SbBool normalCacheUsed; + + SoMaterialBundle mb(action); + SoTextureCoordinateBundle tb(action, TRUE, FALSE); + doTextures = tb.needCoordinates(); + SbBool sendNormals = !mb.isColorOnly() || tb.isFunction(); + + this->getVertexData(state, coords, normals, cindices, + nindices, tindices, mindices, numindices, + sendNormals, normalCacheUsed); + + mb.sendFirst(); // make sure we have the correct material + + // just in case someone forgot + if (!mindices) mindices = cindices; + if (!nindices) nindices = cindices; + pindices = this->partIndex.getValues(0); + + // materials + mbind = OVERALL; + doTextures = FALSE; + + for (int i=0; i(coords), &(cindices[start]), length, + &(pindices[id]), 1, normals_s, nindices_s, &mb, mindices, &tb, tindices, nbind, mbind, doTextures?1:0); + } + state->pop(); +} + + +SoDetail * SoBrepFaceSet::createTriangleDetail(SoRayPickAction * action, + const SoPrimitiveVertex * v1, + const SoPrimitiveVertex * v2, + const SoPrimitiveVertex * v3, + SoPickedPoint * pp) +{ + SoDetail* detail = inherited::createTriangleDetail(action, v1, v2, v3, pp); + const int32_t * indices = this->partIndex.getValues(0); + int num = this->partIndex.getNum(); + if (indices) { + SoFaceDetail* face_detail = static_cast(detail); + int index = face_detail->getFaceIndex(); + int count = 0; + for (int i=0; isetPartIndex(i); + break; + } + } + } + return detail; +} + +SoBrepFaceSet::Binding +SoBrepFaceSet::findMaterialBinding(SoState * const state) const +{ + Binding binding = OVERALL; + SoMaterialBindingElement::Binding matbind = + SoMaterialBindingElement::get(state); + + switch (matbind) { + case SoMaterialBindingElement::OVERALL: + binding = OVERALL; + break; + case SoMaterialBindingElement::PER_VERTEX: + binding = PER_VERTEX; + break; + case SoMaterialBindingElement::PER_VERTEX_INDEXED: + binding = PER_VERTEX_INDEXED; + break; + case SoMaterialBindingElement::PER_PART: + binding = PER_PART; + break; + case SoMaterialBindingElement::PER_FACE: + binding = PER_FACE; + break; + case SoMaterialBindingElement::PER_PART_INDEXED: + binding = PER_PART_INDEXED; + break; + case SoMaterialBindingElement::PER_FACE_INDEXED: + binding = PER_FACE_INDEXED; + break; + default: + break; + } + return binding; +} + +SoBrepFaceSet::Binding +SoBrepFaceSet::findNormalBinding(SoState * const state) const +{ + Binding binding = PER_VERTEX_INDEXED; + SoNormalBindingElement::Binding normbind = + (SoNormalBindingElement::Binding) SoNormalBindingElement::get(state); + + switch (normbind) { + case SoNormalBindingElement::OVERALL: + binding = OVERALL; + break; + case SoNormalBindingElement::PER_VERTEX: + binding = PER_VERTEX; + break; + case SoNormalBindingElement::PER_VERTEX_INDEXED: + binding = PER_VERTEX_INDEXED; + break; + case SoNormalBindingElement::PER_PART: + binding = PER_PART; + break; + case SoNormalBindingElement::PER_FACE: + binding = PER_FACE; + break; + case SoNormalBindingElement::PER_PART_INDEXED: + binding = PER_PART_INDEXED; + break; + case SoNormalBindingElement::PER_FACE_INDEXED: + binding = PER_FACE_INDEXED; + break; + default: + break; + } + return binding; +} + + +//**************************************************************************** +// renderShape: fallback rendering: one vertex at a time +// +void SoBrepFaceSet::renderShape(const SoGLCoordinateElement * const vertexlist, + const int32_t *vertexindices, + int num_indices, + const int32_t *partindices, + int num_partindices, + const SbVec3f *normals, + const int32_t *normalindices, + SoMaterialBundle *const materials, + const int32_t *matindices, + SoTextureCoordinateBundle * const texcoords, + const int32_t *texindices, + const int nbind, + const int mbind, + const int texture) +{ + int texidx = 0; + + const SbVec3f * coords3d = NULL; + coords3d = vertexlist->getArrayPtr3(); + + const int32_t *viptr = vertexindices; + const int32_t *viendptr = viptr + num_indices; + const int32_t *piptr = partindices; + const int32_t *piendptr = piptr + num_partindices; + int32_t v1, v2, v3, v4, pi; + SbVec3f dummynormal(0,0,1); + int numverts = vertexlist->getNum(); + + const SbVec3f *currnormal = &dummynormal; + if (normals) currnormal = normals; + + int matnr = 0; + int trinr = 0; + pi = piptr < piendptr ? *piptr++ : -1; + while (pi == 0) { + // It may happen that a part has no triangles + pi = piptr < piendptr ? *piptr++ : -1; + if (mbind == PER_PART) + matnr++; + else if (mbind == PER_PART_INDEXED) + matindices++; + } + + glBegin(GL_TRIANGLES); + while (viptr + 2 < viendptr) { + v1 = *viptr++; + v2 = *viptr++; + v3 = *viptr++; + + // This test is for robustness upon buggy data sets + if (v1 < 0 || v2 < 0 || v3 < 0 || + v1 >= numverts || v2 >= numverts || v3 >= numverts) { + break; + } + v4 = viptr < viendptr ? *viptr++ : -1; + + /* vertex 1 *********************************************************/ + if (mbind == PER_PART) { + if (trinr == 0) + materials->send(matnr++, TRUE); + } + else if (mbind == PER_PART_INDEXED) { + if (trinr == 0) + materials->send(*matindices++, TRUE); + } + else if (mbind == PER_VERTEX || mbind == PER_FACE) { + materials->send(matnr++, TRUE); + } + else if (mbind == PER_VERTEX_INDEXED || mbind == PER_FACE_INDEXED) { + materials->send(*matindices++, TRUE); + } + + if (normals) { + if (nbind == PER_VERTEX || nbind == PER_FACE) { + currnormal = normals++; + glNormal3fv((const GLfloat*)currnormal); + } + else if (nbind == PER_VERTEX_INDEXED || nbind == PER_FACE_INDEXED) { + currnormal = &normals[*normalindices++]; + glNormal3fv((const GLfloat*)currnormal); + } + } + + if (texture) { + texcoords->send(texindices ? *texindices++ : texidx++, + vertexlist->get3(v1), + *currnormal); + } + + glVertex3fv((const GLfloat*) (coords3d + v1)); + + /* vertex 2 *********************************************************/ + if (mbind == PER_VERTEX) + materials->send(matnr++, TRUE); + else if (mbind == PER_VERTEX_INDEXED) + materials->send(*matindices++, TRUE); + + if (normals) { + if (nbind == PER_VERTEX) { + currnormal = normals++; + glNormal3fv((const GLfloat*)currnormal); + } + else if (nbind == PER_VERTEX_INDEXED) { + currnormal = &normals[*normalindices++]; + glNormal3fv((const GLfloat*)currnormal); + } + } + + if (texture) { + texcoords->send(texindices ? *texindices++ : texidx++, + vertexlist->get3(v2), + *currnormal); + } + + glVertex3fv((const GLfloat*) (coords3d + v2)); + + /* vertex 3 *********************************************************/ + if (mbind == PER_VERTEX) + materials->send(matnr++, TRUE); + else if (mbind == PER_VERTEX_INDEXED) + materials->send(*matindices++, TRUE); + + if (normals) { + if (nbind == PER_VERTEX) { + currnormal = normals++; + glNormal3fv((const GLfloat*)currnormal); + } + else if (nbind == PER_VERTEX_INDEXED) { + currnormal = &normals[*normalindices++]; + glNormal3fv((const GLfloat*)currnormal); + } + } + + if (texture) { + texcoords->send(texindices ? *texindices++ : texidx++, + vertexlist->get3(v3), + *currnormal); + } + + glVertex3fv((const GLfloat*) (coords3d + v3)); + + if (mbind == PER_VERTEX_INDEXED) + matindices++; + + if (nbind == PER_VERTEX_INDEXED) + normalindices++; + + if (texture && texindices) { + texindices++; + } + + trinr++; + if (pi == trinr) { + pi = piptr < piendptr ? *piptr++ : -1; + while (pi == 0) { + // It may happen that a part has no triangles + pi = piptr < piendptr ? *piptr++ : -1; + if (mbind == PER_PART) + matnr++; + else if (mbind == PER_PART_INDEXED) + matindices++; + } + trinr = 0; + } + } + glEnd(); +} + + +#ifdef RENDER_GLARRAYS +//**************************************************************************** +// renderSimpleArray: normal and coord from vertex_array; +// no texture, color, highlight or selection but highet possible speed; +// all vertices written in one go! +// +void SoBrepFaceSet::renderSimpleArray() +{ + int cnt = index_array.size(); + + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + + glInterleavedArrays(GL_N3F_V3F, 0, vertex_array.data()); + glDrawElements(GL_TRIANGLES, cnt, GL_UNSIGNED_INT, index_array.data()); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); +} +#endif + + +#ifdef RENDER_GLARRAYS +//**************************************************************************** +// renderColoredArray: normal and coord from vertex_array; +// no texture, highlight or selection but color / material array. +// needs to iterate over parts (i.e. geometry faces) +// +void SoBrepFaceSet::renderColoredArray(SoMaterialBundle *const materials) +{ + int num_parts = partIndex.getNum(); + int cnt = index_array.size(); + + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + + glInterleavedArrays(GL_N3F_V3F, 0, vertex_array.data()); + const int32_t* ptr = index_array.data(); + + for (int part_id = 0; part_id < num_parts; part_id++) { + int tris = partIndex[part_id]; + + if (tris > 0) { + materials->send(part_id, TRUE); + glDrawElements(GL_TRIANGLES, 3 * tris, GL_UNSIGNED_INT, ptr); + ptr += 3 * tris; + } + } + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); +} +#endif + +#endif + diff --git a/src/Mod/Part/Gui/SoBrepFaceSet.h b/src/Mod/Part/Gui/SoBrepFaceSet.h new file mode 100644 index 000000000..9259601a0 --- /dev/null +++ b/src/Mod/Part/Gui/SoBrepFaceSet.h @@ -0,0 +1,128 @@ +/*************************************************************************** + * Copyright (c) 2011 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., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef PARTGUI_SOBREPFACESET_H +#define PARTGUI_SOBREPFACESET_H +#if 0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class SoGLCoordinateElement; +class SoTextureCoordinateBundle; + + +#define RENDER_GLARRAYS + +namespace PartGui { + +class VertexArray; + + +class PartGuiExport SoBrepFaceSet : public SoIndexedFaceSet { + typedef SoIndexedFaceSet inherited; + + SO_NODE_HEADER(SoBrepFaceSet); + +public: + static void initClass(); + SoBrepFaceSet(); + + SoMFInt32 partIndex; + SoSFInt32 highlightIndex; + SoMFInt32 selectionIndex; + +#ifdef RENDER_GLARRAYS + std::vector index_array; + std::vector vertex_array; +#endif + + enum Binding { + OVERALL = 0, + PER_PART, + PER_PART_INDEXED, + PER_FACE, + PER_FACE_INDEXED, + PER_VERTEX, + PER_VERTEX_INDEXED, + NONE = OVERALL + }; + +protected: + virtual ~SoBrepFaceSet(); + virtual void GLRender(SoGLRenderAction *action); + virtual void GLRenderBelowPath(SoGLRenderAction * action); + virtual void doAction(SoAction* action); + virtual SoDetail * createTriangleDetail( + SoRayPickAction * action, + const SoPrimitiveVertex * v1, + const SoPrimitiveVertex * v2, + const SoPrimitiveVertex * v3, + SoPickedPoint * pp); + virtual void generatePrimitives(SoAction * action); + +private: + Binding findMaterialBinding(SoState * const state) const; + Binding findNormalBinding(SoState * const state) const; + void renderHighlight(SoGLRenderAction *action); + void renderSelection(SoGLRenderAction *action); + + + // low-level render functions + + void renderShape(const SoGLCoordinateElement * const vertexlist, + const int32_t *vertexindices, + int num_vertexindices, + const int32_t *partindices, + int num_partindices, + const SbVec3f *normals, + const int32_t *normindices, + SoMaterialBundle *const materials, + const int32_t *matindices, + SoTextureCoordinateBundle * const texcoords, + const int32_t *texindices, + const int nbind, + const int mbind, + const int texture); + +#ifdef RENDER_GLARRAYS + void renderSimpleArray(); + void renderColoredArray(SoMaterialBundle *const materials); +#endif + +private: + SbColor selectionColor; + SbColor highlightColor; + SoColorPacker colorpacker; +}; + +} // namespace PartGui +#endif +#endif // PARTGUI_SOBREPFACESET_H + diff --git a/src/Mod/Part/Gui/ViewProviderExt.cpp b/src/Mod/Part/Gui/ViewProviderExt.cpp index 7dc155b08..cf35e4a14 100644 --- a/src/Mod/Part/Gui/ViewProviderExt.cpp +++ b/src/Mod/Part/Gui/ViewProviderExt.cpp @@ -102,6 +102,7 @@ #include "ViewProviderExt.h" #include "SoBrepShape.h" +#include "SoBrepFaceSet.h" #include "TaskFaceColors.h" #include From a63e18f170a3edb32f830c443619cb00e727e63c Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sun, 16 Jun 2013 14:13:20 -0300 Subject: [PATCH 096/160] Arch: Added preliminary dimensions tracking to walls --- src/Mod/Draft/DraftSnap.py | 55 ++++++++++++++++++++++++++++++---- src/Mod/Draft/DraftTrackers.py | 48 +++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 5 deletions(-) diff --git a/src/Mod/Draft/DraftSnap.py b/src/Mod/Draft/DraftSnap.py index 792f1c8be..24d6cdb08 100644 --- a/src/Mod/Draft/DraftSnap.py +++ b/src/Mod/Draft/DraftSnap.py @@ -71,11 +71,15 @@ class Snapper: self.constrainLine = None self.trackLine = None self.radiusTracker = None + self.dim1 = None + self.dim2 = None self.snapInfo = None self.lastSnappedObject = None + self.lastArchPoint = None self.active = True self.forceGridOff = False - self.trackers = [[],[],[],[],[]] # view, grid, snap, extline, radius + # the trackers are stored in lists because there can be several views, each with its own set + self.trackers = [[],[],[],[],[],[],[]] # view, grid, snap, extline, radius, dim1, dim2 self.polarAngles = [90,45] @@ -85,9 +89,9 @@ class Snapper: 'parallel':'circle', 'grid':'circle', 'endpoint':'dot', - 'midpoint':'dot', + 'midpoint':'square', 'perpendicular':'dot', - 'angle':'dot', + 'angle':'square', 'center':'dot', 'ortho':'dot', 'intersection':'dot'} @@ -172,6 +176,10 @@ class Snapper: self.extLine.off() if self.trackLine: self.trackLine.off() + if self.dim1: + self.dim1.off() + if self.dim2: + self.dim2.off() point = self.getApparentPoint(screenpos[0],screenpos[1]) @@ -199,6 +207,9 @@ class Snapper: if self.trackLine and lastpoint and (not noTracker): self.trackLine.p2(fp) self.trackLine.on() + # set the arch point tracking + if self.lastArchPoint: + self.setArchDims(self.lastArchPoint,fp) return fp else: @@ -242,7 +253,7 @@ class Snapper: snaps.extend(self.snapToPerpendicular(edge,lastpoint)) snaps.extend(self.snapToIntersection(edge)) snaps.extend(self.snapToElines(edge,eline)) - + elif obj.isDerivedFrom("Part::Feature"): if (not self.maxEdges) or (len(obj.Edges) <= self.maxEdges): if "Edge" in comp: @@ -326,7 +337,16 @@ class Snapper: self.trackLine.on() # set the cursor self.setCursor(winner[1]) - + + # set the arch point tracking + if self.lastArchPoint: + self.setArchDims(self.lastArchPoint,fp) + if Draft.getType(obj) == "Wall": + if self.lastArchPoint != fp: + self.lastArchPoint = fp + else: + self.lastArchPoint = None + # return the final point return fp @@ -643,6 +663,21 @@ class Snapper: nv = DraftVecUtils.project(dv,DraftGeomUtils.vec(edge)) np = (edge.Vertexes[0].Point).add(nv) return np + + def setArchDims(self,p1,p2): + "show arch dimensions between 2 points" + if not self.dim1: + self.dim1 = DraftTrackers.archDimTracker(mode=2) + if not self.dim2: + self.dim1 = DraftTrackers.archDimTracker(mode=3) + self.dim1.p1(p1) + self.dim2.p1(p1) + self.dim1.p2(p2) + self.dim2.p2(p2) + if self.dim1.Distance: + self.dim1.on() + if self.dim2.Distance: + self.dim2.on() def setCursor(self,mode=None): "setCursor(self,mode=None): sets or resets the cursor to the given mode or resets" @@ -686,6 +721,10 @@ class Snapper: self.extLine.off() if self.radiusTracker: self.radiusTracker.off() + if self.dim1: + self.dim1.off() + if self.dim2: + self.dim2.off() if self.grid: if not Draft.getParam("alwaysShowGrid"): self.grid.off() @@ -958,6 +997,8 @@ class Snapper: self.tracker = self.trackers[2][i] self.extLine = self.trackers[3][i] self.radiusTracker = self.trackers[4][i] + self.dim1 = self.trackers[5][i] + self.dim2 = self.trackers[6][i] else: if Draft.getParam("grid"): self.grid = DraftTrackers.gridTracker() @@ -966,11 +1007,15 @@ class Snapper: self.tracker = DraftTrackers.snapTracker() self.extLine = DraftTrackers.lineTracker(dotted=True) self.radiusTracker = DraftTrackers.radiusTracker() + self.dim1 = DraftTrackers.archDimTracker(mode=2) + self.dim2 = DraftTrackers.archDimTracker(mode=3) self.trackers[0].append(v) self.trackers[1].append(self.grid) self.trackers[2].append(self.tracker) self.trackers[3].append(self.extLine) self.trackers[4].append(self.radiusTracker) + self.trackers[5].append(self.dim1) + self.trackers[6].append(self.dim2) if self.grid and (not self.forceGridOff): self.grid.set() diff --git a/src/Mod/Draft/DraftTrackers.py b/src/Mod/Draft/DraftTrackers.py index 570883c06..89b4d9935 100644 --- a/src/Mod/Draft/DraftTrackers.py +++ b/src/Mod/Draft/DraftTrackers.py @@ -784,3 +784,51 @@ class radiusTracker(Tracker): self.trans.translation.setValue([arg2.x,arg2.y,arg2.z]) else: self.sphere.radius.setValue(arg2) + +class archDimTracker(Tracker): + "A wrapper around a Sketcher dim" + def __init__(self,p1=FreeCAD.Vector(0,0,0),p2=FreeCAD.Vector(1,0,0),mode=1): + import SketcherGui + self.dimnode = coin.SoType.fromName("SoDatumLabel").createInstance() + p1node = coin.SbVec3f([p1.x,p1.y,p1.z]) + p2node = coin.SbVec3f([p2.x,p2.y,p2.z]) + self.dimnode.pnts.setValues([p1node,p2node]) + self.dimnode.lineWidth = 1 + color = FreeCADGui.draftToolBar.getDefaultColor("snap") + self.dimnode.textColor.setValue(coin.SbVec3f(color)) + self.setString() + self.setMode(mode) + Tracker.__init__(self,children=[self.dimnode]) + + def setString(self,text=None): + "sets the dim string to the given value or auto value" + self.dimnode.param1.setValue(.5) + p1 = Vector(self.dimnode.pnts.getValues()[0].getValue()) + p2 = Vector(self.dimnode.pnts.getValues()[-1].getValue()) + self.Distance = p2.sub(p1).Length + if not text: + text = Draft.getParam("dimPrecision") + text = "%."+str(text)+"f" + text = (text % self.Distance) + self.dimnode.string.setValue(text) + + def setMode(self,mode=1): + """sets the mode: 0 = without lines (a simple mark), 1 = + aligned (default), 2 = horizontal, 3 = vertical.""" + self.dimnode.datumtype.setValue(mode) + + def p1(self,point=None): + "sets or gets the first point of the dim" + if point: + self.dimnode.pnts.set1Value(0,point.x,point.y,point.z) + self.setString() + else: + return Vector(self.dimnode.pnts.getValues()[0].getValue()) + + def p2(self,point=None): + "sets or gets the second point of the dim" + if point: + self.dimnode.pnts.set1Value(1,point.x,point.y,point.z) + self.setString() + else: + return Vector(self.dimnode.pnts.getValues()[-1].getValue()) From d26ffbe9aa1ccf17b964b646ee2f70124b71300e Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sun, 16 Jun 2013 20:06:14 -0300 Subject: [PATCH 097/160] Arch: misc improvements + Further work on snap tracking dims + Better snap for structures + Corrected initial temp shape of structures + Added a box with wall length (still readonly) --- src/Mod/Arch/ArchStructure.py | 3 +++ src/Mod/Arch/ArchWall.py | 16 ++++++++++++++++ src/Mod/Draft/DraftSnap.py | 20 +++++++++++++++++--- src/Mod/Draft/DraftTrackers.py | 8 +++++++- 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/Mod/Arch/ArchStructure.py b/src/Mod/Arch/ArchStructure.py index 14a9a3f80..379730903 100644 --- a/src/Mod/Arch/ArchStructure.py +++ b/src/Mod/Arch/ArchStructure.py @@ -97,6 +97,9 @@ class _CommandStructure: import DraftTrackers self.points = [] self.tracker = DraftTrackers.boxTracker() + self.tracker.width(self.Width) + self.tracker.height(self.Height) + self.tracker.length(self.Length) self.tracker.on() FreeCADGui.Snapper.getPoint(callback=self.getPoint,movecallback=self.update,extradlg=self.taskbox()) diff --git a/src/Mod/Arch/ArchWall.py b/src/Mod/Arch/ArchWall.py index 91d3f26f6..9fd625b82 100644 --- a/src/Mod/Arch/ArchWall.py +++ b/src/Mod/Arch/ArchWall.py @@ -136,6 +136,7 @@ class _CommandWall: self.Width = 0.1 self.Height = 1 self.Align = "Center" + self.Length = None self.continueCmd = False p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") self.JOIN_WALLS = p.GetBool("joinWallSketches") @@ -223,12 +224,24 @@ class _CommandWall: else: dv = DraftVecUtils.neg(dv) self.tracker.update([b.add(dv),point.add(dv)]) + if self.Length: + self.Length.setValue(bv.Length) def taskbox(self): "sets up a taskbox widget" w = QtGui.QWidget() w.setWindowTitle(str(translate("Arch","Wall options"))) lay0 = QtGui.QVBoxLayout(w) + + lay5 = QtGui.QHBoxLayout() + lay0.addLayout(lay5) + label5 = QtGui.QLabel(str(translate("Arch","Length"))) + lay5.addWidget(label5) + self.Length = QtGui.QDoubleSpinBox() + self.Length.setDecimals(2) + self.Length.setValue(0.00) + lay5.addWidget(self.Length) + lay1 = QtGui.QHBoxLayout() lay0.addLayout(lay1) label1 = QtGui.QLabel(str(translate("Arch","Width"))) @@ -237,6 +250,7 @@ class _CommandWall: value1.setDecimals(2) value1.setValue(self.Width) lay1.addWidget(value1) + lay2 = QtGui.QHBoxLayout() lay0.addLayout(lay2) label2 = QtGui.QLabel(str(translate("Arch","Height"))) @@ -245,6 +259,7 @@ class _CommandWall: value2.setDecimals(2) value2.setValue(self.Height) lay2.addWidget(value2) + lay3 = QtGui.QHBoxLayout() lay0.addLayout(lay3) label3 = QtGui.QLabel(str(translate("Arch","Alignment"))) @@ -254,6 +269,7 @@ class _CommandWall: value3.addItems(items) value3.setCurrentIndex(items.index(self.Align)) lay3.addWidget(value3) + value4 = QtGui.QCheckBox(str(translate("Arch","Continue"))) lay0.addWidget(value4) QtCore.QObject.connect(value1,QtCore.SIGNAL("valueChanged(double)"),self.setWidth) diff --git a/src/Mod/Draft/DraftSnap.py b/src/Mod/Draft/DraftSnap.py index 24d6cdb08..685bce591 100644 --- a/src/Mod/Draft/DraftSnap.py +++ b/src/Mod/Draft/DraftSnap.py @@ -242,6 +242,7 @@ class Snapper: comp = self.snapInfo['Component'] if (Draft.getType(obj) == "Wall") and not oldActive: + # special snapping for wall: only to its base shape (except when CTRL is pressed) edges = [] for o in [obj]+obj.Additions: if Draft.getType(o) == "Wall": @@ -253,6 +254,19 @@ class Snapper: snaps.extend(self.snapToPerpendicular(edge,lastpoint)) snaps.extend(self.snapToIntersection(edge)) snaps.extend(self.snapToElines(edge,eline)) + + elif (Draft.getType(obj) == "Structure") and not oldActive: + # special snapping for struct: only to its base point (except when CTRL is pressed) + if obj.Base: + for edge in o.Base.Shape.Edges: + snaps.extend(self.snapToEndpoints(edge)) + snaps.extend(self.snapToMidpoint(edge)) + snaps.extend(self.snapToPerpendicular(edge,lastpoint)) + snaps.extend(self.snapToIntersection(edge)) + snaps.extend(self.snapToElines(edge,eline)) + else: + b = obj.Placement.Base + snaps.append([b,'endpoint',b]) elif obj.isDerivedFrom("Part::Feature"): if (not self.maxEdges) or (len(obj.Edges) <= self.maxEdges): @@ -341,9 +355,8 @@ class Snapper: # set the arch point tracking if self.lastArchPoint: self.setArchDims(self.lastArchPoint,fp) - if Draft.getType(obj) == "Wall": - if self.lastArchPoint != fp: - self.lastArchPoint = fp + if Draft.getType(obj) in ["Wall","Structure"]: + self.lastArchPoint = winner[2] else: self.lastArchPoint = None @@ -734,6 +747,7 @@ class Snapper: if Draft.getParam("hideSnapBar"): self.toolbar.hide() self.mask = None + self.lastArchPoint = None def constrain(self,point,basepoint=None,axis=None): '''constrain(point,basepoint=None,axis=None: Returns a diff --git a/src/Mod/Draft/DraftTrackers.py b/src/Mod/Draft/DraftTrackers.py index 89b4d9935..f672cad5b 100644 --- a/src/Mod/Draft/DraftTrackers.py +++ b/src/Mod/Draft/DraftTrackers.py @@ -805,7 +805,13 @@ class archDimTracker(Tracker): self.dimnode.param1.setValue(.5) p1 = Vector(self.dimnode.pnts.getValues()[0].getValue()) p2 = Vector(self.dimnode.pnts.getValues()[-1].getValue()) - self.Distance = p2.sub(p1).Length + m = self.dimnode.datumtype.getValue() + if m == 2: + self.Distance = (DraftVecUtils.project(p2.sub(p1),Vector(1,0,0))).Length + elif m == 3: + self.Distance = (DraftVecUtils.project(p2.sub(p1),Vector(0,1,0))).Length + else: + self.Distance = (p2.sub(p1)).Length if not text: text = Draft.getParam("dimPrecision") text = "%."+str(text)+"f" From fe9da93c9c56ca4810c39bc5e931c51c15b7e8cf Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 17 Jun 2013 11:44:23 +0200 Subject: [PATCH 098/160] Fix in returning correct surface from face --- src/Mod/Part/App/TopoShapeFacePyImp.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/Mod/Part/App/TopoShapeFacePyImp.cpp b/src/Mod/Part/App/TopoShapeFacePyImp.cpp index 00e86fddd..6a872b162 100644 --- a/src/Mod/Part/App/TopoShapeFacePyImp.cpp +++ b/src/Mod/Part/App/TopoShapeFacePyImp.cpp @@ -37,6 +37,7 @@ # include # include # include +# include # include # include # include @@ -563,28 +564,49 @@ Py::Object TopoShapeFacePy::getSurface() const { Handle_Geom_Surface s = BRep_Tool::Surface(f); Handle_Geom_SurfaceOfRevolution rev = Handle_Geom_SurfaceOfRevolution::DownCast(s); + if (rev.IsNull()) { + Handle_Geom_RectangularTrimmedSurface rect = Handle_Geom_RectangularTrimmedSurface::DownCast(s); + rev = Handle_Geom_SurfaceOfRevolution::DownCast(rect->BasisSurface()); + } if (!rev.IsNull()) { GeomSurfaceOfRevolution* surf = new GeomSurfaceOfRevolution(rev); return Py::Object(new SurfaceOfRevolutionPy(surf),true); } + else { + throw Py::RuntimeError("Failed to convert to surface of revolution"); + } } case GeomAbs_SurfaceOfExtrusion: { Handle_Geom_Surface s = BRep_Tool::Surface(f); Handle_Geom_SurfaceOfLinearExtrusion ext = Handle_Geom_SurfaceOfLinearExtrusion::DownCast(s); + if (ext.IsNull()) { + Handle_Geom_RectangularTrimmedSurface rect = Handle_Geom_RectangularTrimmedSurface::DownCast(s); + ext = Handle_Geom_SurfaceOfLinearExtrusion::DownCast(rect->BasisSurface()); + } if (!ext.IsNull()) { GeomSurfaceOfExtrusion* surf = new GeomSurfaceOfExtrusion(ext); return Py::Object(new SurfaceOfExtrusionPy(surf),true); } + else { + throw Py::RuntimeError("Failed to convert to surface of extrusion"); + } } case GeomAbs_OffsetSurface: { Handle_Geom_Surface s = BRep_Tool::Surface(f); Handle_Geom_OffsetSurface off = Handle_Geom_OffsetSurface::DownCast(s); + if (off.IsNull()) { + Handle_Geom_RectangularTrimmedSurface rect = Handle_Geom_RectangularTrimmedSurface::DownCast(s); + off = Handle_Geom_OffsetSurface::DownCast(rect->BasisSurface()); + } if (!off.IsNull()) { GeomOffsetSurface* surf = new GeomOffsetSurface(off); return Py::Object(new OffsetSurfacePy(surf),true); } + else { + throw Py::RuntimeError("Failed to convert to offset surface"); + } } case GeomAbs_OtherSurface: break; From b63f9d7a2b440e1363508976ec105dac31d7f698 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 17 Jun 2013 13:21:25 +0200 Subject: [PATCH 099/160] 0001152: The output of __repr__() of Vector and Rotatio would create Objects with different Values do to inapropriate rounding --- src/Base/RotationPyImp.cpp | 11 +++++++++-- src/Base/VectorPyImp.cpp | 5 ++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Base/RotationPyImp.cpp b/src/Base/RotationPyImp.cpp index 159952c7e..2cf30426c 100644 --- a/src/Base/RotationPyImp.cpp +++ b/src/Base/RotationPyImp.cpp @@ -38,9 +38,16 @@ using namespace Base; std::string RotationPy::representation(void) const { RotationPy::PointerType ptr = reinterpret_cast(_pcTwinPointer); + Py::Float q0(ptr->getValue()[0]); + Py::Float q1(ptr->getValue()[1]); + Py::Float q2(ptr->getValue()[2]); + Py::Float q3(ptr->getValue()[3]); std::stringstream str; - str << "Quaternion ("; - str << ptr->getValue()[0] << ","<< ptr->getValue()[1] << "," << ptr->getValue()[2] << "," << ptr->getValue()[3]; + str << "Rotation ("; + str << (std::string)q0.repr() << ", " + << (std::string)q1.repr() << ", " + << (std::string)q2.repr() << ", " + << (std::string)q3.repr(); str << ")"; return str.str(); diff --git a/src/Base/VectorPyImp.cpp b/src/Base/VectorPyImp.cpp index da2bb5831..4a1bae849 100644 --- a/src/Base/VectorPyImp.cpp +++ b/src/Base/VectorPyImp.cpp @@ -40,9 +40,12 @@ using namespace Base; std::string VectorPy::representation(void) const { VectorPy::PointerType ptr = reinterpret_cast(_pcTwinPointer); + Py::Float x(ptr->x); + Py::Float y(ptr->y); + Py::Float z(ptr->z); std::stringstream str; str << "Vector ("; - str << ptr->x << ", "<< ptr->y << ", "<< ptr->z; + str << (std::string)x.repr() << ", "<< (std::string)y.repr() << ", "<< (std::string)z.repr(); str << ")"; return str.str(); From e5224f1140e7a6bfac2c873195b6579b8ceaf171 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 19 Jun 2013 10:21:01 +0200 Subject: [PATCH 100/160] Fix license of script --- src/Mod/Part/MakeBottle.py | 25 +++--------------- src/Mod/PartDesign/Scripts/DistanceBolt.py | 27 +++----------------- src/Mod/PartDesign/Scripts/FilletArc.py | 27 +++----------------- src/Mod/PartDesign/Scripts/Parallelepiped.py | 27 +++----------------- 4 files changed, 14 insertions(+), 92 deletions(-) diff --git a/src/Mod/Part/MakeBottle.py b/src/Mod/Part/MakeBottle.py index 1f4c2babf..b75096bca 100644 --- a/src/Mod/Part/MakeBottle.py +++ b/src/Mod/Part/MakeBottle.py @@ -1,25 +1,6 @@ -#*************************************************************************** -#* Copyright (c) 2008 Werner Mayer * -#* * -#* This file is part of the FreeCAD CAx development system. * -#* * -#* This program is free software; you can redistribute it and/or modify * -#* it under the terms of the GNU General Public License (GPL) * -#* 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. * -#* * -#* FreeCAD 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 FreeCAD; if not, write to the Free Software * -#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -#* USA * -#* * -#*************************************************************************** +#! python +# -*- coding: utf-8 -*- +# (c) 2008 Werner Mayer LGPL import Part, math diff --git a/src/Mod/PartDesign/Scripts/DistanceBolt.py b/src/Mod/PartDesign/Scripts/DistanceBolt.py index b7cc385cc..a9c4add48 100644 --- a/src/Mod/PartDesign/Scripts/DistanceBolt.py +++ b/src/Mod/PartDesign/Scripts/DistanceBolt.py @@ -1,28 +1,9 @@ +#! python +# -*- coding: utf-8 -*- +# (c) 2010 Werner Mayer LGPL + """ An example for a high-level cutsom feature object to form a full-parametric distance bolt. - -*************************************************************************** -* Copyright (c) 2010 Werner Mayer * -* * -* This file is part of the FreeCAD CAx development system. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License (GPL) * -* 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. * -* * -* FreeCAD 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 FreeCAD; if not, write to the Free Software * -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -* USA * -* * -*************************************************************************** """ __author__ = "Werner Mayer " diff --git a/src/Mod/PartDesign/Scripts/FilletArc.py b/src/Mod/PartDesign/Scripts/FilletArc.py index f536aa5a3..65a2aeaba 100644 --- a/src/Mod/PartDesign/Scripts/FilletArc.py +++ b/src/Mod/PartDesign/Scripts/FilletArc.py @@ -1,27 +1,6 @@ -""" -*************************************************************************** -* Copyright (c) 2010 Werner Mayer * -* * -* This file is part of the FreeCAD CAx development system. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License (GPL) * -* 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. * -* * -* FreeCAD 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 FreeCAD; if not, write to the Free Software * -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -* USA * -* * -*************************************************************************** -""" +#! python +# -*- coding: utf-8 -*- +# (c) 2010 Werner Mayer LGPL __author__ = "Werner Mayer " diff --git a/src/Mod/PartDesign/Scripts/Parallelepiped.py b/src/Mod/PartDesign/Scripts/Parallelepiped.py index 98b41a7c3..41c47d3b6 100644 --- a/src/Mod/PartDesign/Scripts/Parallelepiped.py +++ b/src/Mod/PartDesign/Scripts/Parallelepiped.py @@ -1,28 +1,9 @@ +#! python +# -*- coding: utf-8 -*- +# (c) 2011 Werner Mayer LGPL + """ An example for a high-level cutsom feature object to form a full-parametric parallelepiped. - -*************************************************************************** -* Copyright (c) 2011 Werner Mayer * -* * -* This file is part of the FreeCAD CAx development system. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License (GPL) * -* 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. * -* * -* FreeCAD 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 FreeCAD; if not, write to the Free Software * -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -* USA * -* * -*************************************************************************** """ __author__ = "Werner Mayer " From c6b02da6485c2e5f2018be7e57d6d075e05a676b Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 19 Jun 2013 17:42:28 +0200 Subject: [PATCH 101/160] Use framebuffer object as fallback for off-screen rendering --- src/Gui/Thumbnail.cpp | 36 ++++++++++---------- src/Gui/Thumbnail.h | 5 +++ src/Gui/View3DInventor.cpp | 29 +++++++++++++++- src/Gui/View3DInventor.h | 1 + src/Gui/View3DInventorViewer.cpp | 13 +++++-- src/Gui/View3DInventorViewer.h | 1 + src/Gui/View3DPy.cpp | 58 +++++++++++++++++++++++++------- src/Gui/View3DPy.h | 2 ++ 8 files changed, 111 insertions(+), 34 deletions(-) diff --git a/src/Gui/Thumbnail.cpp b/src/Gui/Thumbnail.cpp index aeb0a594a..ac0d4490e 100644 --- a/src/Gui/Thumbnail.cpp +++ b/src/Gui/Thumbnail.cpp @@ -29,6 +29,7 @@ # include # include # include +# include #endif #include "Thumbnail.h" @@ -85,24 +86,17 @@ void Thumbnail::SaveDocFile (Base::Writer &writer) const if (!this->viewer) return; QImage img; - try { - this->viewer->savePicture(this->size, this->size, View3DInventorViewer::Current, img); - // Alternative way of off-screen rendering -#if 0 - QGLFramebufferObject fbo(this->size, this->size,QGLFramebufferObject::Depth); - fbo.bind(); - glEnable(GL_DEPTH_TEST); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glDepthRange(0.1,1.0); - glEnable(GL_LINE_SMOOTH); - SoGLRenderAction gl(SbViewportRegion(this->size,this->size)); - gl.apply(this->viewer->getSceneManager()->getSceneGraph()); - fbo.release(); - img = fbo.toImage(); -#endif + if (App::GetApplication().GetParameterGroupByPath + ("User parameter:BaseApp/Preferences/Document")->GetBool("DisablePBuffers",false)) { + this->createThumbnailFromFramebuffer(img); } - catch (...) { - return; // offscreen rendering failed + else { + try { + this->viewer->savePicture(this->size, this->size, View3DInventorViewer::Current, img); + } + catch (...) { + this->createThumbnailFromFramebuffer(img); + } } QPixmap px = Gui::BitmapFactory().pixmap(App::Application::Config()["AppIcon"].c_str()); @@ -126,3 +120,11 @@ void Thumbnail::SaveDocFile (Base::Writer &writer) const void Thumbnail::RestoreDocFile(Base::Reader &reader) { } + +void Thumbnail::createThumbnailFromFramebuffer(QImage& img) const +{ + // Alternative way of off-screen rendering + QGLFramebufferObject fbo(this->size, this->size,QGLFramebufferObject::Depth); + this->viewer->renderToFramebuffer(&fbo); + img = fbo.toImage(); +} diff --git a/src/Gui/Thumbnail.h b/src/Gui/Thumbnail.h index daa66ad11..2f387a600 100644 --- a/src/Gui/Thumbnail.h +++ b/src/Gui/Thumbnail.h @@ -27,6 +27,8 @@ #include #include +class QImage; + namespace Gui { class View3DInventorViewer; @@ -53,6 +55,9 @@ public: void RestoreDocFile(Base::Reader &reader); //@} +private: + void createThumbnailFromFramebuffer(QImage&) const; + private: QUrl uri; View3DInventorViewer* viewer; diff --git a/src/Gui/View3DInventor.cpp b/src/Gui/View3DInventor.cpp index 01e5fa115..9528ef143 100644 --- a/src/Gui/View3DInventor.cpp +++ b/src/Gui/View3DInventor.cpp @@ -27,6 +27,7 @@ # include # include # include +# include # include # include # include @@ -483,12 +484,38 @@ void View3DInventor::print(QPrinter* printer) QImage img; QPainter p(printer); QRect rect = printer->pageRect(); - _viewer->savePicture(rect.width(), rect.height(), View3DInventorViewer::White, img); + + if (App::GetApplication().GetParameterGroupByPath + ("User parameter:BaseApp/Preferences/Document")->GetBool("DisablePBuffers",false)) { + previewFromFramebuffer(rect, img); + } + else { + try { + _viewer->savePicture(rect.width(), rect.height(), View3DInventorViewer::White, img); + } + catch (...) { + previewFromFramebuffer(rect, img); + } + } + p.drawImage(0,0,img); p.end(); #endif } +void View3DInventor::previewFromFramebuffer(const QRect& rect, QImage& img) +{ + QGLFramebufferObject fbo(rect.width(), rect.height(), QGLFramebufferObject::Depth); + const SbColor col = _viewer->getBackgroundColor(); + bool on = _viewer->hasGradientBackground(); + _viewer->setBackgroundColor(SbColor(1.0f,1.0f,1.0f)); + _viewer->setGradientBackground(false); + _viewer->renderToFramebuffer(&fbo); + _viewer->setBackgroundColor(col); + _viewer->setGradientBackground(on); + img = fbo.toImage(); +} + // ********************************************************************************** bool View3DInventor::onMsg(const char* pMsg, const char** ppReturn) diff --git a/src/Gui/View3DInventor.h b/src/Gui/View3DInventor.h index de3bc9249..94cd990e8 100644 --- a/src/Gui/View3DInventor.h +++ b/src/Gui/View3DInventor.h @@ -127,6 +127,7 @@ protected: void focusInEvent (QFocusEvent * e); void customEvent (QEvent * e); void contextMenuEvent (QContextMenuEvent*e); + void previewFromFramebuffer(const QRect&, QImage&); /// handle to the viewer parameter group ParameterGrp::handle hGrp; diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index 1d37bd310..5f19b4b94 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -430,6 +430,11 @@ void View3DInventorViewer::setGradientBackground(bool on) backgroundroot->removeChild(pcBackGround); } +bool View3DInventorViewer::hasGradientBackground() const +{ + return (backgroundroot->findChild(pcBackGround) != -1); +} + void View3DInventorViewer::setGradientBackgroundColor(const SbColor& fromColor, const SbColor& toColor) { @@ -577,7 +582,6 @@ void View3DInventorViewer::savePicture(const char* filename, int w, int h, throw Base::Exception("Offscreen rendering failed"); // set matrix for miba renderer._Matrix = camera->getViewVolume().getMatrix(); - //bool ok = renderer.writeToImageFile(filename, filetypeextension); renderer.writeToImageFile(filename, comment); root->unref(); } @@ -941,6 +945,8 @@ void View3DInventorViewer::renderToFramebuffer(QGLFramebufferObject* fbo) { this->glLockNormal(); fbo->bind(); + int width = fbo->size().width(); + int height = fbo->size().height(); glDisable(GL_TEXTURE_2D); glEnable(GL_LIGHTING); @@ -948,12 +954,13 @@ void View3DInventorViewer::renderToFramebuffer(QGLFramebufferObject* fbo) glEnable(GL_LINE_SMOOTH); const SbColor col = this->getBackgroundColor(); - glClearColor(col[0], col[1], col[2], 0.0f); + glViewport(0, 0, width, height); + glClearColor(col[0], col[1], col[2], 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDepthRange(0.1,1.0); - SoGLRenderAction gl(SbViewportRegion(fbo->size().width(),fbo->size().height())); + SoGLRenderAction gl(SbViewportRegion(width, height)); gl.apply(this->backgroundroot); gl.apply(this->getSceneManager()->getSceneGraph()); gl.apply(this->foregroundroot); diff --git a/src/Gui/View3DInventorViewer.h b/src/Gui/View3DInventorViewer.h index fa0571292..0a589a270 100644 --- a/src/Gui/View3DInventorViewer.h +++ b/src/Gui/View3DInventorViewer.h @@ -269,6 +269,7 @@ public: void viewSelection(); void setGradientBackground(bool b); + bool hasGradientBackground() const; void setGradientBackgroundColor(const SbColor& fromColor, const SbColor& toColor); void setGradientBackgroundColor(const SbColor& fromColor, diff --git a/src/Gui/View3DPy.cpp b/src/Gui/View3DPy.cpp index 889712108..a0570a16c 100644 --- a/src/Gui/View3DPy.cpp +++ b/src/Gui/View3DPy.cpp @@ -26,6 +26,8 @@ #ifndef __InventorAll__ # include "InventorAll.h" # include +# include +# include #endif @@ -556,6 +558,37 @@ Py::Object View3DInventorPy::isAnimationEnabled(const Py::Tuple& args) return Py::Boolean(ok ? true : false); } +void View3DInventorPy::createImageFromFramebuffer(int backgroundType, int width, int height, QImage& img) +{ + QGLFramebufferObject fbo(width, height, QGLFramebufferObject::Depth); + const SbColor col = _view->getViewer()->getBackgroundColor(); + bool on = _view->getViewer()->hasGradientBackground(); + + switch(backgroundType){ + case 0: // Current + break; + case 1: // Black + _view->getViewer()->setBackgroundColor(SbColor(0.0f,0.0f,0.0f)); + _view->getViewer()->setGradientBackground(false); + break; + case 2: // White + _view->getViewer()->setBackgroundColor(SbColor(1.0f,1.0f,1.0f)); + _view->getViewer()->setGradientBackground(false); + break; + case 3: // Transparent + _view->getViewer()->setBackgroundColor(SbColor(1.0f,1.0f,1.0f)); + _view->getViewer()->setGradientBackground(false); + break; + default: + break; + } + + _view->getViewer()->renderToFramebuffer(&fbo); + _view->getViewer()->setBackgroundColor(col); + _view->getViewer()->setGradientBackground(on); + img = fbo.toImage(); +} + Py::Object View3DInventorPy::saveImage(const Py::Tuple& args) { char *cFileName,*cImageType="Current",*cComment="$MIBA"; @@ -587,24 +620,23 @@ Py::Object View3DInventorPy::saveImage(const Py::Tuple& args) else throw Py::Exception("Parameter 4 have to be (Current|Black|White|Transparent)"); #endif + if (App::GetApplication().GetParameterGroupByPath + ("User parameter:BaseApp/Preferences/Document")->GetBool("DisablePBuffers",false)) { + QImage img; + createImageFromFramebuffer(t, w, h, img); + img.save(QString::fromUtf8(cFileName)); + return Py::None(); + } try { - QColor c; _view->getViewer()->savePicture(cFileName,w,h,t,cComment); return Py::None(); } - catch (const Base::Exception& e) { - Base::Console().Log("Try disabling the use of pbuffers, set the environment variables\n" - "COIN_GLXGLUE_NO_PBUFFERS=1\n" - "COIN_GLXGLUE_NO_GLX13_PBUFFERS=1\n" - "and re-run the application.\n"); - throw Py::Exception(e.what()); - } - catch (const std::exception& e) { - throw Py::Exception(e.what()); - } - catch(...) { - throw Py::Exception("Unknown C++ exception"); + catch (const Base::Exception&) { + QImage img; + createImageFromFramebuffer(t, w, h, img); + img.save(QString::fromUtf8(cFileName)); + return Py::None(); } } diff --git a/src/Gui/View3DPy.h b/src/Gui/View3DPy.h index 43fd65318..5b0920f59 100644 --- a/src/Gui/View3DPy.h +++ b/src/Gui/View3DPy.h @@ -28,6 +28,7 @@ #include class SoEventCallback; +class QImage; namespace Gui { @@ -102,6 +103,7 @@ private: typedef PyObject* (*method_varargs_handler)(PyObject *_self, PyObject *_args); static method_varargs_handler pycxx_handler; static PyObject *method_varargs_ext_handler(PyObject *_self, PyObject *_args); + void createImageFromFramebuffer(int backgroundType, int width, int height, QImage&); private: std::list callbacks; From 5b46a86056c0bbb13526be62d13d3e20f212efc0 Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 20 Jun 2013 13:12:31 +0200 Subject: [PATCH 102/160] 0001155: FreeCAD crashed while creating a loft of two ellipses --- src/Mod/Drawing/App/CMakeLists.txt | 9 +++------ src/Mod/Drawing/App/FeatureView.cpp | 14 ++++++++++++++ src/Mod/Drawing/App/FeatureView.h | 1 + src/Mod/Part/App/CMakeLists.txt | 11 +++-------- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/Mod/Drawing/App/CMakeLists.txt b/src/Mod/Drawing/App/CMakeLists.txt index 00710b75e..06d6ca7d2 100644 --- a/src/Mod/Drawing/App/CMakeLists.txt +++ b/src/Mod/Drawing/App/CMakeLists.txt @@ -65,12 +65,6 @@ if(MSVC) ADD_MSVC_PRECOMPILED_HEADER("PreCompiled.h" "PreCompiled.cpp" Drawing_CPP_SRCS) endif(MSVC) -# Set special compiler flag to convert a SIGSEV into an exception -# to handle issue #0000478. -IF(MSVC) -SET_SOURCE_FILES_PROPERTIES(ProjectionAlgos.cpp PROPERTIES COMPILE_FLAGS "/EHa") -ENDIF(MSVC) - add_library(Drawing SHARED ${Drawing_SRCS} ${Features_SRCS} ${DrawingAlgos_SRCS}) target_link_libraries(Drawing ${Drawing_LIBS}) @@ -94,6 +88,9 @@ if(MSVC) set_target_properties(Drawing PROPERTIES DEBUG_OUTPUT_NAME "Drawing_d") set_target_properties(Drawing PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Mod/Drawing) set_target_properties(Drawing PROPERTIES PREFIX "../") + # Set special compiler flag to convert a SIGSEV into an exception + # to fix issue #0000478 + set_target_properties(Drawing PROPERTIES COMPILE_FLAGS "/EHa") elseif(MINGW) set_target_properties(Drawing PROPERTIES SUFFIX ".pyd") set_target_properties(Drawing PROPERTIES DEBUG_OUTPUT_NAME "Drawing_d") diff --git a/src/Mod/Drawing/App/FeatureView.cpp b/src/Mod/Drawing/App/FeatureView.cpp index fea2121a8..e570ca46f 100644 --- a/src/Mod/Drawing/App/FeatureView.cpp +++ b/src/Mod/Drawing/App/FeatureView.cpp @@ -25,6 +25,7 @@ #ifndef _PreComp_ # include +# include #endif @@ -63,6 +64,19 @@ FeatureView::~FeatureView() { } +App::DocumentObjectExecReturn *FeatureView::recompute(void) +{ + try { + return App::DocumentObject::recompute(); + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + App::DocumentObjectExecReturn* ret = new App::DocumentObjectExecReturn(e->GetMessageString()); + if (ret->Why.empty()) ret->Why = "Unknown OCC exception"; + return ret; + } +} + App::DocumentObjectExecReturn *FeatureView::execute(void) { return App::DocumentObject::StdReturn; diff --git a/src/Mod/Drawing/App/FeatureView.h b/src/Mod/Drawing/App/FeatureView.h index 5b3d23950..9d4607fff 100644 --- a/src/Mod/Drawing/App/FeatureView.h +++ b/src/Mod/Drawing/App/FeatureView.h @@ -55,6 +55,7 @@ public: /** @name methods overide Feature */ //@{ /// recalculate the Feature + virtual App::DocumentObjectExecReturn *recompute(void); virtual App::DocumentObjectExecReturn *execute(void); //@} diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index e337bebb9..391bb6023 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -127,14 +127,6 @@ SET(Features_SRCS ) SOURCE_GROUP("Features" FILES ${Features_SRCS}) -# Set special compiler flag to convert a SIGSEV into an exception -# to fix issue #0000215. -IF(MSVC) -SET_SOURCE_FILES_PROPERTIES(FeatureFillet.cpp PROPERTIES COMPILE_FLAGS "/EHa") -SET_SOURCE_FILES_PROPERTIES(FeaturePartBoolean.cpp PROPERTIES COMPILE_FLAGS "/EHa") -SET_SOURCE_FILES_PROPERTIES(FeatureExtrusion.cpp PROPERTIES COMPILE_FLAGS "/EHa") -ENDIF(MSVC) - SET(Properties_SRCS PropertyTopoShape.cpp PropertyTopoShape.h @@ -270,6 +262,9 @@ if(MSVC) set_target_properties(Part PROPERTIES DEBUG_OUTPUT_NAME "Part_d") set_target_properties(Part PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Mod/Part) set_target_properties(Part PROPERTIES PREFIX "../") + # Set special compiler flag to convert a SIGSEV into an exception + # to fix issue #0000215, #0001155, ... + set_target_properties(Part PROPERTIES COMPILE_FLAGS "/EHa") elseif(MINGW) set_target_properties(Part PROPERTIES SUFFIX ".pyd") set_target_properties(Part PROPERTIES DEBUG_OUTPUT_NAME "Part_d") From 7e3751224a9904a35b34be5238a5759ce625b419 Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 20 Jun 2013 16:54:52 +0200 Subject: [PATCH 103/160] Minor fix --- data/examples/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/examples/CMakeLists.txt b/data/examples/CMakeLists.txt index 4c92d776b..4df175800 100644 --- a/data/examples/CMakeLists.txt +++ b/data/examples/CMakeLists.txt @@ -14,7 +14,7 @@ ADD_CUSTOM_TARGET(Example_data ALL # 0001097: CMake stops with error "Circular ... <- ... dependency dropped." if(NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") - fc_copy_sources(Examples "${CMAKE_BINARY_DIR}/data/examples" ${Examples_Files}) + fc_copy_sources(Example_data "${CMAKE_BINARY_DIR}/data/examples" ${Examples_Files}) endif() INSTALL( From f05be462bc7f06955ab558bb8d75e90f5bece85c Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 20 Jun 2013 16:57:10 +0200 Subject: [PATCH 104/160] Reduce redundant code in View3DInventorViewer class --- src/Gui/SoFCOffscreenRenderer.cpp | 27 ++++++----- src/Gui/SoFCOffscreenRenderer.h | 11 +++-- src/Gui/View3DInventorViewer.cpp | 75 ------------------------------- src/Gui/View3DInventorViewer.h | 8 +--- src/Gui/View3DPy.cpp | 30 +++++++------ 5 files changed, 38 insertions(+), 113 deletions(-) diff --git a/src/Gui/SoFCOffscreenRenderer.cpp b/src/Gui/SoFCOffscreenRenderer.cpp index 8af4a831b..025ac69d7 100644 --- a/src/Gui/SoFCOffscreenRenderer.cpp +++ b/src/Gui/SoFCOffscreenRenderer.cpp @@ -85,19 +85,16 @@ void SoFCOffscreenRenderer::writeToImage (QImage& img) const BitmapFactory().convert(image, img); } -void SoFCOffscreenRenderer::writeToImageFile (const char *filename, const char* comment) const +void SoFCOffscreenRenderer::writeToImageFile(const char* filename, const char* comment, const SbMatrix& mat, const QImage& image) { Base::FileInfo file(filename); if (file.hasExtension("JPG") || file.hasExtension("JPEG")) { - QImage img; - writeToImage(img); - // writing comment in case of jpeg (Qt ignores setText() in case of jpeg) std::string com; if (strcmp(comment,"")==0) com = "Screenshot created by FreeCAD"; else if (strcmp(comment,"$MIBA")==0) - com = createMIBA(); + com = createMIBA(mat); else com = comment; @@ -105,7 +102,7 @@ void SoFCOffscreenRenderer::writeToImageFile (const char *filename, const char* QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); - img.save(&buffer, "JPG"); + image.save(&buffer, "JPG"); writeJPEGComment(com, ba); QFile file(QString::fromUtf8(filename)); @@ -134,8 +131,7 @@ void SoFCOffscreenRenderer::writeToImageFile (const char *filename, const char* // Supported by Qt if (supported) { - QImage img; - writeToImage(img); + QImage img = image; // set keywords for PNG format if (file.hasExtension("PNG")) { img.setText(QLatin1String("Title"), QString::fromUtf8(filename)); @@ -143,7 +139,7 @@ void SoFCOffscreenRenderer::writeToImageFile (const char *filename, const char* if (strcmp(comment,"")==0) img.setText(QLatin1String("Description"), QLatin1String("Screenshot created by FreeCAD")); else if (strcmp(comment,"$MIBA")==0) - img.setText(QLatin1String("Description"), QLatin1String(createMIBA().c_str())); + img.setText(QLatin1String("Description"), QLatin1String(createMIBA(mat).c_str())); else img.setText(QLatin1String("Description"), QString::fromUtf8(comment)); img.setText(QLatin1String("Creation Time"), QDateTime::currentDateTime().toString()); @@ -169,6 +165,9 @@ void SoFCOffscreenRenderer::writeToImageFile (const char *filename, const char* throw Base::Exception(str.str()); } } + // + // Use internal buffer instead of QImage + // else if (isWriteSupported(file.extension().c_str())) { // Any format which is supported by Coin only if (!writeToFile(filename, file.extension().c_str())) @@ -249,7 +248,7 @@ QStringList SoFCOffscreenRenderer::getWriteImageFiletypeInfo() return formats; } -std::string SoFCOffscreenRenderer::createMIBA() const +std::string SoFCOffscreenRenderer::createMIBA(const SbMatrix& mat) const { std::stringstream com; const std::map& cfg = App::Application::Config(); @@ -264,10 +263,10 @@ std::string SoFCOffscreenRenderer::createMIBA() const com << " \n" ; com << " \n"; com << " \n" ; com << " \n" ; com << " \n" ; diff --git a/src/Gui/SoFCOffscreenRenderer.h b/src/Gui/SoFCOffscreenRenderer.h index a5f87b1a4..7a8cc71f4 100644 --- a/src/Gui/SoFCOffscreenRenderer.h +++ b/src/Gui/SoFCOffscreenRenderer.h @@ -79,19 +79,22 @@ public: * Note that you must still specify the full filename for the first argument, i.e. the second argument will * not automatically be attached to the filename -- it is only used to decide the filetype. * + * If \a comment is set to '$MIBA' information regarding the MIBA standard is + * embedded to the picture, otherwise the \a comment is embedded as is. + * The appropriate file format must support embedding meta information which + * is provided by JPEG or PNG. + * * This does basically the same as writeToFile() unless that all QImage file formats are supported if not * directly supported by Coin3D. */ - void writeToImageFile (const char *filename, const char* comment) const; + void writeToImageFile(const char* filename, const char* comment, const SbMatrix& mat, const QImage& img); /** * This method returns all image file formats supported by Coin3D (see getWriteFiletypeInfo()) with all QImage file formats that are * not directly supported by Coin3D, if so. */ QStringList getWriteImageFiletypeInfo(); - std::string createMIBA() const; - - SbMatrix _Matrix; + std::string createMIBA(const SbMatrix& mat) const; }; } // namespace Gui diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index 5f19b4b94..80796f003 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -516,81 +516,6 @@ void View3DInventorViewer::setSceneGraph (SoNode *root) } } -void View3DInventorViewer::savePicture(const char* filename, int w, int h, - int eBackgroundType, const char* comment) const -{ - // if no valid color use the current background - bool useBackground = false; - SbViewportRegion vp(getViewportRegion()); - if (w>0 && h>0) - vp.setWindowSize( (short)w, (short)h ); - - //NOTE: To support pixels per inch we must use SbViewportRegion::setPixelsPerInch( ppi ); - //The default value is 72.0. - //If we need to support grayscale images with must either use SoOffscreenRenderer::LUMINANCE or - //SoOffscreenRenderer::LUMINANCE_TRANSPARENCY. - SoFCOffscreenRenderer& renderer = SoFCOffscreenRenderer::instance(); - renderer.setViewportRegion(vp); - SoCallback* cb = 0; - - // if we use transparency then we must not set a background color - switch(eBackgroundType){ - case Current: - if (backgroundroot->findChild(pcBackGround) == -1) { - renderer.setBackgroundColor(this->getBackgroundColor()); - } - else { - useBackground = true; - cb = new SoCallback; - cb->setCallback(clearBuffer); - } - break; - case White: - renderer.setBackgroundColor( SbColor(1.0, 1.0, 1.0) ); - break; - case Black: - renderer.setBackgroundColor( SbColor(0.0, 0.0, 0.0) ); - break; - case Transparent: - renderer.setComponents(SoFCOffscreenRenderer::RGB_TRANSPARENCY ); - break; - default: - break; - } - - SoSeparator* root = new SoSeparator; - root->ref(); - - SoCamera* camera = getCamera(); - if (useBackground) { - root->addChild(backgroundroot); - root->addChild(cb); - } - root->addChild(getHeadlight()); - root->addChild(camera); - SoCallback* gl = new SoCallback; - gl->setCallback(setGLWidget,this->getGLWidget()); - root->addChild(gl); - root->addChild(pcViewProviderRoot); - if (useBackground) - root->addChild(cb); - root->addChild(foregroundroot); - - try { - // render the scene - if (!renderer.render(root)) - throw Base::Exception("Offscreen rendering failed"); - // set matrix for miba - renderer._Matrix = camera->getViewVolume().getMatrix(); - renderer.writeToImageFile(filename, comment); - root->unref(); - } - catch (...) { - root->unref(); - throw; // re-throw exception - } -} - void View3DInventorViewer::savePicture(int w, int h, int eBackgroundType, QImage& img) const { // if no valid color use the current background diff --git a/src/Gui/View3DInventorViewer.h b/src/Gui/View3DInventorViewer.h index 0a589a270..c8e2384ac 100644 --- a/src/Gui/View3DInventorViewer.h +++ b/src/Gui/View3DInventorViewer.h @@ -162,14 +162,8 @@ public: //@{ /** * Creates an image with width \a w and height \a h of the current scene graph - * and exports the rendered scenegraph directly to file \a filename. - * If \a comment is set to '$MIBA' information regarding the MIBA standard is - * embedded to the picture, otherwise the \a comment is embedded as is. - * The appropriate file format must support embedding meta information which - * is provided by JPEG or PNG. + * and exports the rendered scenegraph to an image. */ - void savePicture(const char* filename, int w, int h, int eBackgroundType, - const char* comment) const; void savePicture(int w, int h, int eBackgroundType, QImage&) const; void saveGraphic(int pagesize, int eBackgroundType, SoVectorizeAction* va) const; //@} diff --git a/src/Gui/View3DPy.cpp b/src/Gui/View3DPy.cpp index a0570a16c..9f008bacd 100644 --- a/src/Gui/View3DPy.cpp +++ b/src/Gui/View3DPy.cpp @@ -28,6 +28,8 @@ # include # include # include +# include +# include #endif @@ -39,6 +41,7 @@ #include "NavigationStyle.h" #include "SoFCSelection.h" #include "SoFCSelectionAction.h" +#include "SoFCOffscreenRenderer.h" #include "SoFCVectorizeSVGAction.h" #include "SoFCVectorizeU3DAction.h" #include "SoFCDB.h" @@ -620,24 +623,25 @@ Py::Object View3DInventorPy::saveImage(const Py::Tuple& args) else throw Py::Exception("Parameter 4 have to be (Current|Black|White|Transparent)"); #endif + QImage img; if (App::GetApplication().GetParameterGroupByPath ("User parameter:BaseApp/Preferences/Document")->GetBool("DisablePBuffers",false)) { - QImage img; createImageFromFramebuffer(t, w, h, img); - img.save(QString::fromUtf8(cFileName)); - return Py::None(); + } + else { + try { + _view->getViewer()->savePicture(w, h, t, img); + } + catch (const Base::Exception&) { + createImageFromFramebuffer(t, w, h, img); + } } - try { - _view->getViewer()->savePicture(cFileName,w,h,t,cComment); - return Py::None(); - } - catch (const Base::Exception&) { - QImage img; - createImageFromFramebuffer(t, w, h, img); - img.save(QString::fromUtf8(cFileName)); - return Py::None(); - } + SoFCOffscreenRenderer& renderer = SoFCOffscreenRenderer::instance(); + SoCamera* cam = _view->getViewer()->getCamera(); + renderer.writeToImageFile(cFileName, cComment, cam->getViewVolume().getMatrix(), img); + + return Py::None(); } Py::Object View3DInventorPy::saveVectorGraphic(const Py::Tuple& args) From 33faa4010149b967f8fcbb659d227c5b06acd3fd Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Thu, 20 Jun 2013 21:21:35 -0300 Subject: [PATCH 105/160] 0001078: Draft now snaps to center of polygons and cylinders --- src/Mod/Draft/DraftGeomUtils.py | 2 ++ src/Mod/Draft/DraftSnap.py | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/Mod/Draft/DraftGeomUtils.py b/src/Mod/Draft/DraftGeomUtils.py index 1ae0d693f..1f81d6ed3 100755 --- a/src/Mod/Draft/DraftGeomUtils.py +++ b/src/Mod/Draft/DraftGeomUtils.py @@ -301,6 +301,8 @@ def findIntersection(edge1,edge2,infinite1=False,infinite2=False,ex1=False,ex2=F if dirVec.dot(arc.Curve.Axis) != 0 : toPlane = Vector(arc.Curve.Axis) ; toPlane.normalize() d = pt1.dot(toPlane) + if not d: + return [] dToPlane = center.sub(pt1).dot(toPlane) toPlane = Vector(pt1) toPlane.scale(dToPlane/d,dToPlane/d,dToPlane/d) diff --git a/src/Mod/Draft/DraftSnap.py b/src/Mod/Draft/DraftSnap.py index 685bce591..9f5d98202 100644 --- a/src/Mod/Draft/DraftSnap.py +++ b/src/Mod/Draft/DraftSnap.py @@ -269,6 +269,9 @@ class Snapper: snaps.append([b,'endpoint',b]) elif obj.isDerivedFrom("Part::Feature"): + if Draft.getType(obj) == "Polygon": + snaps.extend(self.snapToPolygon(obj)) + if (not self.maxEdges) or (len(obj.Edges) <= self.maxEdges): if "Edge" in comp: # we are snapping to an edge @@ -650,6 +653,19 @@ class Snapper: for p in pt: snaps.append([p,'intersection',p]) return snaps + + def snapToPolygon(self,obj): + "returns a list of polygon center snap locations" + snaps = [] + c = obj.Placement.Base + for edge in obj.Shape.Edges: + p1 = edge.Vertexes[0].Point + p2 = edge.Vertexes[-1].Point + v1 = p1.add((p2-p1).scale(.25,.25,.25)) + v2 = p1.add((p2-p1).scale(.75,.75,.75)) + snaps.append([v1,'center',c]) + snaps.append([v2,'center',c]) + return snaps def snapToVertex(self,info,active=False): p = Vector(info['x'],info['y'],info['z']) From 367a8f9aee36d6d76a8e9396774e9a378ba9a089 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Thu, 20 Jun 2013 21:32:41 -0300 Subject: [PATCH 106/160] Draft: Fixed license blocks --- src/Mod/Draft/importDWG.py | 2 +- src/Mod/Draft/importDXF.py | 3 +-- src/Mod/Draft/importOCA.py | 5 +++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Mod/Draft/importDWG.py b/src/Mod/Draft/importDWG.py index bbfc947a0..f976b1a01 100644 --- a/src/Mod/Draft/importDWG.py +++ b/src/Mod/Draft/importDWG.py @@ -5,7 +5,7 @@ #* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * -#* it under the terms of the GNU Lesser General Public License (GPL) * +#* 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. * diff --git a/src/Mod/Draft/importDXF.py b/src/Mod/Draft/importDXF.py index 7ee157a06..85d89ec4c 100644 --- a/src/Mod/Draft/importDXF.py +++ b/src/Mod/Draft/importDXF.py @@ -1,4 +1,3 @@ - # -*- coding: utf8 -*- #*************************************************************************** @@ -6,7 +5,7 @@ #* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * -#* it under the terms of the GNU Lesser General Public License (GPL) * +#* 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. * diff --git a/src/Mod/Draft/importOCA.py b/src/Mod/Draft/importOCA.py index e71fa060e..d618258ee 100644 --- a/src/Mod/Draft/importOCA.py +++ b/src/Mod/Draft/importOCA.py @@ -1,10 +1,11 @@ +# -*- coding: utf8 -*- #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * -#* it under the terms of the GNU General Public License (GPL) * +#* 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. * From 1dc122dc9a0b0cf49ec4bf25e63ee19f0e345470 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 22 Jun 2013 01:56:58 +0200 Subject: [PATCH 107/160] 0000877: Move from PyQt to PySide --- CMakeLists.txt | 11 ++++ src/Gui/CMakeLists.txt | 23 +++++++ src/Gui/TaskView/TaskDialogPython.cpp | 76 ++++++++++------------ src/Gui/WidgetFactory.cpp | 94 ++++++++++++++++++++++----- src/Gui/WidgetFactory.h | 11 ++++ 5 files changed, 159 insertions(+), 56 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 17cda74bc..3bc629c75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -360,6 +360,17 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X) find_package(Spnav) endif(WIN32) +# -------------------------------- Shiboken/PySide ------------------------ + + find_package(Shiboken) + IF(SHIBOKEN_INCLUDE_DIR) + message("-- Shiboken has been found.") + ENDIF(SHIBOKEN_INCLUDE_DIR) + find_package(PySide) + IF(PYSIDE_INCLUDE_DIR) + message("-- PySide has been found.") + ENDIF(PYSIDE_INCLUDE_DIR) + # ------------------------------ Matplotlib ------------------------------ find_package(Matplotlib) diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 104e4486b..79137b392 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -3,6 +3,7 @@ if(WIN32) add_definitions(-DFCGui -DQIIS_MAKEDLL) endif(WIN32) + if (FREECAD_USE_3DCONNEXION) add_definitions(-D_USE_3DCONNEXION_SDK) endif(FREECAD_USE_3DCONNEXION) @@ -59,6 +60,28 @@ IF(SPNAV_FOUND) ) ENDIF(SPNAV_FOUND) +if(SHIBOKEN_INCLUDE_DIR) + add_definitions(-DHAVE_SHIBOKEN) + include_directories( + ${SHIBOKEN_INCLUDE_DIR} + ) + set(FreeCADGui_LIBS + ${FreeCADGui_LIBS} + ${SHIBOKEN_LIBRARY} + ) +endif(SHIBOKEN_INCLUDE_DIR) + +if(PYSIDE_INCLUDE_DIR) + add_definitions(-DHAVE_PYSIDE) + include_directories( + ${PYSIDE_INCLUDE_DIR} + ) + set(FreeCADGui_LIBS + ${FreeCADGui_LIBS} + ${PYSIDE_LIBRARY} + ) +endif(PYSIDE_INCLUDE_DIR) + generate_from_xml(DocumentPy) generate_from_xml(PythonWorkbenchPy) generate_from_xml(ViewProviderPy) diff --git a/src/Gui/TaskView/TaskDialogPython.cpp b/src/Gui/TaskView/TaskDialogPython.cpp index c921eb110..e8da8ca38 100644 --- a/src/Gui/TaskView/TaskDialogPython.cpp +++ b/src/Gui/TaskView/TaskDialogPython.cpp @@ -186,24 +186,22 @@ TaskWatcherPython::TaskWatcherPython(const Py::Object& o) if (!tb && !title.isEmpty()) tb = new Gui::TaskView::TaskBox(icon, title, true, 0); Py::List list(watcher.getAttr(std::string("widgets"))); - Py::Module mainmod(PyImport_AddModule((char*)"sip")); - Py::Callable func = mainmod.getDict().getItem("unwrapinstance"); - for (Py::List::iterator it = list.begin(); it != list.end(); ++it) { - Py::Tuple arguments(1); - arguments[0] = *it; //PyQt pointer - Py::Object result = func.apply(arguments); - void* ptr = PyLong_AsVoidPtr(result.ptr()); - QObject* object = reinterpret_cast(ptr); - if (object) { - QWidget* w = qobject_cast(object); - if (w) { - if (tb) - tb->groupLayout()->addWidget(w); - else - Content.push_back(w); + + Gui::PythonWrapper wrap; + if (wrap.loadModule()) { + for (Py::List::iterator it = list.begin(); it != list.end(); ++it) { + QObject* object = wrap.toQObject(*it); + if (object) { + QWidget* w = qobject_cast(object); + if (w) { + if (tb) + tb->groupLayout()->addWidget(w); + else + Content.push_back(w); + } } } - } + } } if (tb) Content.push_back(tb); @@ -278,30 +276,28 @@ TaskDialogPython::TaskDialogPython(const Py::Object& o) : dlg(o) } } else if (dlg.hasAttr(std::string("form"))) { - Py::Object f(dlg.getAttr(std::string("form"))); - Py::List widgets; - if (f.isList()) { - widgets = f; - } - else { - widgets.append(f); - } - for (Py::List::iterator it = widgets.begin(); it != widgets.end(); ++it) { - Py::Module mainmod(PyImport_AddModule((char*)"sip")); - Py::Callable func = mainmod.getDict().getItem("unwrapinstance"); - Py::Tuple arguments(1); - arguments[0] = *it; //PyQt pointer - Py::Object result = func.apply(arguments); - void* ptr = PyLong_AsVoidPtr(result.ptr()); - QObject* object = reinterpret_cast(ptr); - if (object) { - QWidget* form = qobject_cast(object); - if (form) { - Gui::TaskView::TaskBox* taskbox = new Gui::TaskView::TaskBox( - form->windowIcon().pixmap(32), form->windowTitle(), true, 0); - taskbox->groupLayout()->addWidget(form); - Content.push_back(taskbox); - } + Py::Object f(dlg.getAttr(std::string("form"))); + Py::List widgets; + if (f.isList()) { + widgets = f; + } + else { + widgets.append(f); + } + + Gui::PythonWrapper wrap; + if (wrap.loadModule()) { + for (Py::List::iterator it = widgets.begin(); it != widgets.end(); ++it) { + QObject* object = wrap.toQObject(*it); + if (object) { + QWidget* form = qobject_cast(object); + if (form) { + Gui::TaskView::TaskBox* taskbox = new Gui::TaskView::TaskBox( + form->windowIcon().pixmap(32), form->windowTitle(), true, 0); + taskbox->groupLayout()->addWidget(form); + Content.push_back(taskbox); + } + } } } } diff --git a/src/Gui/WidgetFactory.cpp b/src/Gui/WidgetFactory.cpp index fd734154f..2996f2592 100644 --- a/src/Gui/WidgetFactory.cpp +++ b/src/Gui/WidgetFactory.cpp @@ -23,6 +23,20 @@ #include "PreCompiled.h" +#if 0 // disable for now +#ifdef HAVE_SHIBOKEN +# undef _POSIX_C_SOURCE +# undef _XOPEN_SOURCE +# include +# include +# include +# ifdef HAVE_PYSIDE +# include +PyTypeObject** SbkPySide_QtCoreTypes=NULL; +# endif +#endif +#endif + #include #include #include @@ -37,6 +51,64 @@ using namespace Gui; +PythonWrapper::PythonWrapper() +{ +} + +QObject* PythonWrapper::toQObject(const Py::Object& pyobject) +{ +#if 0 + // http://pastebin.com/JByDAF5Z +//#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) + PyTypeObject * type = Shiboken::SbkType(); + if (type) { + if (Shiboken::Object::checkType(pyobject.ptr())) { + SbkObject* sbkobject = reinterpret_cast(pyobject.ptr()); + void* cppobject = Shiboken::Object::cppPointer(sbkobject, type); + return reinterpret_cast(cppobject); + } + } +#else + Py::Module mainmod(PyImport_AddModule((char*)"sip")); + Py::Callable func = mainmod.getDict().getItem("unwrapinstance"); + Py::Tuple arguments(1); + arguments[0] = pyobject; //PyQt pointer + Py::Object result = func.apply(arguments); + void* ptr = PyLong_AsVoidPtr(result.ptr()); + return reinterpret_cast(ptr); +#endif + + return 0; +} + +Py::Object PythonWrapper::toPython(QWidget* widget) +{ + // todo: Port to PySide + Py::Module sipmod(PyImport_AddModule((char*)"sip")); + Py::Callable func = sipmod.getDict().getItem("wrapinstance"); + Py::Tuple arguments(2); + arguments[0] = Py::asObject(PyLong_FromVoidPtr(widget)); + Py::Module qtmod(PyImport_ImportModule((char*)"PyQt4.Qt")); + arguments[1] = qtmod.getDict().getItem("QWidget"); + return func.apply(arguments); +} + +bool PythonWrapper::loadModule() +{ +#if 0 +//#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) + if (SbkPySide_QtCoreTypes) + return true; // already loaded + Shiboken::AutoDecRef requiredModule(Shiboken::Module::import("PySide.QtCore")); + if (requiredModule.isNull()) + return false; + SbkPySide_QtCoreTypes = Shiboken::Module::getTypes(requiredModule); +#endif + return true; +} + +// ---------------------------------------------------- + Gui::WidgetFactoryInst* Gui::WidgetFactoryInst::_pcSingleton = NULL; WidgetFactoryInst& WidgetFactoryInst::instance() @@ -232,23 +304,17 @@ Py::Object UiLoaderPy::repr() Py::Object UiLoaderPy::createWidget(const Py::Tuple& args) { - Py::Module sipmod(PyImport_AddModule((char*)"sip")); - Py::Module qtmod(PyImport_ImportModule((char*)"PyQt4.Qt")); + Gui::PythonWrapper wrap; // 1st argument std::string className = (std::string)Py::String(args[0]); // 2nd argument QWidget* parent = 0; - if (args.size() > 1) { - Py::Callable func = sipmod.getDict().getItem("unwrapinstance"); - Py::Tuple arguments(1); - arguments[0] = args[1]; //PyQt pointer - Py::Object result = func.apply(arguments); - void* ptr = PyLong_AsVoidPtr(result.ptr()); - QObject* object = reinterpret_cast(ptr); - if (object) - parent = qobject_cast(object); + if (wrap.loadModule() && args.size() > 1) { + QObject* object = wrap.toQObject(args[1]); + if (object) + parent = qobject_cast(object); } // 3rd argument @@ -259,11 +325,7 @@ Py::Object UiLoaderPy::createWidget(const Py::Tuple& args) QWidget* widget = loader.createWidget(QString::fromAscii(className.c_str()), parent, QString::fromAscii(objectName.c_str())); - Py::Callable func = sipmod.getDict().getItem("wrapinstance"); - Py::Tuple arguments(2); - arguments[0] = Py::asObject(PyLong_FromVoidPtr(widget)); - arguments[1] = qtmod.getDict().getItem("QWidget"); - return func.apply(arguments); + return wrap.toPython(widget); } // ---------------------------------------------------- diff --git a/src/Gui/WidgetFactory.h b/src/Gui/WidgetFactory.h index 705e4c36b..5442c7efc 100644 --- a/src/Gui/WidgetFactory.h +++ b/src/Gui/WidgetFactory.h @@ -38,6 +38,17 @@ namespace Gui { namespace Dialog{ class PreferencePage; } + +class GuiExport PythonWrapper +{ +public: + PythonWrapper(); + bool loadModule(); + + QObject* toQObject(const Py::Object&); + Py::Object toPython(QWidget*); +}; + /** * The widget factory provides methods for the dynamic creation of widgets. * To create these widgets once they must be registered to the factory. From 2d180fac387d3c4e891c8eeb94541140c5844af2 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sat, 22 Jun 2013 14:48:58 -0300 Subject: [PATCH 108/160] Draft: Removed draftlibs Removed the contents of the draftlibs folder (dxf import-export) for license reasons. These files are now hosted on https://github.com/yorikvanhavre/Draft-dxf-importer and will be downloaded automatically by FreeCAD on first use. --- src/Mod/Draft/draftlibs/__init__.py | 1 - src/Mod/Draft/draftlibs/dxfColorMap.py | 282 ---- src/Mod/Draft/draftlibs/dxfImportObjects.py | 1330 ------------------- src/Mod/Draft/draftlibs/dxfLibrary.py | 896 ------------- src/Mod/Draft/draftlibs/dxfReader.py | 384 ------ src/Mod/Draft/importDXF.py | 22 +- 6 files changed, 17 insertions(+), 2898 deletions(-) delete mode 100644 src/Mod/Draft/draftlibs/__init__.py delete mode 100644 src/Mod/Draft/draftlibs/dxfColorMap.py delete mode 100644 src/Mod/Draft/draftlibs/dxfImportObjects.py delete mode 100644 src/Mod/Draft/draftlibs/dxfLibrary.py delete mode 100644 src/Mod/Draft/draftlibs/dxfReader.py diff --git a/src/Mod/Draft/draftlibs/__init__.py b/src/Mod/Draft/draftlibs/__init__.py deleted file mode 100644 index 0f0a32df1..000000000 --- a/src/Mod/Draft/draftlibs/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# this is the init file of the draftlibs library diff --git a/src/Mod/Draft/draftlibs/dxfColorMap.py b/src/Mod/Draft/draftlibs/dxfColorMap.py deleted file mode 100644 index 66c0bd4e9..000000000 --- a/src/Mod/Draft/draftlibs/dxfColorMap.py +++ /dev/null @@ -1,282 +0,0 @@ -# dictionary mapping AutoCAD color indexes with Blender colors - -# -------------------------------------------------------------------------- -# color_map.py Final by Ed Blake (AKA Kitsu) -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# 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 General Public License for more details. -# -# You should have received a copy of the GNU 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. -# -# ***** END GPL LICENCE BLOCK ***** -# -------------------------------------------------------------------------- - -color_map = { - 0:[0.0, 0.0, 0.0], - 1:[0.99609375, 0.0, 0.0], - 2:[0.99609375, 0.99609375, 0.0], - 3:[0.0, 0.99609375, 0.0], - 4:[0.0, 0.99609375, 0.99609375], - 5:[0.0, 0.0, 0.99609375], - 6:[0.99609375, 0.0, 0.99609375], - 7:[0.99609375, 0.99609375, 0.99609375], - 8:[0.25390625, 0.25390625, 0.25390625], - 9:[0.5, 0.5, 0.5], - 10:[0.99609375, 0.0, 0.0], - 11:[0.99609375, 0.6640625, 0.6640625], - 12:[0.73828125, 0.0, 0.0], - 13:[0.73828125, 0.4921875, 0.4921875], - 14:[0.50390625, 0.0, 0.0], - 15:[0.50390625, 0.3359375, 0.3359375], - 16:[0.40625, 0.0, 0.0], - 17:[0.40625, 0.26953125, 0.26953125], - 18:[0.30859375, 0.0, 0.0], - 19:[0.30859375, 0.20703125, 0.20703125], - 20:[0.99609375, 0.24609375, 0.0], - 21:[0.99609375, 0.74609375, 0.6640625], - 22:[0.73828125, 0.1796875, 0.0], - 23:[0.73828125, 0.55078125, 0.4921875], - 24:[0.50390625, 0.12109375, 0.0], - 25:[0.50390625, 0.375, 0.3359375], - 26:[0.40625, 0.09765625, 0.0], - 27:[0.40625, 0.3046875, 0.26953125], - 28:[0.30859375, 0.07421875, 0.0], - 29:[0.30859375, 0.23046875, 0.20703125], - 30:[0.99609375, 0.49609375, 0.0], - 31:[0.99609375, 0.828125, 0.6640625], - 32:[0.73828125, 0.3671875, 0.0], - 33:[0.73828125, 0.61328125, 0.4921875], - 34:[0.50390625, 0.25, 0.0], - 35:[0.50390625, 0.41796875, 0.3359375], - 36:[0.40625, 0.203125, 0.0], - 37:[0.40625, 0.3359375, 0.26953125], - 38:[0.30859375, 0.15234375, 0.0], - 39:[0.30859375, 0.2578125, 0.20703125], - 40:[0.99609375, 0.74609375, 0.0], - 41:[0.99609375, 0.9140625, 0.6640625], - 42:[0.73828125, 0.55078125, 0.0], - 43:[0.73828125, 0.67578125, 0.4921875], - 44:[0.50390625, 0.375, 0.0], - 45:[0.50390625, 0.4609375, 0.3359375], - 46:[0.40625, 0.3046875, 0.0], - 47:[0.40625, 0.37109375, 0.26953125], - 48:[0.30859375, 0.23046875, 0.0], - 49:[0.30859375, 0.28515625, 0.20703125], - 50:[0.99609375, 0.99609375, 0.0], - 51:[0.99609375, 0.99609375, 0.6640625], - 52:[0.73828125, 0.73828125, 0.0], - 53:[0.73828125, 0.73828125, 0.4921875], - 54:[0.50390625, 0.50390625, 0.0], - 55:[0.50390625, 0.50390625, 0.3359375], - 56:[0.40625, 0.40625, 0.0], - 57:[0.40625, 0.40625, 0.26953125], - 58:[0.30859375, 0.30859375, 0.0], - 59:[0.30859375, 0.30859375, 0.20703125], - 60:[0.74609375, 0.99609375, 0.0], - 61:[0.9140625, 0.99609375, 0.6640625], - 62:[0.55078125, 0.73828125, 0.0], - 63:[0.67578125, 0.73828125, 0.4921875], - 64:[0.375, 0.50390625, 0.0], - 65:[0.4609375, 0.50390625, 0.3359375], - 66:[0.3046875, 0.40625, 0.0], - 67:[0.37109375, 0.40625, 0.26953125], - 68:[0.23046875, 0.30859375, 0.0], - 69:[0.28515625, 0.30859375, 0.20703125], - 70:[0.49609375, 0.99609375, 0.0], - 71:[0.828125, 0.99609375, 0.6640625], - 72:[0.3671875, 0.73828125, 0.0], - 73:[0.61328125, 0.73828125, 0.4921875], - 74:[0.25, 0.50390625, 0.0], - 75:[0.41796875, 0.50390625, 0.3359375], - 76:[0.203125, 0.40625, 0.0], - 77:[0.3359375, 0.40625, 0.26953125], - 78:[0.15234375, 0.30859375, 0.0], - 79:[0.2578125, 0.30859375, 0.20703125], - 80:[0.24609375, 0.99609375, 0.0], - 81:[0.74609375, 0.99609375, 0.6640625], - 82:[0.1796875, 0.73828125, 0.0], - 83:[0.55078125, 0.73828125, 0.4921875], - 84:[0.12109375, 0.50390625, 0.0], - 85:[0.375, 0.50390625, 0.3359375], - 86:[0.09765625, 0.40625, 0.0], - 87:[0.3046875, 0.40625, 0.26953125], - 88:[0.07421875, 0.30859375, 0.0], - 89:[0.23046875, 0.30859375, 0.20703125], - 90:[0.0, 0.99609375, 0.0], - 91:[0.6640625, 0.99609375, 0.6640625], - 92:[0.0, 0.73828125, 0.0], - 93:[0.4921875, 0.73828125, 0.4921875], - 94:[0.0, 0.50390625, 0.0], - 95:[0.3359375, 0.50390625, 0.3359375], - 96:[0.0, 0.40625, 0.0], - 97:[0.26953125, 0.40625, 0.26953125], - 98:[0.0, 0.30859375, 0.0], - 99:[0.20703125, 0.30859375, 0.20703125], - 100:[0.0, 0.99609375, 0.24609375], - 101:[0.6640625, 0.99609375, 0.74609375], - 102:[0.0, 0.73828125, 0.1796875], - 103:[0.4921875, 0.73828125, 0.55078125], - 104:[0.0, 0.50390625, 0.12109375], - 105:[0.3359375, 0.50390625, 0.375], - 106:[0.0, 0.40625, 0.09765625], - 107:[0.26953125, 0.40625, 0.3046875], - 108:[0.0, 0.30859375, 0.07421875], - 109:[0.20703125, 0.30859375, 0.23046875], - 110:[0.0, 0.99609375, 0.49609375], - 111:[0.6640625, 0.99609375, 0.828125], - 112:[0.0, 0.73828125, 0.3671875], - 113:[0.4921875, 0.73828125, 0.61328125], - 114:[0.0, 0.50390625, 0.25], - 115:[0.3359375, 0.50390625, 0.41796875], - 116:[0.0, 0.40625, 0.203125], - 117:[0.26953125, 0.40625, 0.3359375], - 118:[0.0, 0.30859375, 0.15234375], - 119:[0.20703125, 0.30859375, 0.2578125], - 120:[0.0, 0.99609375, 0.74609375], - 121:[0.6640625, 0.99609375, 0.9140625], - 122:[0.0, 0.73828125, 0.55078125], - 123:[0.4921875, 0.73828125, 0.67578125], - 124:[0.0, 0.50390625, 0.375], - 125:[0.3359375, 0.50390625, 0.4609375], - 126:[0.0, 0.40625, 0.3046875], - 127:[0.26953125, 0.40625, 0.37109375], - 128:[0.0, 0.30859375, 0.23046875], - 129:[0.20703125, 0.30859375, 0.28515625], - 130:[0.0, 0.99609375, 0.99609375], - 131:[0.6640625, 0.99609375, 0.99609375], - 132:[0.0, 0.73828125, 0.73828125], - 133:[0.4921875, 0.73828125, 0.73828125], - 134:[0.0, 0.50390625, 0.50390625], - 135:[0.3359375, 0.50390625, 0.50390625], - 136:[0.0, 0.40625, 0.40625], - 137:[0.26953125, 0.40625, 0.40625], - 138:[0.0, 0.30859375, 0.30859375], - 139:[0.20703125, 0.30859375, 0.30859375], - 140:[0.0, 0.74609375, 0.99609375], - 141:[0.6640625, 0.9140625, 0.99609375], - 142:[0.0, 0.55078125, 0.73828125], - 143:[0.4921875, 0.67578125, 0.73828125], - 144:[0.0, 0.375, 0.50390625], - 145:[0.3359375, 0.4609375, 0.50390625], - 146:[0.0, 0.3046875, 0.40625], - 147:[0.26953125, 0.37109375, 0.40625], - 148:[0.0, 0.23046875, 0.30859375], - 149:[0.20703125, 0.28515625, 0.30859375], - 150:[0.0, 0.49609375, 0.99609375], - 151:[0.6640625, 0.828125, 0.99609375], - 152:[0.0, 0.3671875, 0.73828125], - 153:[0.4921875, 0.61328125, 0.73828125], - 154:[0.0, 0.25, 0.50390625], - 155:[0.3359375, 0.41796875, 0.50390625], - 156:[0.0, 0.203125, 0.40625], - 157:[0.26953125, 0.3359375, 0.40625], - 158:[0.0, 0.15234375, 0.30859375], - 159:[0.20703125, 0.2578125, 0.30859375], - 160:[0.0, 0.24609375, 0.99609375], - 161:[0.6640625, 0.74609375, 0.99609375], - 162:[0.0, 0.1796875, 0.73828125], - 163:[0.4921875, 0.55078125, 0.73828125], - 164:[0.0, 0.12109375, 0.50390625], - 165:[0.3359375, 0.375, 0.50390625], - 166:[0.0, 0.09765625, 0.40625], - 167:[0.26953125, 0.3046875, 0.40625], - 168:[0.0, 0.07421875, 0.30859375], - 169:[0.20703125, 0.23046875, 0.30859375], - 170:[0.0, 0.0, 0.99609375], - 171:[0.6640625, 0.6640625, 0.99609375], - 172:[0.0, 0.0, 0.73828125], - 173:[0.4921875, 0.4921875, 0.73828125], - 174:[0.0, 0.0, 0.50390625], - 175:[0.3359375, 0.3359375, 0.50390625], - 176:[0.0, 0.0, 0.40625], - 177:[0.26953125, 0.26953125, 0.40625], - 178:[0.0, 0.0, 0.30859375], - 179:[0.20703125, 0.20703125, 0.30859375], - 180:[0.24609375, 0.0, 0.99609375], - 181:[0.74609375, 0.6640625, 0.99609375], - 182:[0.1796875, 0.0, 0.73828125], - 183:[0.55078125, 0.4921875, 0.73828125], - 184:[0.12109375, 0.0, 0.50390625], - 185:[0.375, 0.3359375, 0.50390625], - 186:[0.09765625, 0.0, 0.40625], - 187:[0.3046875, 0.26953125, 0.40625], - 188:[0.07421875, 0.0, 0.30859375], - 189:[0.23046875, 0.20703125, 0.30859375], - 190:[0.49609375, 0.0, 0.99609375], - 191:[0.828125, 0.6640625, 0.99609375], - 192:[0.3671875, 0.0, 0.73828125], - 193:[0.61328125, 0.4921875, 0.73828125], - 194:[0.25, 0.0, 0.50390625], - 195:[0.41796875, 0.3359375, 0.50390625], - 196:[0.203125, 0.0, 0.40625], - 197:[0.3359375, 0.26953125, 0.40625], - 198:[0.15234375, 0.0, 0.30859375], - 199:[0.2578125, 0.20703125, 0.30859375], - 200:[0.74609375, 0.0, 0.99609375], - 201:[0.9140625, 0.6640625, 0.99609375], - 202:[0.55078125, 0.0, 0.73828125], - 203:[0.67578125, 0.4921875, 0.73828125], - 204:[0.375, 0.0, 0.50390625], - 205:[0.4609375, 0.3359375, 0.50390625], - 206:[0.3046875, 0.0, 0.40625], - 207:[0.37109375, 0.26953125, 0.40625], - 208:[0.23046875, 0.0, 0.30859375], - 209:[0.28515625, 0.20703125, 0.30859375], - 210:[0.99609375, 0.0, 0.99609375], - 211:[0.99609375, 0.6640625, 0.99609375], - 212:[0.73828125, 0.0, 0.73828125], - 213:[0.73828125, 0.4921875, 0.73828125], - 214:[0.50390625, 0.0, 0.50390625], - 215:[0.50390625, 0.3359375, 0.50390625], - 216:[0.40625, 0.0, 0.40625], - 217:[0.40625, 0.26953125, 0.40625], - 218:[0.30859375, 0.0, 0.30859375], - 219:[0.30859375, 0.20703125, 0.30859375], - 220:[0.99609375, 0.0, 0.74609375], - 221:[0.99609375, 0.6640625, 0.9140625], - 222:[0.73828125, 0.0, 0.55078125], - 223:[0.73828125, 0.4921875, 0.67578125], - 224:[0.50390625, 0.0, 0.375], - 225:[0.50390625, 0.3359375, 0.4609375], - 226:[0.40625, 0.0, 0.3046875], - 227:[0.40625, 0.26953125, 0.37109375], - 228:[0.30859375, 0.0, 0.23046875], - 229:[0.30859375, 0.20703125, 0.28515625], - 230:[0.99609375, 0.0, 0.49609375], - 231:[0.99609375, 0.6640625, 0.828125], - 232:[0.73828125, 0.0, 0.3671875], - 233:[0.73828125, 0.4921875, 0.61328125], - 234:[0.50390625, 0.0, 0.25], - 235:[0.50390625, 0.3359375, 0.41796875], - 236:[0.40625, 0.0, 0.203125], - 237:[0.40625, 0.26953125, 0.3359375], - 238:[0.30859375, 0.0, 0.15234375], - 239:[0.30859375, 0.20703125, 0.2578125], - 240:[0.99609375, 0.0, 0.24609375], - 241:[0.99609375, 0.6640625, 0.74609375], - 242:[0.73828125, 0.0, 0.1796875], - 243:[0.73828125, 0.4921875, 0.55078125], - 244:[0.50390625, 0.0, 0.12109375], - 245:[0.50390625, 0.3359375, 0.375], - 246:[0.40625, 0.0, 0.09765625], - 247:[0.40625, 0.26953125, 0.3046875], - 248:[0.30859375, 0.0, 0.07421875], - 249:[0.30859375, 0.20703125, 0.23046875], - 250:[0.19921875, 0.19921875, 0.19921875], - 251:[0.3125, 0.3125, 0.3125], - 252:[0.41015625, 0.41015625, 0.41015625], - 253:[0.5078125, 0.5078125, 0.5078125], - 254:[0.7421875, 0.7421875, 0.7421875], - 255:[0.99609375, 0.99609375, 0.99609375], -} diff --git a/src/Mod/Draft/draftlibs/dxfImportObjects.py b/src/Mod/Draft/draftlibs/dxfImportObjects.py deleted file mode 100644 index 27406b819..000000000 --- a/src/Mod/Draft/draftlibs/dxfImportObjects.py +++ /dev/null @@ -1,1330 +0,0 @@ -"""This module provides wrapper objects for dxf entities. - - The wrappers expect a "dxf object" as input. The dxf object is - an object with a type and a data attribute. Type is a lowercase - string matching the 0 code of a dxf entity. Data is a list containing - dxf objects or lists of [code, data] pairs. - - This module is not general, and is only for dxf import. -""" - -# -------------------------------------------------------------------------- -# DXF Import Objects v0.8 by Ed Blake (AKA Kitsu) -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# 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 General Public License for more details. -# -# You should have received a copy of the GNU 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. -# -# ***** END GPL LICENCE BLOCK ***** -# -------------------------------------------------------------------------- -from math import * - - -# from Stani's dxf writer v1.1 (c)www.stani.be (GPL) -#---color values -BYBLOCK=0 -BYLAYER=256 - -#---block-type flags (bit coded values, may be combined): -ANONYMOUS =1 # This is an anonymous block generated by hatching, associative dimensioning, other internal operations, or an application -NON_CONSTANT_ATTRIBUTES =2 # This block has non-constant attribute definitions (this bit is not set if the block has any attribute definitions that are constant, or has no attribute definitions at all) -XREF =4 # This block is an external reference (xref) -XREF_OVERLAY =8 # This block is an xref overlay -EXTERNAL =16 # This block is externally dependent -RESOLVED =32 # This is a resolved external reference, or dependent of an external reference (ignored on input) -REFERENCED =64 # This definition is a referenced external reference (ignored on input) - -#---mtext flags -#attachment point -TOP_LEFT = 1 -TOP_CENTER = 2 -TOP_RIGHT = 3 -MIDDLE_LEFT = 4 -MIDDLE_CENTER = 5 -MIDDLE_RIGHT = 6 -BOTTOM_LEFT = 7 -BOTTOM_CENTER = 8 -BOTTOM_RIGHT = 9 -#drawing direction -LEFT_RIGHT = 1 -TOP_BOTTOM = 3 -BY_STYLE = 5 #the flow direction is inherited from the associated text style -#line spacing style (optional): -AT_LEAST = 1 #taller characters will override -EXACT = 2 #taller characters will not override - -#---polyline flags -CLOSED =1 # This is a closed polyline (or a polygon mesh closed in the M direction) -CURVE_FIT =2 # Curve-fit vertices have been added -SPLINE_FIT =4 # Spline-fit vertices have been added -POLYLINE_3D =8 # This is a 3D polyline -POLYGON_MESH =16 # This is a 3D polygon mesh -CLOSED_N =32 # The polygon mesh is closed in the N direction -POLYFACE_MESH =64 # The polyline is a polyface mesh -CONTINOUS_LINETYPE_PATTERN =128 # The linetype pattern is generated continuously around the vertices of this polyline - -#---text flags -#horizontal -LEFT = 0 -CENTER = 1 -RIGHT = 2 -ALIGNED = 3 #if vertical alignment = 0 -MIDDLE = 4 #if vertical alignment = 0 -FIT = 5 #if vertical alignment = 0 -#vertical -BASELINE = 0 -BOTTOM = 1 -MIDDLE = 2 -TOP = 3 -class Object: - """Empty container class for dxf objects""" - - def __init__(self, _type=''): - """_type expects a string value.""" - self.type = _type - self.name = '' - self.data = [] - - def __str__(self): - if self.name: - return self.name - else: - return self.type - - def __repr__(self): - return str(self.data) - - def get_type(self, kind=''): - """Despite the name, this method actually returns all objects of type 'kind' from self.data.""" - if type: - objects = [] - for item in self.data: - if type(item) != list and item.type == kind: - # we want this type of object - objects.append(item) - elif type(item) == list and item[0] == kind: - # we want this type of data - objects.append(item[1]) - return objects - - -class Layer: - """Class for objects representing dxf layers.""" - - def __init__(self, obj): - """Expects an entity object of type line as input.""" - self.type = obj.type - self.data = obj.data[:] - - self.name = obj.get_type(2)[0] - self.color = obj.get_type(62)[0] - self.flags = obj.get_type(70)[0] - self.frozen = self.flags&1 - - - - def __repr__(self): - return "%s: name - %s, color - %s" %(self.__class__.__name__, self.name, self.color) - - - -class Line: - """Class for objects representing dxf lines.""" - - def __init__(self, obj): - """Expects an entity object of type line as input.""" - if not obj.type == 'line': - raise TypeError, "Wrong type %s for line object!" %obj.type - self.type = obj.type - self.data = obj.data[:] - - self.space = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - - self.points = self.get_points(obj.data) - - - - - def get_points(self, data): - """Gets start and end points for a line type object. - - Lines have a fixed number of points (two) and fixed codes for each value. - """ - - # start x, y, z and end x, y, z = 0 - sx, sy, sz, ex, ey, ez = 0, 0, 0, 0, 0, 0 - for item in data: - if item[0] == 10: # 10 = x - sx = item[1] - elif item[0] == 20: # 20 = y - sy = item[1] - elif item[0] == 30: # 30 = z - sz = item[1] - elif item[0] == 11: # 11 = x - ex = item[1] - elif item[0] == 21: # 21 = y - ey = item[1] - elif item[0] == 31: # 31 = z - ez = item[1] - return [[sx, sy, sz], [ex, ey, ez]] - - - - def __repr__(self): - return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) - - - -class LWpolyline: - """Class for objects representing dxf LWpolylines.""" - - def __init__(self, obj): - """Expects an entity object of type lwpolyline as input.""" - if not obj.type == 'lwpolyline': - raise TypeError, "Wrong type %s for polyline object!" %obj.type - self.type = obj.type - self.data = obj.data[:] - - # required data - self.num_points = obj.get_type(90)[0] - - # optional data (with defaults) - self.space = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - self.elevation = obj.get_type(38) - if self.elevation: - self.elevation = self.elevation[0] - else: - self.elevation = 0 - - self.flags = obj.get_type(70) - if self.flags: - self.flags = self.flags[0] - else: - self.flags = 0 - - self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.points = self.get_points(obj.data) - self.extrusion = self.get_extrusion(obj.data) - - - - - - - def get_points(self, data): - """Gets points for a polyline type object. - - Polylines have no fixed number of verts, and - each vert can have a number of properties. - Verts should be coded as - 10:xvalue - 20:yvalue - 40:startwidth or 0 - 41:endwidth or 0 - 42:bulge or 0 - for each vert - """ - num = self.num_points - point = None - points = [] - for item in data: - if item[0] == 10: # 10 = x - if point: - points.append(point) - point = Vertex() - point.x = item[1] - elif item[0] == 20: # 20 = y - point.y = item[1] - elif item[0] == 40: # 40 = start width - point.swidth = item[1] - elif item[0] == 41: # 41 = end width - point.ewidth = item[1] - elif item[0] == 42: # 42 = bulge - point.bulge = item[1] - points.append(point) - return points - - - def get_extrusion(self, data): - """Find the axis of extrusion. - - Used to get the objects Object Coordinate System (ocs). - """ - vec = [0,0,1] - for item in data: - if item[0] == 210: # 210 = x - vec[0] = item[1] - elif item[0] == 220: # 220 = y - vec[1] = item[1] - elif item[0] == 230: # 230 = z - vec[2] = item[1] - return vec - - - def __repr__(self): - return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) - - - -class Polyline: - """Class for objects representing dxf LWpolylines.""" - - def __init__(self, obj): - """Expects an entity object of type polyline as input.""" - if not obj.type == 'polyline': - raise TypeError, "Wrong type %s for polyline object!" %obj.type - self.type = obj.type - self.data = obj.data[:] - self.points = [] - - # optional data (with defaults) - self.space = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - self.elevation = obj.get_type(30) - if self.elevation: - self.elevation = self.elevation[0] - else: - self.elevation = 0 - - self.flags = obj.get_type(70) - if self.flags: - self.flags = self.flags[0] - else: - self.flags = 0 - - self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.extrusion = self.get_extrusion(obj.data) - - - - - - def get_extrusion(self, data): - """Find the axis of extrusion. - - Used to get the objects Object Coordinate System (ocs). - """ - vec = [0,0,1] - for item in data: - if item[0] == 210: # 210 = x - vec[0] = item[1] - elif item[0] == 220: # 220 = y - vec[1] = item[1] - elif item[0] == 230: # 230 = z - vec[2] = item[1] - return vec - - - def __repr__(self): - return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) - - - -class Vertex(object): - """Generic vertex object used by polylines (and maybe others).""" - - def __init__(self, obj=None): - """Initializes vertex data. - - The optional obj arg is an entity object of type vertex. - """ - self.loc = [0,0,0] - self.bulge = 0 - self.swidth = 0 - self.ewidth = 0 - self.flags = 0 - - if obj is not None: - if not obj.type == 'vertex': - raise TypeError, "Wrong type %s for vertex object!" %obj.type - self.type = obj.type - self.data = obj.data[:] - - self.get_props(obj.data) - - - def get_props(self, data): - """Gets coords for a vertex type object. - - Each vert can have a number of properties. - Verts should be coded as - 10:xvalue - 20:yvalue - 40:startwidth or 0 - 41:endwidth or 0 - 42:bulge or 0 - """ - for item in data: - if item[0] == 10: # 10 = x - self.x = item[1] - elif item[0] == 20: # 20 = y - self.y = item[1] - elif item[0] == 30: # 30 = z - self.z = item[1] - elif item[0] == 40: # 40 = start width - self.swidth = item[1] - elif item[0] == 41: # 41 = end width - self.ewidth = item[1] - elif item[0] == 42: # 42 = bulge - self.bulge = item[1] - elif item[0] == 70: # 70 = vert flags - self.flags = item[1] - - - def __len__(self): - return 3 - - - def __getitem__(self, key): - return self.loc[key] - - - def __setitem__(self, key, value): - if key in [0,1,2]: - self.loc[key] - - - def __iter__(self): - return self.loc.__iter__() - - - def __str__(self): - return str(self.loc) - - - def __repr__(self): - return "Vertex %s, swidth=%s, ewidth=%s, bulge=%s" %(self.loc, self.swidth, self.ewidth, self.bulge) - - - def getx(self): - return self.loc[0] - - def setx(self, value): - self.loc[0] = value - - x = property(getx, setx) - - - def gety(self): - return self.loc[1] - - def sety(self, value): - self.loc[1] = value - - y = property(gety, sety) - - - def getz(self): - return self.loc[2] - - def setz(self, value): - self.loc[2] = value - - z = property(getz, setz) - - - -class Text: - """Class for objects representing dxf Text.""" - - def __init__(self, obj): - """Expects an entity object of type text as input.""" - if not obj.type == 'text': - raise TypeError, "Wrong type %s for text object!" %obj.type - self.type = obj.type - self.data = obj.data[:] - - # required data - self.height = obj.get_type(40)[0] - self.value = obj.get_type(1)[0] # The text string value - - # optional data (with defaults) - self.space = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - self.rotation = obj.get_type(50) # radians? - if not self.rotation: - self.rotation = 0 - else: - self.rotation = self.rotation[0] - - self.width_factor = obj.get_type(41) # Scaling factor along local x axis - if not self.width_factor: - self.width_factor = 1 - else: - self.width_factor = self.width_factor[0] - - self.oblique = obj.get_type(51) # skew in degrees -90 <= oblique <= 90 - if not self.oblique: - self.oblique = 0 - else: - self.oblique = self.oblique[0] - - self.halignment = obj.get_type(72) # horiz. alignment - if not self.halignment: # 0=left, 1=center, 2=right, 3=aligned, 4=middle, 5=fit - self.halignment = 0 - else: - self.halignment = self.halignment[0] - - self.valignment = obj.get_type(73) # vert. alignment - if not self.valignment: # 0=baseline, 1=bottom, 2=middle, 3=top - self.valignment = 0 - else: - self.valignment = self.valignment[0] - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.loc = self.get_loc(obj.data, self.halignment, self.valignment) - self.extrusion = self.get_extrusion(obj.data) - - - - - def get_loc(self, data, halign, valign): - """Gets adjusted location for text type objects. - - If group 72 and/or 73 values are nonzero then the first alignment point values - are ignored and AutoCAD calculates new values based on the second alignment - point and the length and height of the text string itself (after applying the - text style). If the 72 and 73 values are zero or missing, then the second - alignment point is meaningless. - - I don't know how to calc text size... - """ - # bottom left x, y, z and justification x, y, z = 0 - x, y, z, jx, jy, jz = 0, 0, 0, 0, 0, 0 - for item in data: - if item[0] == 10: # 10 = x - x = item[1] - elif item[0] == 20: # 20 = y - y = item[1] - elif item[0] == 30: # 30 = z - z = item[1] - elif item[0] == 11: # 11 = x - jx = item[1] - elif item[0] == 21: # 21 = y - jy = item[1] - elif item[0] == 31: # 31 = z - jz = item[1] - - if halign or valign: - x, y, z = jx, jy, jz - return [x, y, z] - - def get_extrusion(self, data): - """Find the axis of extrusion. - - Used to get the objects Object Coordinate System (ocs). - """ - vec = [0,0,1] - for item in data: - if item[0] == 210: # 210 = x - vec[0] = item[1] - elif item[0] == 220: # 220 = y - vec[1] = item[1] - elif item[0] == 230: # 230 = z - vec[2] = item[1] - return vec - - - def __repr__(self): - return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value) - - - -class Mtext: - """Class for objects representing dxf Mtext.""" - - def __init__(self, obj): - """Expects an entity object of type mtext as input.""" - if not obj.type == 'mtext': - raise TypeError, "Wrong type %s for mtext object!" %obj.type - self.type = obj.type - self.data = obj.data[:] - - # required data - self.height = obj.get_type(40)[0] - self.width = obj.get_type(41)[0] - self.alignment = obj.get_type(71)[0] # alignment 1=TL, 2=TC, 3=TR, 4=ML, 5=MC, 6=MR, 7=BL, 8=BC, 9=BR - self.value = self.get_text(obj.data) # The text string value - - # optional data (with defaults) - self.space = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - self.rotation = obj.get_type(50) # radians - if not self.rotation: - self.rotation = 0 - else: - self.rotation = self.rotation[0] - - self.width_factor = obj.get_type(42) # Scaling factor along local x axis - if not self.width_factor: - self.width_factor = 1 - else: - self.width_factor = self.width_factor[0] - - self.line_space = obj.get_type(44) # percentage of default - if not self.line_space: - self.line_space = 1 - else: - self.line_space = self.line_space[0] - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.loc = self.get_loc(obj.data) - self.extrusion = self.get_extrusion(obj.data) - - - - - - def get_text(self, data): - """Reconstructs mtext data from dxf codes.""" - primary = '' - secondary = [] - for item in data: - if item[0] == 1: # There should be only one primary... - primary = item[1] - elif item[0] == 3: # There may be any number of extra strings (in order) - secondary.append(item[1]) - if not primary: - #raise ValueError, "Empty Mtext Object!" - string = "Empty Mtext Object!" - if not secondary: - string = primary.replace(r'\P', '\n') - else: - string = ''.join(secondary)+primary - string = string.replace(r'\P', '\n') - return string - def get_loc(self, data): - """Gets location for a mtext type objects. - - Mtext objects have only one point indicating location. - """ - loc = [0,0,0] - for item in data: - if item[0] == 10: # 10 = x - loc[0] = item[1] - elif item[0] == 20: # 20 = y - loc[1] = item[1] - elif item[0] == 30: # 30 = z - loc[2] = item[1] - return loc - - - - - def get_extrusion(self, data): - """Find the axis of extrusion. - - Used to get the objects Object Coordinate System (ocs). - """ - vec = [0,0,1] - for item in data: - if item[0] == 210: # 210 = x - vec[0] = item[1] - elif item[0] == 220: # 220 = y - vec[1] = item[1] - elif item[0] == 230: # 230 = z - vec[2] = item[1] - return vec - - - def __repr__(self): - return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value) - - - -class Circle: - """Class for objects representing dxf Circles.""" - - def __init__(self, obj): - """Expects an entity object of type circle as input.""" - if not obj.type == 'circle': - raise TypeError, "Wrong type %s for circle object!" %obj.type - self.type = obj.type - self.data = obj.data[:] - - # required data - self.radius = obj.get_type(40)[0] - - # optional data (with defaults) - self.space = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.loc = self.get_loc(obj.data) - self.extrusion = self.get_extrusion(obj.data) - - - - - - def get_loc(self, data): - """Gets the center location for circle type objects. - - Circles have a single coord location. - """ - loc = [0, 0, 0] - for item in data: - if item[0] == 10: # 10 = x - loc[0] = item[1] - elif item[0] == 20: # 20 = y - loc[1] = item[1] - elif item[0] == 30: # 30 = z - loc[2] = item[1] - return loc - - - - def get_extrusion(self, data): - """Find the axis of extrusion. - - Used to get the objects Object Coordinate System (ocs). - """ - vec = [0,0,1] - for item in data: - if item[0] == 210: # 210 = x - vec[0] = item[1] - elif item[0] == 220: # 220 = y - vec[1] = item[1] - elif item[0] == 230: # 230 = z - vec[2] = item[1] - return vec - - - def __repr__(self): - return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) - - - -class Arc: - """Class for objects representing dxf arcs.""" - - def __init__(self, obj): - """Expects an entity object of type arc as input.""" - if not obj.type == 'arc': - raise TypeError, "Wrong type %s for arc object!" %obj.type - self.type = obj.type - self.data = obj.data[:] - - # required data - self.radius = obj.get_type(40)[0] - self.start_angle = obj.get_type(50)[0] - self.end_angle = obj.get_type(51)[0] - - # optional data (with defaults) - self.space = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.loc = self.get_loc(obj.data) - self.extrusion = self.get_extrusion(obj.data) - - - - - - def get_loc(self, data): - """Gets the center location for arc type objects. - - Arcs have a single coord location. - """ - loc = [0, 0, 0] - for item in data: - if item[0] == 10: # 10 = x - loc[0] = item[1] - elif item[0] == 20: # 20 = y - loc[1] = item[1] - elif item[0] == 30: # 30 = z - loc[2] = item[1] - return loc - - - - def get_extrusion(self, data): - """Find the axis of extrusion. - - Used to get the objects Object Coordinate System (ocs). - """ - vec = [0,0,1] - for item in data: - if item[0] == 210: # 210 = x - vec[0] = item[1] - elif item[0] == 220: # 220 = y - vec[1] = item[1] - elif item[0] == 230: # 230 = z - vec[2] = item[1] - return vec - - - def __repr__(self): - return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) - - - -class BlockRecord: - """Class for objects representing dxf block_records.""" - - def __init__(self, obj): - """Expects an entity object of type block_record as input.""" - if not obj.type == 'block_record': - raise TypeError, "Wrong type %s for block_record object!" %obj.type - self.type = obj.type - self.data = obj.data[:] - - # required data - self.name = obj.get_type(2)[0] - - # optional data (with defaults) - self.insertion_units = obj.get_type(70) - if not self.insertion_units: - self.insertion_units = None - else: - self.insertion_units = self.insertion_units[0] - - self.insert_units = obj.get_type(1070) - if not self.insert_units: - self.insert_units = None - else: - self.insert_units = self.insert_units[0] - - - - - - - def __repr__(self): - return "%s: name - %s, insert units - %s" %(self.__class__.__name__, self.name, self.insertion_units) - - - - -class Block: - """Class for objects representing dxf blocks.""" - - def __init__(self, obj): - """Expects an entity object of type block as input.""" - if not obj.type == 'block': - raise TypeError, "Wrong type %s for block object!" %obj.type - self.type = obj.type - self.data = obj.data[:] - - # required data - self.flags = obj.get_type(70)[0] - self.entities = Object('block_contents') - self.entities.data = objectify([ent for ent in obj.data if type(ent) != list]) - - # optional data (with defaults) - self.name = obj.get_type(3) - if self.name: - self.name = self.name[0] - else: - self.name = obj.get_type(2) - if self.name: - self.name = self.name[0] - else: - self.name = 'blank' - - self.path = obj.get_type(1) - if self.path: - self.path = self.path[0] - else: - self.path = '' - - self.discription = obj.get_type(4) - if self.discription: - self.discription = self.discription[0] - else: - self.discription = '' - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.loc = self.get_loc(obj.data) - - - - - - def get_loc(self, data): - """Gets the insert point of the block.""" - loc = [0, 0, 0] - for item in data: - if type(item) != list: - continue - if item[0] == 10: # 10 = x - loc[0] = item[1] - elif item[0] == 20: # 20 = y - loc[1] = item[1] - elif item[0] == 30: # 30 = z - loc[2] = item[1] - return loc - - - - def __repr__(self): - return "%s: name - %s, description - %s, xref-path - %s" %(self.__class__.__name__, self.name, self.discription, self.path) - - - - -class Insert: - """Class for objects representing dxf inserts.""" - - def __init__(self, obj): - """Expects an entity object of type insert as input.""" - if not obj.type == 'insert': - raise TypeError, "Wrong type %s for insert object!" %obj.type - self.type = obj.type - self.data = obj.data[:] - - # required data - self.block = obj.get_type(2)[0] - - # optional data (with defaults) - self.rotation = obj.get_type(50) - if self.rotation: - self.rotation = self.rotation[0] - else: - self.rotation = 0 - - self.space = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.loc = self.get_loc(obj.data) - self.scale = self.get_scale(obj.data) - self.rows, self.columns = self.get_array(obj.data) - self.extrusion = self.get_extrusion(obj.data) - - - - - - def get_loc(self, data): - """Gets the center location for circle type objects. - - Circles have a single coord location. - """ - loc = [0, 0, 0] - for item in data: - if item[0] == 10: # 10 = x - loc[0] = item[1] - elif item[0] == 20: # 20 = y - loc[1] = item[1] - elif item[0] == 30: # 30 = z - loc[2] = item[1] - return loc - - - - def get_scale(self, data): - """Gets the x/y/z scale factor for the block. - """ - scale = [1, 1, 1] - for item in data: - if item[0] == 41: # 41 = x scale - scale[0] = item[1] - elif item[0] == 42: # 42 = y scale - scale[1] = item[1] - elif item[0] == 43: # 43 = z scale - scale[2] = item[1] - return scale - - - - def get_array(self, data): - """Returns the pair (row number, row spacing), (column number, column spacing).""" - columns = 1 - rows = 1 - cspace = 0 - rspace = 0 - for item in data: - if item[0] == 70: # 70 = columns - columns = item[1] - elif item[0] == 71: # 71 = rows - rows = item[1] - if item[0] == 44: # 44 = columns - cspace = item[1] - elif item[0] == 45: # 45 = rows - rspace = item[1] - return (rows, rspace), (columns, cspace) - - - - def get_extrusion(self, data): - """Find the axis of extrusion. - - Used to get the objects Object Coordinate System (ocs). - """ - vec = [0,0,1] - for item in data: - if item[0] == 210: # 210 = x - vec[0] = item[1] - elif item[0] == 220: # 220 = y - vec[1] = item[1] - elif item[0] == 230: # 230 = z - vec[2] = item[1] - return vec - - - def __repr__(self): - return "%s: layer - %s, block - %s" %(self.__class__.__name__, self.layer, self.block) - - - - -class Ellipse: - """Class for objects representing dxf ellipses.""" - - def __init__(self, obj): - """Expects an entity object of type ellipse as input.""" - if not obj.type == 'ellipse': - raise TypeError, "Wrong type %s for ellipse object!" %obj.type - self.type = obj.type - self.data = obj.data[:] - - # required data - self.ratio = obj.get_type(40)[0] - self.start_angle = obj.get_type(41)[0] - self.end_angle = obj.get_type(42)[0] - - # optional data (with defaults) - self.space = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.loc = self.get_loc(obj.data) - self.major = self.get_major(obj.data) - self.extrusion = self.get_extrusion(obj.data) - self.radius = sqrt(self.major[0]**2 + self.major[0]**2 + self.major[0]**2) - - - - - def get_loc(self, data): - """Gets the center location for arc type objects. - - Arcs have a single coord location. - """ - loc = [0, 0, 0] - for item in data: - if item[0] == 10: # 10 = x - loc[0] = item[1] - elif item[0] == 20: # 20 = y - loc[1] = item[1] - elif item[0] == 30: # 30 = z - loc[2] = item[1] - return loc - - - - def get_major(self, data): - """Gets the major axis for ellipse type objects. - - The ellipse major axis defines the rotation of the ellipse and its radius. - """ - loc = [0, 0, 0] - for item in data: - if item[0] == 11: # 11 = x - loc[0] = item[1] - elif item[0] == 21: # 21 = y - loc[1] = item[1] - elif item[0] == 31: # 31 = z - loc[2] = item[1] - return loc - - - - def get_extrusion(self, data): - """Find the axis of extrusion. - - Used to get the objects Object Coordinate System (ocs). - """ - vec = [0,0,1] - for item in data: - if item[0] == 210: # 210 = x - vec[0] = item[1] - elif item[0] == 220: # 220 = y - vec[1] = item[1] - elif item[0] == 230: # 230 = z - vec[2] = item[1] - return vec - - - def __repr__(self): - return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) - - - -class Face: - """Class for objects representing dxf 3d faces.""" - - def __init__(self, obj): - """Expects an entity object of type 3dfaceplot as input.""" - if not obj.type == '3dface': - raise TypeError, "Wrong type %s for 3dface object!" %obj.type - self.type = obj.type - self.data = obj.data[:] - - # optional data (with defaults) - self.space = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.points = self.get_points(obj.data) - - - - - def get_points(self, data): - """Gets 3-4 points for a 3d face type object. - - Faces have three or optionally four verts. - """ - - a = [0, 0, 0] - b = [0, 0, 0] - c = [0, 0, 0] - d = False - for item in data: - # ----------- a ------------- - if item[0] == 10: # 10 = x - a[0] = item[1] - elif item[0] == 20: # 20 = y - a[1] = item[1] - elif item[0] == 30: # 30 = z - a[2] = item[1] - # ----------- b ------------- - elif item[0] == 11: # 11 = x - b[0] = item[1] - elif item[0] == 21: # 21 = y - b[1] = item[1] - elif item[0] == 31: # 31 = z - b[2] = item[1] - # ----------- c ------------- - elif item[0] == 12: # 12 = x - c[0] = item[1] - elif item[0] == 22: # 22 = y - c[1] = item[1] - elif item[0] == 32: # 32 = z - c[2] = item[1] - # ----------- d ------------- - elif item[0] == 13: # 13 = x - d = [0, 0, 0] - d[0] = item[1] - elif item[0] == 23: # 23 = y - d[1] = item[1] - elif item[0] == 33: # 33 = z - d[2] = item[1] - out = [a,b,c] - if d: - out.append(d) - return out - - - def __repr__(self): - return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) - - -def get_name(data): - """Get the name of an object from its object data. - - Returns a pair of (data_item, name) where data_item is the list entry where the name was found - (the data_item can be used to remove the entry from the object data). Be sure to check - name not None before using the returned values! - """ - value = None - for i, item in enumerate(data): - if item[0] == 2: - value = item[1] - break - return item, value, i - -def get_layer(data): - """Expects object data as input. - - Returns (entry, layer_name, entry_index) where entry is the data item that provided the layer name. - """ - value = None - for i, item in enumerate(data): - if item[0] == 8: - value = item[1] - break - return item, value, i - - -# type to object map -type_map = { - 'line':Line, - 'lwpolyline':LWpolyline, - 'text':Text, - 'mtext':Mtext, - 'circle':Circle, - 'arc':Arc, - 'layer':Layer, - 'block_record':BlockRecord, - 'block':Block, - 'insert':Insert, - 'ellipse':Ellipse, - '3dface':Face -} - -def objectify(data): - """Expects a section type object's data as input. - - Maps object data to the correct object type. - """ - objects = [] # colector for finished objects - known_types = type_map.keys() # so we don't have to call foo.keys() every iteration - index = 0 - while index < len(data): - item = data[index] - if type(item) != list and item.type in known_types: - # proccess the object and append the resulting object - objects.append(type_map[item.type](item)) - elif type(item) != list and item.type == 'table': - item.data = objectify(item.data) # tables have sub-objects - objects.append(item) - elif type(item) != list and item.type == 'polyline': - pline = Polyline(item) - while 1: - index += 1 - item = data[index] - if item.type == 'vertex': - v = Vertex(item) - pline.points.append(v) - elif item.type == 'seqend': - break - else: - print "Error: non-vertex found before seqend!" - index -= 1 - break - objects.append(pline) - else: - # we will just let the data pass un-harrased - objects.append(item) - index += 1 - return objects -if __name__ == "__main__": - print "No example yet!" diff --git a/src/Mod/Draft/draftlibs/dxfLibrary.py b/src/Mod/Draft/draftlibs/dxfLibrary.py deleted file mode 100644 index 05a6e4f03..000000000 --- a/src/Mod/Draft/draftlibs/dxfLibrary.py +++ /dev/null @@ -1,896 +0,0 @@ -#dxfLibrary.py : provides functions for generating DXF files -# -------------------------------------------------------------------------- -__version__ = "v1.33 - 2009.06.16" -__author__ = "Stani Michiels(Stani), Remigiusz Fiedler(migius)" -__license__ = "GPL" -__url__ = "http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_dxf" -__bpydoc__ ="""The library to export geometry data to DXF format r12 version. - -Copyright %s -Version %s -License %s -Homepage %s - -See the homepage for documentation. -Dedicated thread on BlenderArtists: http://blenderartists.org/forum/showthread.php?t=136439 - -IDEAs: -- - -TODO: -- add support for DXFr14 (needs extended file header) -- add support for SPLINEs (possible first in DXFr14 version) -- add user preset for floating point precision (3-16?) - -History -v1.33 - 2009.06.16 by migius - - modif _point(): converts all coords to floats - - modif LineType class: implement elements - - added VPORT class, incl. defaults - - fix Insert class -v1.32 - 2009.06.06 by migius - - modif Style class: changed defaults to widthFactor=1.0, obliqueAngle=0.0 - - modif Text class: alignment parameter reactivated -v1.31 - 2009.06.02 by migius - - modif _Entity class: added paperspace,elevation -v1.30 - 2009.05.28 by migius - - bugfix 3dPOLYLINE/POLYFACE: VERTEX needs x,y,z coordinates, index starts with 1 not 0 -v1.29 - 2008.12.28 by Yorik - - modif POLYLINE to support bulge segments -v1.28 - 2008.12.13 by Steeve/BlenderArtists - - bugfix for EXTMIN/EXTMAX to suit Cycas-CAD -v1.27 - 2008.10.07 by migius - - beautifying output code: keys whitespace prefix - - refactoring DXF-strings format: NewLine moved to the end of -v1.26 - 2008.10.05 by migius - - modif POLYLINE to support POLYFACE -v1.25 - 2008.09.28 by migius - - modif FACE class for r12 -v1.24 - 2008.09.27 by migius - - modif POLYLINE class for r12 - - changing output format from r9 to r12(AC1009) -v1.1 (20/6/2005) by www.stani.be/python/sdxf - - Python library to generate dxf drawings -______________________________________________________________ -""" % (__author__,__version__,__license__,__url__) - -# -------------------------------------------------------------------------- -# DXF Library: copyright (C) 2005 by Stani Michiels (AKA Stani) -# 2008/2009 modif by Remigiusz Fiedler (AKA migius) -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# 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 General Public License for more details. -# -# You should have received a copy of the GNU 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. -# -# ***** END GPL LICENCE BLOCK ***** - - -#import Blender -#from Blender import Mathutils, Window, Scene, sys, Draw -#import BPyMessages - -try: - import copy - #from struct import pack -except: - copy = None - -####1) Private (only for developpers) -_HEADER_POINTS=['insbase','extmin','extmax'] - -#---helper functions----------------------------------- -def _point(x,index=0): - """Convert tuple to a dxf point""" - #print 'deb: _point=', x #------------- - return '\n'.join([' %s\n%s'%((i+1)*10+index,float(x[i])) for i in range(len(x))]) - -def _points(plist): - """Convert a list of tuples to dxf points""" - out = '\n'.join([_point(plist[i],i)for i in range(len(plist))]) - return out - -#---base classes---------------------------------------- -class _Call: - """Makes a callable class.""" - def copy(self): - """Returns a copy.""" - return copy.deepcopy(self) - - def __call__(self,**attrs): - """Returns a copy with modified attributes.""" - copied=self.copy() - for attr in attrs:setattr(copied,attr,attrs[attr]) - return copied - -#------------------------------------------------------- -class _Entity(_Call): - """Base class for _common group codes for entities.""" - def __init__(self,paperspace=None,color=None,layer='0', - lineType=None,lineTypeScale=None,lineWeight=None, - extrusion=None,elevation=None,thickness=None, - parent=None): - """None values will be omitted.""" - self.paperspace = paperspace - self.color = color - self.layer = layer - self.lineType = lineType - self.lineTypeScale = lineTypeScale - self.lineWeight = lineWeight - self.extrusion = extrusion - self.elevation = elevation - self.thickness = thickness - #self.visible = visible - self.parent = parent - - def _common(self): - """Return common group codes as a string.""" - if self.parent:parent=self.parent - else:parent=self - result ='' - if parent.paperspace==1: result+=' 67\n1\n' - if parent.layer!=None: result+=' 8\n%s\n'%parent.layer - if parent.color!=None: result+=' 62\n%s\n'%parent.color - if parent.lineType!=None: result+=' 6\n%s\n'%parent.lineType - # TODO: if parent.lineWeight!=None: result+='370\n%s\n'%parent.lineWeight - # TODO: if parent.visible!=None: result+='60\n%s\n'%parent.visible - if parent.lineTypeScale!=None: result+=' 48\n%s\n'%parent.lineTypeScale - if parent.elevation!=None: result+=' 38\n%s\n'%parent.elevation - if parent.thickness!=None: result+=' 39\n%s\n'%parent.thickness - if parent.extrusion!=None: result+='%s\n'%_point(parent.extrusion,200) - return result - -#-------------------------- -class _Entities: - """Base class to deal with composed objects.""" - def __dxf__(self): - return [] - - def __str__(self): - return ''.join([str(x) for x in self.__dxf__()]) - -#-------------------------- -class _Collection(_Call): - """Base class to expose entities methods to main object.""" - def __init__(self,entities=[]): - self.entities=copy.copy(entities) - #link entities methods to drawing - for attr in dir(self.entities): - if attr[0]!='_': - attrObject=getattr(self.entities,attr) - if callable(attrObject): - setattr(self,attr,attrObject) - -####2) Constants -#---color values -BYBLOCK=0 -BYLAYER=256 - -#---block-type flags (bit coded values, may be combined): -ANONYMOUS =1 # This is an anonymous block generated by hatching, associative dimensioning, other internal operations, or an application -NON_CONSTANT_ATTRIBUTES =2 # This block has non-constant attribute definitions (this bit is not set if the block has any attribute definitions that are constant, or has no attribute definitions at all) -XREF =4 # This block is an external reference (xref) -XREF_OVERLAY =8 # This block is an xref overlay -EXTERNAL =16 # This block is externally dependent -RESOLVED =32 # This is a resolved external reference, or dependent of an external reference (ignored on input) -REFERENCED =64 # This definition is a referenced external reference (ignored on input) - -#---mtext flags -#attachment point -TOP_LEFT = 1 -TOP_CENTER = 2 -TOP_RIGHT = 3 -MIDDLE_LEFT = 4 -MIDDLE_CENTER = 5 -MIDDLE_RIGHT = 6 -BOTTOM_LEFT = 7 -BOTTOM_CENTER = 8 -BOTTOM_RIGHT = 9 -#drawing direction -LEFT_RIGHT = 1 -TOP_BOTTOM = 3 -BY_STYLE = 5 #the flow direction is inherited from the associated text style -#line spacing style (optional): -AT_LEAST = 1 #taller characters will override -EXACT = 2 #taller characters will not override - -#---polyline flags -CLOSED =1 # This is a closed polyline (or a polygon mesh closed in the M direction) -CURVE_FIT =2 # Curve-fit vertices have been added -SPLINE_FIT =4 # Spline-fit vertices have been added -POLYLINE_3D =8 # This is a 3D polyline -POLYGON_MESH =16 # This is a 3D polygon mesh -CLOSED_N =32 # The polygon mesh is closed in the N direction -POLYFACE_MESH =64 # The polyline is a polyface mesh -CONTINOUS_LINETYPE_PATTERN =128 # The linetype pattern is generated continuously around the vertices of this polyline - -#---text flags -#horizontal -LEFT = 0 -CENTER = 1 -RIGHT = 2 -ALIGNED = 3 #if vertical alignment = 0 -MIDDLE = 4 #if vertical alignment = 0 -FIT = 5 #if vertical alignment = 0 -#vertical -BASELINE = 0 -BOTTOM = 1 -MIDDLE = 2 -TOP = 3 - -####3) Classes -#---entitities ----------------------------------------------- -#-------------------------- -class Arc(_Entity): - """Arc, angles in degrees.""" - def __init__(self,center=(0,0,0),radius=1, - startAngle=0.0,endAngle=90,**common): - """Angles in degrees.""" - _Entity.__init__(self,**common) - self.center=center - self.radius=radius - self.startAngle=startAngle - self.endAngle=endAngle - def __str__(self): - return ' 0\nARC\n%s%s\n 40\n%s\n 50\n%s\n 51\n%s\n'%\ - (self._common(),_point(self.center), - self.radius,self.startAngle,self.endAngle) - -#----------------------------------------------- -class Circle(_Entity): - """Circle""" - def __init__(self,center=(0,0,0),radius=1,**common): - _Entity.__init__(self,**common) - self.center=center - self.radius=radius - def __str__(self): - return ' 0\nCIRCLE\n%s%s\n 40\n%s\n'%\ - (self._common(),_point(self.center),self.radius) - -#----------------------------------------------- -class Face(_Entity): - """3dface""" - def __init__(self,points,**common): - _Entity.__init__(self,**common) - while len(points)<4: #fix for r12 format - points.append(points[-1]) - self.points=points - - def __str__(self): - out = ' 0\n3DFACE\n%s%s\n' %(self._common(),_points(self.points)) - #print 'deb:out=', out #------------------- - return out - -#----------------------------------------------- -class Insert(_Entity): - """Block instance.""" - def __init__(self,name,point=(0,0,0), - xscale=None,yscale=None,zscale=None, - cols=None,colspacing=None,rows=None,rowspacing=None, - rotation=None, - **common): - _Entity.__init__(self,**common) - self.name=name - self.point=point - self.xscale=xscale - self.yscale=yscale - self.zscale=zscale - self.cols=cols - self.colspacing=colspacing - self.rows=rows - self.rowspacing=rowspacing - self.rotation=rotation - - def __str__(self): - result=' 0\nINSERT\n 2\n%s\n%s%s\n'%\ - (self.name,self._common(),_point(self.point)) - if self.xscale!=None:result+=' 41\n%s\n'%self.xscale - if self.yscale!=None:result+=' 42\n%s\n'%self.yscale - if self.zscale!=None:result+=' 43\n%s\n'%self.zscale - if self.rotation:result+=' 50\n%s\n'%self.rotation - if self.cols!=None:result+=' 70\n%s\n'%self.cols - if self.colspacing!=None:result+=' 44\n%s\n'%self.colspacing - if self.rows!=None:result+=' 71\n%s\n'%self.rows - if self.rowspacing!=None:result+=' 45\n%s\n'%self.rowspacing - return result - -#----------------------------------------------- -class Line(_Entity): - """Line""" - def __init__(self,points,**common): - _Entity.__init__(self,**common) - self.points=points - def __str__(self): - return ' 0\nLINE\n%s%s\n' %( - self._common(), _points(self.points)) - - -#----------------------------------------------- -class PolyLine(_Entity): - def __init__(self,points,org_point=[0,0,0],flag=0,width=None,**common): - #width = number, or width = list [width_start=None, width_end=None] - #for 2d-polyline: points = [ [x, y, z, width_start=None, width_end=None, bulge=0 or None], ...] - #for 3d-polyline: points = [ [x, y, z], ...] - #for polyface: points = [points_list, faces_list] - _Entity.__init__(self,**common) - self.points=points - self.org_point=org_point - self.flag=flag - self.polyface = False - self.polyline2d = False - self.faces = [] # dummy value - self.width= None # dummy value - if self.flag & POLYFACE_MESH: - self.polyface=True - self.points=points[0] - self.faces=points[1] - self.p_count=len(self.points) - self.f_count=len(self.faces) - elif not self.flag & POLYLINE_3D: - self.polyline2d = True - if width: - if type(width)!='list': - width=[width,width] - self.width=width - - def __str__(self): - result= ' 0\nPOLYLINE\n%s 70\n%s\n' %(self._common(),self.flag) - result+=' 66\n1\n' - result+='%s\n' %_point(self.org_point) - if self.polyface: - result+=' 71\n%s\n' %self.p_count - result+=' 72\n%s\n' %self.f_count - elif self.polyline2d: - if self.width!=None: result+=' 40\n%s\n 41\n%s\n' %(self.width[0],self.width[1]) - for point in self.points: - result+=' 0\nVERTEX\n' - result+=' 8\n%s\n' %self.layer - if self.polyface: - result+='%s\n' %_point(point[0:3]) - result+=' 70\n192\n' - elif self.polyline2d: - result+='%s\n' %_point(point[0:2]) - if len(point)>4: - width1, width2 = point[3], point[4] - if width1!=None: result+=' 40\n%s\n' %width1 - if width2!=None: result+=' 41\n%s\n' %width2 - if len(point)==6: - bulge = point[5] - if bulge: result+=' 42\n%s\n' %bulge - else: - result+='%s\n' %_point(point[0:3]) - for face in self.faces: - result+=' 0\nVERTEX\n' - result+=' 8\n%s\n' %self.layer - result+='%s\n' %_point(self.org_point) - result+=' 70\n128\n' - result+=' 71\n%s\n' %face[0] - result+=' 72\n%s\n' %face[1] - result+=' 73\n%s\n' %face[2] - if len(face)==4: result+=' 74\n%s\n' %face[3] - result+=' 0\nSEQEND\n' - result+=' 8\n%s\n' %self.layer - return result - -#----------------------------------------------- -class Point(_Entity): - """Point.""" - def __init__(self,points=None,**common): - _Entity.__init__(self,**common) - self.points=points - def __str__(self): # TODO: - return ' 0\nPOINT\n%s%s\n' %(self._common(), - _points(self.points) - ) - -#----------------------------------------------- -class Solid(_Entity): - """Colored solid fill.""" - def __init__(self,points=None,**common): - _Entity.__init__(self,**common) - self.points=points - def __str__(self): - return ' 0\nSOLID\n%s%s\n' %(self._common(), - _points(self.points[:2]+[self.points[3],self.points[2]]) - ) - - -#----------------------------------------------- -class Dimension(_Entity): - """Basic dimension entity""" - def __init__(self,point,start,end,**common): - _Entity.__init__(self,**common) - self.points=[point,start,end] - def __str__(self): - result = ' 0\nDIMENSION\n%s' %(self._common()) - result+=' 3\nStandard\n' - result+=' 70\n1\n' - result+='%s\n' %_point(self.points[0]) - result+='%s\n' %_point(self.points[1],3) - result+='%s\n' %_point(self.points[2],4) - print result - return result - -#----------------------------------------------- -class Text(_Entity): - """Single text line.""" - def __init__(self,text='',point=(0,0,0),alignment=None, - flag=None,height=1,justifyhor=None,justifyver=None, - rotation=None,obliqueAngle=None,style=None,xscale=None,**common): - _Entity.__init__(self,**common) - self.text=text - self.point=point - self.alignment=alignment - self.flag=flag - self.height=height - self.justifyhor=justifyhor - self.justifyver=justifyver - self.rotation=rotation - self.obliqueAngle=obliqueAngle - self.style=style - self.xscale=xscale - def __str__(self): - result= ' 0\nTEXT\n%s%s\n 40\n%s\n 1\n%s\n'%\ - (self._common(),_point(self.point),self.height,self.text) - if self.rotation: result+=' 50\n%s\n'%self.rotation - if self.xscale: result+=' 41\n%s\n'%self.xscale - if self.obliqueAngle: result+=' 51\n%s\n'%self.obliqueAngle - if self.style: result+=' 7\n%s\n'%self.style - if self.flag: result+=' 71\n%s\n'%self.flag - if self.justifyhor: result+=' 72\n%s\n'%self.justifyhor - if self.alignment: result+='%s\n'%_point(self.alignment,1) - if self.justifyver: result+=' 73\n%s\n'%self.justifyver - return result - -#----------------------------------------------- -class Mtext(Text): - """Surrogate for mtext, generates some Text instances.""" - def __init__(self,text='',point=(0,0,0),width=250,spacingFactor=1.5,down=0,spacingWidth=None,**options): - Text.__init__(self,text=text,point=point,**options) - if down:spacingFactor*=-1 - self.spacingFactor=spacingFactor - self.spacingWidth=spacingWidth - self.width=width - self.down=down - def __str__(self): - texts=self.text.replace('\r\n','\n').split('\n') - if not self.down:texts.reverse() - result='' - x=y=0 - if self.spacingWidth:spacingWidth=self.spacingWidth - else:spacingWidth=self.height*self.spacingFactor - for text in texts: - while text: - result+='%s\n'%Text(text[:self.width], - point=(self.point[0]+x*spacingWidth, - self.point[1]+y*spacingWidth, - self.point[2]), - alignment=self.alignment,flag=self.flag,height=self.height, - justifyhor=self.justifyhor,justifyver=self.justifyver, - rotation=self.rotation,obliqueAngle=self.obliqueAngle, - style=self.style,xscale=self.xscale,parent=self - ) - text=text[self.width:] - if self.rotation:x+=1 - else:y+=1 - return result[1:] - -#----------------------------------------------- -##class _Mtext(_Entity): -## """Mtext not functioning for minimal dxf.""" -## def __init__(self,text='',point=(0,0,0),attachment=1, -## charWidth=None,charHeight=1,direction=1,height=100,rotation=0, -## spacingStyle=None,spacingFactor=None,style=None,width=100, -## xdirection=None,**common): -## _Entity.__init__(self,**common) -## self.text=text -## self.point=point -## self.attachment=attachment -## self.charWidth=charWidth -## self.charHeight=charHeight -## self.direction=direction -## self.height=height -## self.rotation=rotation -## self.spacingStyle=spacingStyle -## self.spacingFactor=spacingFactor -## self.style=style -## self.width=width -## self.xdirection=xdirection -## def __str__(self): -## input=self.text -## text='' -## while len(input)>250: -## text+='3\n%s\n'%input[:250] -## input=input[250:] -## text+='1\n%s\n'%input -## result= '0\nMTEXT\n%s\n%s\n40\n%s\n41\n%s\n71\n%s\n72\n%s%s\n43\n%s\n50\n%s\n'%\ -## (self._common(),_point(self.point),self.charHeight,self.width, -## self.attachment,self.direction,text, -## self.height, -## self.rotation) -## if self.style:result+='7\n%s\n'%self.style -## if self.xdirection:result+='%s\n'%_point(self.xdirection,1) -## if self.charWidth:result+='42\n%s\n'%self.charWidth -## if self.spacingStyle:result+='73\n%s\n'%self.spacingStyle -## if self.spacingFactor:result+='44\n%s\n'%self.spacingFactor -## return result - -#---tables --------------------------------------------------- -#----------------------------------------------- -class Block(_Collection): - """Use list methods to add entities, eg append.""" - def __init__(self,name,layer='0',flag=0,base=(0,0,0),entities=[]): - self.entities=copy.copy(entities) - _Collection.__init__(self,entities) - self.layer=layer - self.name=name - self.flag=0 - self.base=base - def __str__(self): # TODO: - e=''.join([str(x)for x in self.entities]) - return ' 0\nBLOCK\n 8\n%s\n 2\n%s\n 70\n%s\n%s\n 3\n%s\n%s 0\nENDBLK\n'%\ - (self.layer,self.name.upper(),self.flag,_point(self.base),self.name.upper(),e) - -#----------------------------------------------- -class Layer(_Call): - """Layer""" - def __init__(self,name='pydxf',color=7,lineType='continuous',flag=64): - self.name=name - self.color=color - self.lineType=lineType - self.flag=flag - def __str__(self): - return ' 0\nLAYER\n 2\n%s\n 70\n%s\n 62\n%s\n 6\n%s\n'%\ - (self.name.upper(),self.flag,self.color,self.lineType) - -#----------------------------------------------- -class LineType(_Call): - """Custom linetype""" - def __init__(self,name='CONTINUOUS',description='Solid line',elements=[0.0],flag=0): - self.name=name - self.description=description - self.elements=copy.copy(elements) - self.flag=flag - def __str__(self): - result = ' 0\nLTYPE\n 2\n%s\n 70\n%s\n 3\n%s\n 72\n65\n'%\ - (self.name.upper(),self.flag,self.description) - if self.elements: - elements = ' 73\n%s\n' %(len(self.elements)-1) - elements += ' 40\n%s\n' %(self.elements[0]) - for e in self.elements[1:]: - elements += ' 49\n%s\n' %e - result += elements - return result - - -#----------------------------------------------- -class Style(_Call): - """Text style""" - def __init__(self,name='standard',flag=0,height=0,widthFactor=1.0,obliqueAngle=0.0, - mirror=0,lastHeight=1,font='arial.ttf',bigFont=''): - self.name=name - self.flag=flag - self.height=height - self.widthFactor=widthFactor - self.obliqueAngle=obliqueAngle - self.mirror=mirror - self.lastHeight=lastHeight - self.font=font - self.bigFont=bigFont - def __str__(self): - return ' 0\nSTYLE\n 2\n%s\n 70\n%s\n 40\n%s\n 41\n%s\n 50\n%s\n 71\n%s\n 42\n%s\n 3\n%s\n 4\n%s\n'%\ - (self.name.upper(),self.flag,self.flag,self.widthFactor, - self.obliqueAngle,self.mirror,self.lastHeight, - self.font.upper(),self.bigFont.upper()) - -#----------------------------------------------- -class VPort(_Call): - def __init__(self,name,flag=0, - leftBottom=(0.0,0.0), - rightTop=(1.0,1.0), - center=(0.5,0.5), - snap_base=(0.0,0.0), - snap_spacing=(0.1,0.1), - grid_spacing=(0.1,0.1), - direction=(0.0,0.0,1.0), - target=(0.0,0.0,0.0), - height=1.0, - ratio=1.0, - lens=50, - frontClipping=0, - backClipping=0, - snap_rotation=0, - twist=0, - mode=0, - circle_zoom=100, - fast_zoom=1, - ucsicon=1, - snap_on=0, - grid_on=0, - snap_style=0, - snap_isopair=0 - ): - self.name=name - self.flag=flag - self.leftBottom=leftBottom - self.rightTop=rightTop - self.center=center - self.snap_base=snap_base - self.snap_spacing=snap_spacing - self.grid_spacing=grid_spacing - self.direction=direction - self.target=target - self.height=float(height) - self.ratio=float(ratio) - self.lens=float(lens) - self.frontClipping=float(frontClipping) - self.backClipping=float(backClipping) - self.snap_rotation=float(snap_rotation) - self.twist=float(twist) - self.mode=mode - self.circle_zoom=circle_zoom - self.fast_zoom=fast_zoom - self.ucsicon=ucsicon - self.snap_on=snap_on - self.grid_on=grid_on - self.snap_style=snap_style - self.snap_isopair=snap_isopair - def __str__(self): - output = [' 0', 'VPORT', - ' 2', self.name, - ' 70', self.flag, - _point(self.leftBottom), - _point(self.rightTop,1), - _point(self.center,2), # View center point (in DCS) - _point(self.snap_base,3), - _point(self.snap_spacing,4), - _point(self.grid_spacing,5), - _point(self.direction,6), #view direction from target (in WCS) - _point(self.target,7), - ' 40', self.height, - ' 41', self.ratio, - ' 42', self.lens, - ' 43', self.frontClipping, - ' 44', self.backClipping, - ' 50', self.snap_rotation, - ' 51', self.twist, - ' 71', self.mode, - ' 72', self.circle_zoom, - ' 73', self.fast_zoom, - ' 74', self.ucsicon, - ' 75', self.snap_on, - ' 76', self.grid_on, - ' 77', self.snap_style, - ' 78', self.snap_isopair - ] - - output_str = '' - for s in output: - output_str += '%s\n' %s - return output_str - - - -#----------------------------------------------- -class View(_Call): - def __init__(self,name,flag=0, - width=1, - height=1, - center=(0.5,0.5), - direction=(0,0,1), - target=(0,0,0), - lens=50, - frontClipping=0, - backClipping=0, - twist=0,mode=0 - ): - self.name=name - self.flag=flag - self.width=float(width) - self.height=float(height) - self.center=center - self.direction=direction - self.target=target - self.lens=float(lens) - self.frontClipping=float(frontClipping) - self.backClipping=float(backClipping) - self.twist=float(twist) - self.mode=mode - def __str__(self): - output = [' 0', 'VIEW', - ' 2', self.name, - ' 70', self.flag, - ' 40', self.height, - _point(self.center), - ' 41', self.width, - _point(self.direction,1), - _point(self.target,2), - ' 42', self.lens, - ' 43', self.frontClipping, - ' 44', self.backClipping, - ' 50', self.twist, - ' 71', self.mode - ] - output_str = '' - for s in output: - output_str += '%s\n' %s - return output_str - -#----------------------------------------------- -def ViewByWindow(name,leftBottom=(0,0),rightTop=(1,1),**options): - width=abs(rightTop[0]-leftBottom[0]) - height=abs(rightTop[1]-leftBottom[1]) - center=((rightTop[0]+leftBottom[0])*0.5,(rightTop[1]+leftBottom[1])*0.5) - return View(name=name,width=width,height=height,center=center,**options) - -#---drawing -#----------------------------------------------- -class Drawing(_Collection): - """Dxf drawing. Use append or any other list methods to add objects.""" - def __init__(self,insbase=(0.0,0.0,0.0),extmin=(0.0,0.0,0.0),extmax=(0.0,0.0,0.0), - layers=[Layer()],linetypes=[LineType()],styles=[Style()],blocks=[], - views=[],vports=[],entities=None,fileName='test.dxf'): - # TODO: replace list with None,arial - if not entities: - entities=[] - _Collection.__init__(self,entities) - self.insbase=insbase - self.extmin=extmin - self.extmax=extmax - self.layers=copy.copy(layers) - self.linetypes=copy.copy(linetypes) - self.styles=copy.copy(styles) - self.views=copy.copy(views) - self.vports=copy.copy(vports) - self.blocks=copy.copy(blocks) - self.fileName=fileName - #private - #self.acadver='9\n$ACADVER\n1\nAC1006\n' - self.acadver=' 9\n$ACADVER\n 1\nAC1009\n' - """DXF AutoCAD-Release format codes - AC1021 2008, 2007 - AC1018 2006, 2005, 2004 - AC1015 2002, 2000i, 2000 - AC1014 R14,14.01 - AC1012 R13 - AC1009 R12,11 - AC1006 R10 - AC1004 R9 - AC1002 R2.6 - AC1.50 R2.05 - """ - - def _name(self,x): - """Helper function for self._point""" - return ' 9\n$%s\n' %x.upper() - - def _point(self,name,x): - """Point setting from drawing like extmin,extmax,...""" - return '%s%s' %(self._name(name),_point(x)) - - def _section(self,name,x): - """Sections like tables,blocks,entities,...""" - if x: xstr=''.join(x) - else: xstr='' - return ' 0\nSECTION\n 2\n%s\n%s 0\nENDSEC\n'%(name.upper(),xstr) - - def _table(self,name,x): - """Tables like ltype,layer,style,...""" - if x: xstr=''.join(x) - else: xstr='' - return ' 0\nTABLE\n 2\n%s\n 70\n%s\n%s 0\nENDTAB\n'%(name.upper(),len(x),xstr) - - def __str__(self): - """Returns drawing as dxf string.""" - header=[self.acadver]+[self._point(attr,getattr(self,attr))+'\n' for attr in _HEADER_POINTS] - header=self._section('header',header) - - tables=[self._table('vport',[str(x) for x in self.vports]), - self._table('ltype',[str(x) for x in self.linetypes]), - self._table('layer',[str(x) for x in self.layers]), - self._table('style',[str(x) for x in self.styles]), - self._table('view',[str(x) for x in self.views]), - ] - tables=self._section('tables',tables) - - blocks=self._section('blocks',[str(x) for x in self.blocks]) - - entities=self._section('entities',[str(x) for x in self.entities]) - - all=''.join([header,tables,blocks,entities,' 0\nEOF\n']) - return all - - def saveas(self,fileName): - self.fileName=fileName - self.save() - - def save(self): - test=open(self.fileName,'w') - test.write(str(self)) - test.close() - - -#---extras -#----------------------------------------------- -class Rectangle(_Entity): - """Rectangle, creates lines.""" - def __init__(self,point=(0,0,0),width=1,height=1,solid=None,line=1,**common): - _Entity.__init__(self,**common) - self.point=point - self.width=width - self.height=height - self.solid=solid - self.line=line - def __str__(self): - result='' - points=[self.point,(self.point[0]+self.width,self.point[1],self.point[2]), - (self.point[0]+self.width,self.point[1]+self.height,self.point[2]), - (self.point[0],self.point[1]+self.height,self.point[2]),self.point] - if self.solid: - result+= Solid(points=points[:-1],parent=self.solid) - if self.line: - for i in range(4): - result+= Line(points=[points[i],points[i+1]],parent=self) - return result[1:] - -#----------------------------------------------- -class LineList(_Entity): - """Like polyline, but built of individual lines.""" - def __init__(self,points=[],org_point=[0,0,0],closed=0,**common): - _Entity.__init__(self,**common) - self.closed=closed - self.points=copy.copy(points) - def __str__(self): - if self.closed:points=self.points+[self.points[0]] - else: points=self.points - result='' - for i in range(len(points)-1): - result+= Line(points=[points[i],points[i+1]],parent=self) - return result[1:] - -#----------------------------------------------------- -def test(): - #Blocks - b=Block('test') - b.append(Solid(points=[(0,0,0),(1,0,0),(1,1,0),(0,1,0)],color=1)) - b.append(Arc(center=(1,0,0),color=2)) - - #Drawing - d=Drawing() - #tables - d.blocks.append(b) #table blocks - d.styles.append(Style()) #table styles - d.views.append(View('Normal')) #table view - d.views.append(ViewByWindow('Window',leftBottom=(1,0),rightTop=(2,1))) #idem - - #entities - d.append(Circle(center=(1,1,0),color=3)) - d.append(Face(points=[(0,0,0),(1,0,0),(1,1,0),(0,1,0)],color=4)) - d.append(Insert('test',point=(3,3,3),cols=5,colspacing=2)) - d.append(Line(points=[(0,0,0),(1,1,1)])) - d.append(Mtext('Click on Ads\nmultiple lines with mtext',point=(1,1,1),color=5,rotation=90)) - d.append(Text('Please donate!',point=(3,0,1))) - #d.append(Rectangle(point=(2,2,2),width=4,height=3,color=6,solid=Solid(color=2))) - d.append(Solid(points=[(4,4,0),(5,4,0),(7,8,0),(9,9,0)],color=3)) - #d.append(PolyLine(points=[(1,1,1),(2,1,1),(2,2,1),(1,2,1)],flag=1,color=1)) - - #d.saveas('c:\\test.dxf') - d.saveas('test.dxf') - -#----------------------------------------------------- -if __name__=='__main__': - if not copy: - Draw.PupMenu('Error%t|This script requires a full python install') - else: test() - diff --git a/src/Mod/Draft/draftlibs/dxfReader.py b/src/Mod/Draft/draftlibs/dxfReader.py deleted file mode 100644 index e03777515..000000000 --- a/src/Mod/Draft/draftlibs/dxfReader.py +++ /dev/null @@ -1,384 +0,0 @@ -"""This module provides a function for reading dxf files and parsing them into a useful tree of objects and data. - - The convert function is called by the readDXF fuction to convert dxf strings into the correct data based - on their type code. readDXF expects a (full path) file name as input. -""" - -# -------------------------------------------------------------------------- -# DXF Reader v0.9 by Ed Blake (AKA Kitsu) -# 2008.05.08 modif.def convert() by Remigiusz Fiedler (AKA migius) -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# 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 General Public License for more details. -# -# You should have received a copy of the GNU 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. -# -# ***** END GPL LICENCE BLOCK ***** -# -------------------------------------------------------------------------- - - -from dxfImportObjects import * - -class Object: - """Empty container class for dxf objects""" - - def __init__(self, _type='', block=False): - """_type expects a string value.""" - self.type = _type - self.name = '' - self.data = [] - - def __str__(self): - if self.name: - return self.name - else: - return self.type - - def __repr__(self): - return str(self.data) - - def get_type(self, kind=''): - """Despite the name, this method actually returns all objects of type 'kind' from self.data.""" - if type: - objects = [] - for item in self.data: - if type(item) != list and item.type == kind: - # we want this type of object - objects.append(item) - elif type(item) == list and item[0] == kind: - # we want this type of data - objects.append(item[1]) - return objects - - -class InitializationError(Exception): pass - -class StateMachine: - """(finite) State Machine from the great David Mertz's great Charming Python article.""" - - def __init__(self): - self.handlers = [] - self.startState = None - self.endStates = [] - - def add_state(self, handler, end_state=0): - """All states and handlers are functions which return - a state and a cargo.""" - self.handlers.append(handler) - if end_state: - self.endStates.append(handler) - def set_start(self, handler): - """Sets the starting handler function.""" - self.startState = handler - - - def run(self, cargo=None): - if not self.startState: - raise InitializationError,\ - "must call .set_start() before .run()" - if not self.endStates: - raise InitializationError, \ - "at least one state must be an end_state" - handler = self.startState - while 1: - (newState, cargo) = handler(cargo) - #print cargo - if newState in self.endStates: - return newState(cargo) - #break - elif newState not in self.handlers: - raise RuntimeError, "Invalid target %s" % newState - else: - handler = newState - -def get_name(data): - """Get the name of an object from its object data. - - Returns a pair of (data_item, name) where data_item is the list entry where the name was found - (the data_item can be used to remove the entry from the object data). Be sure to check - name not None before using the returned values! - """ - value = None - for item in data: - if item[0] == 2: - value = item[1] - break - return item, value - -def get_layer(data): - """Expects object data as input. - - Returns (entry, layer_name) where entry is the data item that provided the layer name. - """ - value = None - for item in data: - if item[0] == 8: - value = item[1] - break - return item, value - - -def convert(code, value): - """Convert a string to the correct Python type based on its dxf code. - code types: - ints = 60-79, 170-179, 270-289, 370-389, 400-409, 1060-1070 - longs = 90-99, 420-429, 440-459, 1071 - floats = 10-39, 40-59, 110-139, 140-149, 210-239, 460-469, 1010-1059 - hex = 105, 310-379, 390-399 - strings = 0-9, 100, 102, 300-309, 410-419, 430-439, 470-479, 999, 1000-1009 - """ - if 59 < code < 80 or 169 < code < 180 or 269 < code < 290 or 369 < code < 390 or 399 < code < 410 or 1059 < code < 1071: - value = int(float(value)) - elif 89 < code < 100 or 419 < code < 430 or 439 < code < 460 or code == 1071: - value = long(float(value)) - elif 9 < code < 60 or 109 < code < 150 or 209 < code < 240 or 459 < code < 470 or 1009 < code < 1060: - value = float(value) - elif code == 105 or 309 < code < 380 or 389 < code < 400: - try: - value = int(value, 16) # should be left as string? - except: - pass - else: # it's already a string so do nothing - pass - return value - - -def findObject(infile, kind=''): - """Finds the next occurance of an object.""" - obj = False - while 1: - line = infile.readline() - if not line: # readline returns '' at eof - return False - if not obj: # We're still looking for our object code - if line.lower().strip() == '0': - obj = True # found it - else: # we are in an object definition - if kind: # if we're looking for a particular kind - if line.lower().strip() == kind: - obj = Object(line.lower().strip()) - break - else: # otherwise take anything non-numeric - if line.lower().strip() not in string.digits: - obj = Object(line.lower().strip()) - break - obj = False # whether we found one or not it's time to start over - return obj - -def handleObject(infile): - """Add data to an object until end of object is found.""" - line = infile.readline() - if line.lower().strip() == 'section': - return 'section' # this would be a problem - elif line.lower().strip() == 'endsec': - return 'endsec' # this means we are done with a section - else: # add data to the object until we find a new object - obj = Object(line.lower().strip()) - obj.name = obj.type - done = False - data = [] - while not done: - line = infile.readline() - if not data: - if line.lower().strip() == '0': - #we've found an object, time to return - return obj - else: - # first part is always an int - data.append(int(line.lower().strip())) - else: - data.append(convert(data[0], line.strip())) - obj.data.append(data) - data = [] - -def handleTable(table, infile): - """Special handler for dealing with nested table objects.""" - item, name = get_name(table.data) - if name: # We should always find a name - table.data.remove(item) - table.name = name.lower() - # This next bit is from handleObject - # handleObject should be generalized to work with any section like object - while 1: - obj = handleObject(infile) - if obj.type == 'table': - print "Warning: previous table not closed!" - return table - elif obj.type == 'endtab': - return table # this means we are done with the table - else: # add objects to the table until one of the above is found - table.data.append(obj) - - - - -def handleBlock(block, infile): - """Special handler for dealing with nested table objects.""" - item, name = get_name(block.data) - if name: # We should always find a name - # block.data.remove(item) - block.name = name - # This next bit is from handleObject - # handleObject should be generalized to work with any section like object - while 1: - obj = handleObject(infile) - if obj.type == 'block': - print "Warning: previous block not closed!" - return block - elif obj.type == 'endblk': - return block # this means we are done with the table - else: # add objects to the table until one of the above is found - block.data.append(obj) - - - - -"""These are the states/functions used in the State Machine. -states: - start - find first section - start_section - add data, find first object - object - add obj-data, watch for next obj (called directly by start_section) - end_section - look for next section or eof - end - return results -""" - -def start(cargo): - """Expects the infile as cargo, initializes the cargo.""" - #print "Entering start state!" - infile = cargo - drawing = Object('drawing') - section = findObject(infile, 'section') - if section: - return start_section, (infile, drawing, section) - else: - return error, (infile, "Failed to find any sections!") - -def start_section(cargo): - """Expects [infile, drawing, section] as cargo, builds a nested section object.""" - #print "Entering start_section state!" - infile = cargo[0] - drawing = cargo[1] - section = cargo[2] - # read each line, if it is an object declaration go to object mode - # otherwise create a [index, data] pair and add it to the sections data. - done = False - data = [] - while not done: - line = infile.readline() - - if not data: # if we haven't found a dxf code yet - if line.lower().strip() == '0': - # we've found an object - while 1: # no way out unless we find an end section or a new section - obj = handleObject(infile) - if obj == 'section': # shouldn't happen - print "Warning: failed to close previous section!" - return end_section, (infile, drawing) - elif obj == 'endsec': # This section is over, look for the next - drawing.data.append(section) - return end_section, (infile, drawing) - elif obj.type == 'table': # tables are collections of data - obj = handleTable(obj, infile) # we need to find all there contents - section.data.append(obj) # before moving on - elif obj.type == 'block': # the same is true of blocks - obj = handleBlock(obj, infile) # we need to find all there contents - section.data.append(obj) # before moving on - else: # found another sub-object - section.data.append(obj) - else: - data.append(int(line.lower().strip())) - else: # we have our code, now we just need to convert the data and add it to our list. - data.append(convert(data[0], line.strip())) - section.data.append(data) - data = [] -def end_section(cargo): - """Expects (infile, drawing) as cargo, searches for next section.""" - #print "Entering end_section state!" - infile = cargo[0] - drawing = cargo[1] - section = findObject(infile, 'section') - if section: - return start_section, (infile, drawing, section) - else: - return end, (infile, drawing) - -def end(cargo): - """Expects (infile, drawing) as cargo, called when eof has been reached.""" - #print "Entering end state!" - infile = cargo[0] - drawing = cargo[1] - #infile.close() - return drawing - -def error(cargo): - """Expects a (infile, string) as cargo, called when there is an error during processing.""" - #print "Entering error state!" - infile = cargo[0] - err = cargo[1] - infile.close() - print "There has been an error:" - print err - return False - -def readDXF(filename): - """Given a file name try to read it as a dxf file. - - Output is an object with the following structure - drawing - header - header data - classes - class data - tables - table data - blocks - block data - entities - entity data - objects - object data - where foo data is a list of sub-objects. True object data - is of the form [code, data]. -""" - infile = open(filename) - - sm = StateMachine() - sm.add_state(error, True) - sm.add_state(end, True) - sm.add_state(start_section) - sm.add_state(end_section) - sm.add_state(start) - sm.set_start(start) - try: - drawing = sm.run(infile) - if drawing: - drawing.name = filename - for obj in drawing.data: - item, name = get_name(obj.data) - if name: - obj.data.remove(item) - obj.name = name.lower() - setattr(drawing, name.lower(), obj) - # Call the objectify function to cast - # raw objects into the right types of object - obj.data = objectify(obj.data) - #print obj.name - finally: - infile.close() - return drawing -if __name__ == "__main__": - filename = r".\examples\block-test.dxf" - drawing = readDXF(filename) - for item in drawing.entities.data: - print item diff --git a/src/Mod/Draft/importDXF.py b/src/Mod/Draft/importDXF.py index 85d89ec4c..e56f87fd4 100644 --- a/src/Mod/Draft/importDXF.py +++ b/src/Mod/Draft/importDXF.py @@ -39,9 +39,7 @@ lines, polylines, lwpolylines, circles, arcs, texts, colors,layers (from groups) ''' -import FreeCAD, os, Part, math, re, string, Mesh, Draft, DraftVecUtils, DraftGeomUtils -from draftlibs import dxfColorMap, dxfLibrary -from draftlibs.dxfReader import readDXF +import sys, FreeCAD, os, Part, math, re, string, Mesh, Draft, DraftVecUtils, DraftGeomUtils from Draft import _Dimension, _ViewProviderDimension from FreeCAD import Vector @@ -51,9 +49,23 @@ else: gui = True try: draftui = FreeCADGui.draftToolBar except: draftui = None +files = ['dxfColorMap.py','dxfImportObjects.py','dxfLibrary.py','dxfReader.py'] +baseurl = 'https://raw.github.com/yorikvanhavre/Draft-dxf-importer/master/' +for f in files: + p = os.path.join(FreeCAD.ConfigGet("UserAppData"),f) + if not os.path.exists(p): + import ArchCommands + p = None + p = ArchCommands.download(baseurl+f) + if not p: + FreeCAD.Console.PrintWarning("Download of dxf libraries failed. Please download them manually from https://github.com/yorikvanhavre/Draft-dxf-importer") + sys.exit() +sys.path.append(FreeCAD.ConfigGet("UserAppData")) +import dxfColorMap, dxfLibrary, dxfReader + if open.__module__ == '__builtin__': pythonopen = open # to distinguish python built-in open function from the one declared here - + def prec(): "returns the current Draft precision level" return Draft.getParam("precision") @@ -771,7 +783,7 @@ def processdxf(document,filename): "this does the translation of the dxf contents into FreeCAD Part objects" global drawing # for debugging - so drawing is still accessible to python after the script FreeCAD.Console.PrintMessage("opening "+filename+"...\n") - drawing = readDXF(filename) + drawing = dxfReader.readDXF(filename) global layers layers = [] global doc From 218a82832731c99cc930f66170c3a5141129f5ff Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sun, 23 Jun 2013 15:33:26 -0300 Subject: [PATCH 109/160] Draft: fixed cmake and installer stuff with removed draftlibs --- src/Mod/Draft/CMakeLists.txt | 18 +----------------- src/WindowsInstaller/ModDraft.wxi | 9 --------- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/src/Mod/Draft/CMakeLists.txt b/src/Mod/Draft/CMakeLists.txt index 0b0822a83..e380eb193 100644 --- a/src/Mod/Draft/CMakeLists.txt +++ b/src/Mod/Draft/CMakeLists.txt @@ -20,16 +20,7 @@ SET(Draft_SRCS ) SOURCE_GROUP("" FILES ${Draft_SRCS}) -SET(DraftLibs_SRCS - draftlibs/dxfColorMap.py - draftlibs/dxfImportObjects.py - draftlibs/dxfLibrary.py - draftlibs/dxfReader.py - draftlibs/__init__.py -) -SOURCE_GROUP("draftlibs" FILES ${DraftLibs_SRCS}) - -SET(all_files ${Draft_SRCS} ${DraftLibs_SRCS}) +SET(all_files ${Draft_SRCS}) ADD_CUSTOM_TARGET(Draft ALL SOURCES ${all_files} @@ -37,13 +28,6 @@ ADD_CUSTOM_TARGET(Draft ALL fc_copy_sources(Draft "${CMAKE_BINARY_DIR}/Mod/Draft" ${all_files}) - -INSTALL( - FILES - ${DraftLibs_SRCS} - DESTINATION - Mod/Draft/draftlibs -) INSTALL( FILES ${Draft_SRCS} diff --git a/src/WindowsInstaller/ModDraft.wxi b/src/WindowsInstaller/ModDraft.wxi index eb43fee40..2a212d379 100644 --- a/src/WindowsInstaller/ModDraft.wxi +++ b/src/WindowsInstaller/ModDraft.wxi @@ -42,14 +42,5 @@ - - - - - - - - - From 827a716814adc1426db035bacc3dcbca6f085a56 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sun, 23 Jun 2013 15:59:35 -0300 Subject: [PATCH 110/160] Draft: minor fixes to DXF importer --- src/Mod/Draft/importDXF.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/Mod/Draft/importDXF.py b/src/Mod/Draft/importDXF.py index e56f87fd4..cc563f5d3 100644 --- a/src/Mod/Draft/importDXF.py +++ b/src/Mod/Draft/importDXF.py @@ -151,9 +151,9 @@ def calcBulge(v1,bulge,v2): endpoint = DraftVecUtils.scale(perp,sagitta) return startpoint.add(endpoint) -def getGroup(ob,exportList): +def getGroup(ob): "checks if the object is part of a group" - for i in exportList: + for i in FreeCAD.ActiveDocument.Objects: if (i.TypeId == "App::DocumentObjectGroup"): for j in i.Group: if (j == ob): @@ -1337,7 +1337,7 @@ def getWire(wire,nospline=False): def getBlock(sh,obj): "returns a dxf block with the contents of the object" - block = dxfLibrary.Block(name=obj.Name,layer=getGroup(obj,exportList)) + block = dxfLibrary.Block(name=obj.Name,layer=getGroup(obj)) writeShape(sh,obj,block) return block @@ -1352,15 +1352,15 @@ def writeShape(sh,ob,dxfobject,nospline=False): if len(wire.Edges[0].Vertexes) == 1: # circle dxfobject.append(dxfLibrary.Circle(center, radius, color=getACI(ob), - layer=getGroup(ob,exportList))) + layer=getGroup(ob))) else: # arc dxfobject.append(dxfLibrary.Arc(center, radius, ang1, ang2, color=getACI(ob), - layer=getGroup(ob,exportList))) + layer=getGroup(ob))) else: dxfobject.append(dxfLibrary.PolyLine(getWire(wire,nospline), [0.0,0.0,0.0], int(DraftGeomUtils.isReallyClosed(wire)), color=getACI(ob), - layer=getGroup(ob,exportList))) + layer=getGroup(ob))) if len(processededges) < len(sh.Edges): # lone edges loneedges = [] for e in sh.Edges: @@ -1374,7 +1374,7 @@ def writeShape(sh,ob,dxfobject,nospline=False): if c: dxfobject.append(dxfLibrary.Circle(DraftVecUtils.tup(c.Curve.Center), c.Curve.Radius, color=getACI(ob), - layer=getGroup(ob,exportList))) + layer=getGroup(ob))) else: points = [] spline = getSplineSegs(edge) @@ -1382,7 +1382,7 @@ def writeShape(sh,ob,dxfobject,nospline=False): points.append((p.x,p.y,p.z,None,None,0.0)) dxfobject.append(dxfLibrary.PolyLine(points, [0.0,0.0,0.0], 0, color=getACI(ob), - layer=getGroup(ob,exportList))) + layer=getGroup(ob))) elif DraftGeomUtils.geomType(edge) == "Circle": # curves center, radius, ang1, ang2 = getArcData(edge) if not isinstance(center,tuple): @@ -1390,18 +1390,18 @@ def writeShape(sh,ob,dxfobject,nospline=False): if len(edge.Vertexes) == 1: # circles dxfobject.append(dxfLibrary.Circle(center, radius, color=getACI(ob), - layer=getGroup(ob,exportList))) + layer=getGroup(ob))) else : # arcs dxfobject.append(dxfLibrary.Arc(center, radius, ang1, ang2, color=getACI(ob), - layer=getGroup(ob,exportList))) + layer=getGroup(ob))) else: # anything else is treated as lines if len(edge.Vertexes) > 1: ve1=edge.Vertexes[0].Point ve2=edge.Vertexes[1].Point dxfobject.append(dxfLibrary.Line([DraftVecUtils.tup(ve1), DraftVecUtils.tup(ve2)], color=getACI(ob), - layer=getGroup(ob,exportList))) + layer=getGroup(ob))) def writeMesh(ob,dxfobject): "export a shape as a polyface mesh" @@ -1416,12 +1416,14 @@ def writeMesh(ob,dxfobject): # print len(points),len(faces) dxfobject.append(dxfLibrary.PolyLine([points,faces], [0.0,0.0,0.0], 64, color=getACI(ob), - layer=getGroup(ob,exportList))) + layer=getGroup(ob))) 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 + + exportList = Draft.getGroupContents(exportList) if (len(exportList) == 1) and (Draft.getType(exportList[0]) == "ArchSectionView"): # arch view: export it "as is" @@ -1487,7 +1489,7 @@ def export(objectslist,filename,nospline=False): dxf.append(dxfLibrary.Text(text,point,height=height, color=getACI(ob,text=True), style='STANDARD', - layer=getGroup(ob,exportList))) + layer=getGroup(ob))) elif Draft.getType(ob) == "Dimension": p1 = DraftVecUtils.tup(ob.Start) @@ -1499,7 +1501,7 @@ def export(objectslist,filename,nospline=False): else: pbase = DraftVecUtils.tup(ob.End.add(DraftVecUtils.neg(proj))) dxf.append(dxfLibrary.Dimension(pbase,p1,p2,color=getACI(ob), - layer=getGroup(ob,exportList))) + layer=getGroup(ob))) dxf.saveas(filename) FreeCAD.Console.PrintMessage("successfully exported "+filename+"\r\n") From 7f216323fffccfa09c905621d6aeb272fc695e3e Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Tue, 25 Jun 2013 11:40:38 -0300 Subject: [PATCH 111/160] 0001092: Draft local/global coordinates The draft X,Y,Z coordinates are now displayed as global, or local if the current working plane is different from the world axes. --- src/Mod/Draft/DraftGui.py | 22 ++++++++++++++++++++-- src/Mod/Draft/DraftTools.py | 12 ++++++++++-- src/Mod/Draft/WorkingPlane.py | 10 ++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py index 1e44d34d0..0cf0c6776 100644 --- a/src/Mod/Draft/DraftGui.py +++ b/src/Mod/Draft/DraftGui.py @@ -559,7 +559,12 @@ class DraftToolBar: FreeCADGui.ActiveDocument.resetEdit() return True todo.delay(FreeCADGui.Control.showDialog,dummy()) - self.setTitle(title) + self.setTitle(title) + + def redraw(self): + "utility function that is performed after each clicked point" + print "redrawing" + self.checkLocal() def selectPlaneUi(self): self.taskUi(translate("draft", "Select Plane")) @@ -623,7 +628,7 @@ class DraftToolBar: self.taskUi(title,extra,icon) self.xValue.setEnabled(True) self.yValue.setEnabled(True) - self.labelx.setText(translate("draft", "X")) + self.checkLocal() self.labelx.show() self.labely.show() self.labelz.show() @@ -805,6 +810,17 @@ class DraftToolBar: def vertUi(self,addmode=True): self.addButton.setChecked(addmode) self.delButton.setChecked(not(addmode)) + + def checkLocal(self): + "checks if x,y,z coords must be displayed as local or global" + self.labelx.setText(translate("draft", "Global X")) + self.labely.setText(translate("draft", "Global Y")) + self.labelz.setText(translate("draft", "Global Z")) + if hasattr(FreeCAD,"DraftWorkingPlane"): + if not FreeCAD.DraftWorkingPlane.isGlobal(): + self.labelx.setText(translate("draft", "Local X")) + self.labely.setText(translate("draft", "Local Y")) + self.labelz.setText(translate("draft", "Local Z")) def setEditButtons(self,mode): self.addButton.setEnabled(mode) @@ -1191,6 +1207,8 @@ class DraftToolBar: dp = plane.getLocalRot(FreeCAD.Vector(point.x-last.x, point.y-last.y, point.z-last.z)) else: dp = FreeCAD.Vector(point.x-last.x, point.y-last.y, point.z-last.z) + elif plane: + dp = plane.getLocalCoords(point) # set widgets if self.mask in ['y','z']: diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index 981cbe1c2..e310e9b84 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -507,6 +507,7 @@ class Line(Creator): if (not self.node) and (not self.support): self.support = getSupport(arg) if self.point: + self.ui.redraw() self.pos = arg["Position"] self.node.append(self.point) self.drawSegment(self.point) @@ -620,6 +621,7 @@ class BSpline(Line): if (not self.node) and (not self.support): self.support = getSupport(arg) if self.point: + self.ui.redraw() self.pos = arg["Position"] self.node.append(self.point) self.drawUpdate(self.point) @@ -827,6 +829,7 @@ class Rectangle(Creator): if (not self.node) and (not self.support): self.support = getSupport(arg) if self.point: + self.ui.redraw() self.appendPoint(self.point) def numericInput(self,numx,numy,numz): @@ -1419,6 +1422,7 @@ class Ellipse(Creator): if (not self.node) and (not self.support): self.support = getSupport(arg) if self.point: + self.ui.redraw() self.appendPoint(self.point) def numericInput(self,numx,numy,numz): @@ -1703,6 +1707,7 @@ class Dimension(Creator): if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): import DraftGeomUtils if self.point: + self.ui.redraw() if (not self.node) and (not self.support): self.support = getSupport(arg) if hasMod(arg,MODALT) and (len(self.node)<3): @@ -2001,6 +2006,7 @@ class Move(Modifier): elif arg["Type"] == "SoMouseButtonEvent": if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): if self.point: + self.ui.redraw() if (self.node == []): self.node.append(self.point) self.ui.isRelative.show() @@ -2713,7 +2719,7 @@ class Trimex(Modifier): ghost.setRadius(edge.Curve.Radius) if real: newedges.append(edge) ghost.on() - + # finishing if real: return newedges else: return dist @@ -2751,7 +2757,7 @@ class Trimex(Modifier): self.doc.commitTransaction() for g in self.ghost: g.off() - def finish(self,closed=False): + def finish(self,closed=False): Modifier.finish(self) self.force = None if self.ui: @@ -2855,6 +2861,7 @@ class Scale(Modifier): elif arg["Type"] == "SoMouseButtonEvent": if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): if self.point: + self.ui.redraw() if (self.node == []): self.node.append(self.point) self.ui.isRelative.show() @@ -3115,6 +3122,7 @@ class Edit(Modifier): self.update(self.trackers[self.editing].get()) elif arg["Type"] == "SoMouseButtonEvent": if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): + self.ui.redraw() if self.editing == None: sel = FreeCADGui.Selection.getSelectionEx() if sel: diff --git a/src/Mod/Draft/WorkingPlane.py b/src/Mod/Draft/WorkingPlane.py index ddac62c5a..a0057df5e 100644 --- a/src/Mod/Draft/WorkingPlane.py +++ b/src/Mod/Draft/WorkingPlane.py @@ -298,6 +298,16 @@ class plane: return "z" else: return None + + def isGlobal(self): + "returns True if the plane axes are equal to the global axes" + if self.u != Vector(1,0,0): + return False + if self.v != Vector(0,1,0): + return False + if self.axis != Vector(0,0,1): + return False + return True def getPlacementFromPoints(points): "returns a placement from a list of 3 or 4 vectors" From 4b2474807b2f94432e80fbd2da1203208eab3dfb Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 27 Jun 2013 14:16:41 +0200 Subject: [PATCH 112/160] 0001160: Freecad sometimes 'forgets' the ability to handle stp files --- src/Mod/Import/Gui/AppImportGuiPy.cpp | 83 +++++++++++++++++---------- src/Mod/Import/Gui/CMakeLists.txt | 2 + src/Mod/Part/App/AppPart.cpp | 10 ---- src/Mod/Part/App/ImportIges.h | 2 +- src/Mod/Part/App/ImportStep.h | 2 +- src/Mod/Part/Init.py | 13 +---- 6 files changed, 59 insertions(+), 53 deletions(-) diff --git a/src/Mod/Import/Gui/AppImportGuiPy.cpp b/src/Mod/Import/Gui/AppImportGuiPy.cpp index f9ce41189..d5cef5a02 100644 --- a/src/Mod/Import/Gui/AppImportGuiPy.cpp +++ b/src/Mod/Import/Gui/AppImportGuiPy.cpp @@ -57,6 +57,7 @@ # include # include # include +# include #if OCC_VERSION_HEX >= 0x060500 # include # else @@ -74,6 +75,8 @@ #include #include #include +#include +#include @@ -507,40 +510,60 @@ static PyObject * importer(PyObject *self, PyObject *args) hApp->NewDocument(TCollection_ExtendedString("MDTV-CAF"), hDoc); if (file.hasExtension("stp") || file.hasExtension("step")) { - STEPCAFControl_Reader aReader; - aReader.SetColorMode(true); - aReader.SetNameMode(true); - aReader.SetLayerMode(true); - if (aReader.ReadFile((Standard_CString)Name) != IFSelect_RetDone) { - PyErr_SetString(PyExc_Exception, "cannot read STEP file"); - return 0; - } + try { + STEPCAFControl_Reader aReader; + aReader.SetColorMode(true); + aReader.SetNameMode(true); + aReader.SetLayerMode(true); + if (aReader.ReadFile((Standard_CString)Name) != IFSelect_RetDone) { + PyErr_SetString(PyExc_Exception, "cannot read STEP file"); + return 0; + } - Handle_Message_ProgressIndicator pi = new Part::ProgressIndicator(100); - aReader.Reader().WS()->MapReader()->SetProgress(pi); - pi->NewScope(100, "Reading STEP file..."); - pi->Show(); - aReader.Transfer(hDoc); - pi->EndScope(); + Handle_Message_ProgressIndicator pi = new Part::ProgressIndicator(100); + aReader.Reader().WS()->MapReader()->SetProgress(pi); + pi->NewScope(100, "Reading STEP file..."); + pi->Show(); + aReader.Transfer(hDoc); + pi->EndScope(); + } + catch (OSD_Exception) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + Base::Console().Error("%s\n", e->GetMessageString()); + Base::Console().Message("Try to load STEP file without colors...\n"); + + Part::ImportStepParts(pcDoc,Name); + pcDoc->recompute(); + } } else if (file.hasExtension("igs") || file.hasExtension("iges")) { - IGESControl_Controller::Init(); - Interface_Static::SetIVal("read.surfacecurve.mode",3); - IGESCAFControl_Reader aReader; - aReader.SetColorMode(true); - aReader.SetNameMode(true); - aReader.SetLayerMode(true); - if (aReader.ReadFile((Standard_CString)Name) != IFSelect_RetDone) { - PyErr_SetString(PyExc_Exception, "cannot read IGES file"); - return 0; - } + try { + IGESControl_Controller::Init(); + Interface_Static::SetIVal("read.surfacecurve.mode",3); + IGESCAFControl_Reader aReader; + aReader.SetColorMode(true); + aReader.SetNameMode(true); + aReader.SetLayerMode(true); + if (aReader.ReadFile((Standard_CString)Name) != IFSelect_RetDone) { + PyErr_SetString(PyExc_Exception, "cannot read IGES file"); + return 0; + } - Handle_Message_ProgressIndicator pi = new Part::ProgressIndicator(100); - aReader.WS()->MapReader()->SetProgress(pi); - pi->NewScope(100, "Reading IGES file..."); - pi->Show(); - aReader.Transfer(hDoc); - pi->EndScope(); + Handle_Message_ProgressIndicator pi = new Part::ProgressIndicator(100); + aReader.WS()->MapReader()->SetProgress(pi); + pi->NewScope(100, "Reading IGES file..."); + pi->Show(); + aReader.Transfer(hDoc); + pi->EndScope(); + } + catch (OSD_Exception) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + Base::Console().Error("%s\n", e->GetMessageString()); + Base::Console().Message("Try to load IGES file without colors...\n"); + + Part::ImportIgesParts(pcDoc,Name); + pcDoc->recompute(); + } } else { PyErr_SetString(PyExc_Exception, "no supported file format"); diff --git a/src/Mod/Import/Gui/CMakeLists.txt b/src/Mod/Import/Gui/CMakeLists.txt index 4d2862ec7..39193982c 100644 --- a/src/Mod/Import/Gui/CMakeLists.txt +++ b/src/Mod/Import/Gui/CMakeLists.txt @@ -50,6 +50,8 @@ if(MSVC) set_target_properties(ImportGui PROPERTIES DEBUG_OUTPUT_NAME "ImportGui_d") set_target_properties(ImportGui PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Mod/Import) set_target_properties(ImportGui PROPERTIES PREFIX "../") + # Set special compiler flag to convert a SIGSEV into an exception + set_target_properties(ImportGui PROPERTIES COMPILE_FLAGS "/EHa") elseif(MINGW) set_target_properties(ImportGui PROPERTIES SUFFIX ".pyd") set_target_properties(ImportGui PROPERTIES DEBUG_OUTPUT_NAME "ImportGui_d") diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp index 2f5c49189..76ed19154 100644 --- a/src/Mod/Part/App/AppPart.cpp +++ b/src/Mod/Part/App/AppPart.cpp @@ -93,16 +93,6 @@ void PartExport initPart() str << OCC_VERSION_MAJOR << "." << OCC_VERSION_MINOR << "." << OCC_VERSION_MAINTENANCE; App::Application::Config()["OCC_VERSION"] = str.str(); - // see Init.py -#if defined (_OCC64) -#if OCC_VERSION_HEX < 0x060503 - App::GetApplication().addImportType("STEP (*.step *.stp)","Part"); - App::GetApplication().addExportType("STEP (*.step *.stp)","Part"); -#else - App::GetApplication().addImportType("STEP with colors (*.step *.stp)","ImportGui"); - App::GetApplication().addExportType("STEP with colors (*.step *.stp)","ImportGui"); -#endif -#endif // This is highly experimental and we should keep an eye on it // if we have mysterious crashes // The argument must be 'Standard_False' to avoid FPE caused by diff --git a/src/Mod/Part/App/ImportIges.h b/src/Mod/Part/App/ImportIges.h index a6d695710..c527d8be0 100644 --- a/src/Mod/Part/App/ImportIges.h +++ b/src/Mod/Part/App/ImportIges.h @@ -33,7 +33,7 @@ class Document; namespace Part { -int ImportIgesParts(App::Document *pcDoc, const char* Name); +PartExport int ImportIgesParts(App::Document *pcDoc, const char* Name); } //namespace Part diff --git a/src/Mod/Part/App/ImportStep.h b/src/Mod/Part/App/ImportStep.h index 8709e8769..af5e98ad4 100644 --- a/src/Mod/Part/App/ImportStep.h +++ b/src/Mod/Part/App/ImportStep.h @@ -39,7 +39,7 @@ namespace Part /** The part shape property */ -int ImportStepParts(App::Document *pcDoc, const char* Name); +PartExport int ImportStepParts(App::Document *pcDoc, const char* Name); diff --git a/src/Mod/Part/Init.py b/src/Mod/Part/Init.py index 6da3a0373..b81a441b4 100644 --- a/src/Mod/Part/Init.py +++ b/src/Mod/Part/Init.py @@ -49,14 +49,5 @@ FreeCAD.addImportType("BREP format (*.brep *.brp)","Part") FreeCAD.addExportType("BREP format (*.brep *.brp)","Part") FreeCAD.addImportType("IGES format (*.iges *.igs)","Part") FreeCAD.addExportType("IGES format (*.iges *.igs)","Part") - -# There is a bug in OCC 6.5.0 64-bit and older which leads to a crash -# The registration of the STEP filetype for 64-bit is handled in initPart() -import platform -if platform.architecture()[0]=='32bit': - FreeCAD.addImportType("STEP with colors (*.step *.stp)","ImportGui") - FreeCAD.addExportType("STEP with colors (*.step *.stp)","ImportGui") -#else: -# FreeCAD.addImportType("STEP (*.step *.stp)","Part") -# FreeCAD.addExportType("STEP (*.step *.stp)","Part") - +FreeCAD.addImportType("STEP with colors (*.step *.stp)","ImportGui") +FreeCAD.addExportType("STEP with colors (*.step *.stp)","ImportGui") From 9679bacabf4856a3a66cb165da5535953f3d12bd Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 27 Jun 2013 17:07:39 +0200 Subject: [PATCH 113/160] Auto append file extension in file dialog --- src/Gui/FileDialog.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++ src/Gui/FileDialog.h | 8 +++++++ 2 files changed, 62 insertions(+) diff --git a/src/Gui/FileDialog.cpp b/src/Gui/FileDialog.cpp index a34c62fea..a27dca928 100644 --- a/src/Gui/FileDialog.cpp +++ b/src/Gui/FileDialog.cpp @@ -26,11 +26,13 @@ # include # include # include +# include # include # include # include # include # include +# include #endif #include @@ -45,6 +47,32 @@ using namespace Gui; /* TRANSLATOR Gui::FileDialog */ +FileDialog::FileDialog(QWidget * parent) + : QFileDialog(parent) +{ + connect(this, SIGNAL(filterSelected(const QString&)), + this, SLOT(onSelectedFilter(const QString&))); +} + +FileDialog::~FileDialog() +{ +} + +void FileDialog::onSelectedFilter(const QString& filter) +{ + QRegExp rx(QLatin1String("\\(\\*.(\\w+)")); + QString suf = selectedFilter(); + if (rx.indexIn(suf) >= 0) { + suf = rx.cap(1); + setDefaultSuffix(suf); + } +} + +void FileDialog::accept() +{ + QFileDialog::accept(); +} + /** * This is a convenience static function that will return a file name selected by the user. The file does not have to exist. */ @@ -84,7 +112,33 @@ QString FileDialog::getSaveFileName (QWidget * parent, const QString & caption, // NOTE: We must not change the specified file name afterwards as we may return the name of an already // existing file. Hence we must extract the first matching suffix from the filter list and append it // before showing the file dialog. +#if 0 + QList urls; + urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::DesktopLocation)); + urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation)); + urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::HomeLocation)); + urls << QUrl::fromLocalFile(getWorkingDirectory()); + + QString file; + FileDialog dlg(parent); + dlg.setWindowTitle(windowTitle); + dlg.setSidebarUrls(urls); + dlg.setFileMode(QFileDialog::AnyFile); + dlg.setAcceptMode(QFileDialog::AcceptSave); + dlg.setDirectory(dirName); + dlg.setOptions(options); + dlg.setFilters(filter.split(QLatin1String(";;"))); + dlg.onSelectedFilter(dlg.selectedFilter()); + dlg.setNameFilterDetailsVisible(true); + dlg.setConfirmOverwrite(true); + if (dlg.exec() == QDialog::Accepted) { + if (selectedFilter) + *selectedFilter = dlg.selectedFilter(); + file = dlg.selectedFiles().front(); + } +#else QString file = QFileDialog::getSaveFileName(parent, windowTitle, dirName, filter, selectedFilter, options); +#endif if (!file.isEmpty()) { setWorkingDirectory(file); return file; diff --git a/src/Gui/FileDialog.h b/src/Gui/FileDialog.h index 71359dd55..56e0717b2 100644 --- a/src/Gui/FileDialog.h +++ b/src/Gui/FileDialog.h @@ -56,6 +56,14 @@ public: static QString getWorkingDirectory(); static void setWorkingDirectory( const QString& ); + + FileDialog(QWidget * parent = 0); + ~FileDialog(); + + void accept(); + +private Q_SLOTS: + void onSelectedFilter(const QString&); }; // ---------------------------------------------------------------------- From ea08d136f897fc0b39cd04dd5ea0a21122e35474 Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 27 Jun 2013 17:30:33 +0200 Subject: [PATCH 114/160] Activate new file dialog for Linux --- src/Gui/FileDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Gui/FileDialog.cpp b/src/Gui/FileDialog.cpp index a27dca928..028501982 100644 --- a/src/Gui/FileDialog.cpp +++ b/src/Gui/FileDialog.cpp @@ -112,7 +112,7 @@ QString FileDialog::getSaveFileName (QWidget * parent, const QString & caption, // NOTE: We must not change the specified file name afterwards as we may return the name of an already // existing file. Hence we must extract the first matching suffix from the filter list and append it // before showing the file dialog. -#if 0 +#if defined(FC_OS_LINUX) QList urls; urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::DesktopLocation)); urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation)); From b2c635e40c2169198662faefa15530fdd35361ac Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Thu, 27 Jun 2013 20:42:30 -0300 Subject: [PATCH 115/160] 0001032: Preference setting for bounding box colour --- src/Gui/DlgSettingsViewColor.cpp | 2 ++ src/Gui/DlgSettingsViewColor.ui | 30 +++++++++++++++++++++++++- src/Gui/ViewProviderGeometryObject.cpp | 6 +++++- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/Gui/DlgSettingsViewColor.cpp b/src/Gui/DlgSettingsViewColor.cpp index 2bba4faac..bf8f3e216 100644 --- a/src/Gui/DlgSettingsViewColor.cpp +++ b/src/Gui/DlgSettingsViewColor.cpp @@ -71,6 +71,7 @@ void DlgSettingsViewColor::saveSettings() EditedVertexColor->onSave(); ConstructionColor->onSave(); FullyConstrainedColor->onSave(); + BoundingBoxColor->onSave(); DefaultShapeColor->onSave(); DefaultShapeLineColor->onSave(); DefaultShapeLineWidth->onSave(); @@ -94,6 +95,7 @@ void DlgSettingsViewColor::loadSettings() EditedVertexColor->onRestore(); ConstructionColor->onRestore(); FullyConstrainedColor->onRestore(); + BoundingBoxColor->onRestore(); DefaultShapeColor->onRestore(); DefaultShapeLineColor->onRestore(); DefaultShapeLineWidth->onRestore(); diff --git a/src/Gui/DlgSettingsViewColor.ui b/src/Gui/DlgSettingsViewColor.ui index 6acaaeaf9..8a7d92e6f 100644 --- a/src/Gui/DlgSettingsViewColor.ui +++ b/src/Gui/DlgSettingsViewColor.ui @@ -7,7 +7,7 @@ 0 0 601 - 565 + 598 @@ -520,6 +520,33 @@ + + + + Bounding box color + + + + + + + The color of bounding boxes in the 3D view + + + + 255 + 255 + 255 + + + + BoundingBoxColor + + + View + + + @@ -660,6 +687,7 @@ EditedVertexColor ConstructionColor FullyConstrainedColor + BoundingBoxColor radioButtonSimple SelectionColor_Background radioButtonGradient diff --git a/src/Gui/ViewProviderGeometryObject.cpp b/src/Gui/ViewProviderGeometryObject.cpp index a4394338c..698e1e608 100644 --- a/src/Gui/ViewProviderGeometryObject.cpp +++ b/src/Gui/ViewProviderGeometryObject.cpp @@ -482,13 +482,17 @@ SoPickedPoint* ViewProviderGeometryObject::getPickedPoint(const SbVec2s& pos, co void ViewProviderGeometryObject::showBoundingBox(bool show) { if (!pcBoundSwitch && show) { + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); + unsigned long bbcol = hGrp->GetUnsigned("BoundingBoxColor",4294967295UL); // white (255,255,255) + float r,g,b; + r = ((bbcol >> 24) & 0xff) / 255.0; g = ((bbcol >> 16) & 0xff) / 255.0; b = ((bbcol >> 8) & 0xff) / 255.0; pcBoundSwitch = new SoSwitch(); SoSeparator* pBoundingSep = new SoSeparator(); SoDrawStyle* lineStyle = new SoDrawStyle; lineStyle->lineWidth = 2.0f; pBoundingSep->addChild(lineStyle); SoBaseColor* color = new SoBaseColor(); - color->rgb.setValue(1.0f, 1.0f, 1.0f); + color->rgb.setValue(r, g, b); pBoundingSep->addChild(color); pBoundingSep->addChild(new SoTransform()); From c6d512ccabefbd85cdd48fdbad92d0230829a58a Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Fri, 28 Jun 2013 14:13:35 -0300 Subject: [PATCH 116/160] Draft: fixes to dxf & svg exporters to work in console mode --- src/Mod/Draft/Draft.py | 52 ++++++++++++++++++++++++-------------- src/Mod/Draft/importDXF.py | 13 +++++----- 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 26fb53e01..c59f77466 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -1284,15 +1284,16 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct def getLineStyle(obj): "returns a linestyle pattern for a given object" - if obj.ViewObject: - if hasattr(obj.ViewObject,"DrawStyle"): - ds = obj.ViewObject.DrawStyle - if ds == "Dashed": - return "0.09,0.05" - elif ds == "Dashdot": - return "0.09,0.05,0.02,0.05" - elif ds == "Dotted": - return "0.02,0.02" + if gui: + if obj.ViewObject: + if hasattr(obj.ViewObject,"DrawStyle"): + ds = obj.ViewObject.DrawStyle + if ds == "Dashed": + return "0.09,0.05" + elif ds == "Dashdot": + return "0.09,0.05,0.02,0.05" + elif ds == "Dotted": + return "0.02,0.02" return "none" def getProj(vec): @@ -1485,23 +1486,36 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct n += 1 elif obj.isDerivedFrom('Part::Feature'): - if obj.Shape.isNull(): return '' - color = getrgb(obj.ViewObject.LineColor) + if obj.Shape.isNull(): + return '' + if gui: + color = getrgb(obj.ViewObject.LineColor) + else: + color = "#000000" # setting fill - if obj.Shape.Faces and (obj.ViewObject.DisplayMode != "Wireframe"): - if fillstyle == "shape color": - fill = getrgb(obj.ViewObject.ShapeColor) + if obj.Shape.Faces: + if gui: + if (obj.ViewObject.DisplayMode != "Wireframe"): + if fillstyle == "shape color": + fill = getrgb(obj.ViewObject.ShapeColor) + else: + fill = 'url(#'+fillstyle+')' + svg += getPattern(fillstyle) + else: + fill = "none" else: - fill = 'url(#'+fillstyle+')' - svg += getPattern(fillstyle) + fill = "#888888" else: fill = 'none' lstyle = getLineStyle(obj) name = obj.Name - if obj.ViewObject.DisplayMode == "Shaded": - stroke = "none" + if gui: + if obj.ViewObject.DisplayMode == "Shaded": + stroke = "none" + else: + stroke = getrgb(obj.ViewObject.LineColor) else: - stroke = getrgb(obj.ViewObject.LineColor) + stroke = "#000000" if len(obj.Shape.Vertexes) > 1: wiredEdges = [] diff --git a/src/Mod/Draft/importDXF.py b/src/Mod/Draft/importDXF.py index cc563f5d3..494c5166e 100644 --- a/src/Mod/Draft/importDXF.py +++ b/src/Mod/Draft/importDXF.py @@ -43,11 +43,11 @@ import sys, FreeCAD, os, Part, math, re, string, Mesh, Draft, DraftVecUtils, Dra from Draft import _Dimension, _ViewProviderDimension from FreeCAD import Vector -try: import FreeCADGui -except: gui = False -else: gui = True -try: draftui = FreeCADGui.draftToolBar -except: draftui = None +gui = FreeCAD.GuiUp +try: + draftui = FreeCADGui.draftToolBar +except: + draftui = None files = ['dxfColorMap.py','dxfImportObjects.py','dxfLibrary.py','dxfReader.py'] baseurl = 'https://raw.github.com/yorikvanhavre/Draft-dxf-importer/master/' @@ -162,7 +162,8 @@ def getGroup(ob): def getACI(ob,text=False): "gets the ACI color closest to the objects color" - if not gui: return 0 + if not gui: + return 0 else: if text: col=ob.ViewObject.TextColor From 449e71a6b4739d6e12e2bc79b75bcb71fe854f8c Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 29 Jun 2013 15:11:48 +0200 Subject: [PATCH 117/160] Replace native file dialog with Qt's file dialog on Linux --- src/Gui/Document.cpp | 24 ++------------ src/Gui/FileDialog.cpp | 71 +++++++++++++++++++++++++++++++++++++++--- src/Gui/FileDialog.h | 6 ++-- 3 files changed, 72 insertions(+), 29 deletions(-) diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index 6b7fcb884..1629c026a 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -571,28 +571,8 @@ bool Document::saveAs(void) getMainWindow()->showMessage(QObject::tr("Save document under new filename...")); QString exe = qApp->applicationName(); - QString fn = QFileDialog::getSaveFileName(getMainWindow(), QObject::tr("Save %1 Document").arg(exe), - FileDialog::getWorkingDirectory(), QObject::tr("%1 document (*.FCStd)").arg(exe)); - if (!fn.isEmpty()) { - FileDialog::setWorkingDirectory(fn); - QString file = fn.toLower(); - if (!file.endsWith(QLatin1String(".fcstd"))) { - fn += QLatin1String(".fcstd"); - QFileInfo fi; - fi.setFile(fn); - if (fi.exists()) { - // if we auto-append the extension make sure that we don't override an existing file - int ret = QMessageBox::question(getMainWindow(), QObject::tr("Save As"), - QObject::tr("%1 already exists.\n" - "Do you want to replace it?").arg(fn), - QMessageBox::Yes|QMessageBox::Default, - QMessageBox::No|QMessageBox::Escape); - if (ret != QMessageBox::Yes) - fn = QString(); - } - } - } - + QString fn = FileDialog::getSaveFileName(getMainWindow(), QObject::tr("Save %1 Document").arg(exe), + QString(), QObject::tr("%1 document (*.FCStd)").arg(exe)); if (!fn.isEmpty()) { QFileInfo fi; fi.setFile(fn); diff --git a/src/Gui/FileDialog.cpp b/src/Gui/FileDialog.cpp index 028501982..46b044aa6 100644 --- a/src/Gui/FileDialog.cpp +++ b/src/Gui/FileDialog.cpp @@ -32,6 +32,7 @@ # include # include # include +# include # include #endif @@ -64,7 +65,7 @@ void FileDialog::onSelectedFilter(const QString& filter) QString suf = selectedFilter(); if (rx.indexIn(suf) >= 0) { suf = rx.cap(1); - setDefaultSuffix(suf); + setDefaultSuffix(suf.toLower()); } } @@ -117,12 +118,16 @@ QString FileDialog::getSaveFileName (QWidget * parent, const QString & caption, urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::DesktopLocation)); urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation)); urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::HomeLocation)); + urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::MusicLocation)); + urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); + urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::MoviesLocation)); urls << QUrl::fromLocalFile(getWorkingDirectory()); QString file; FileDialog dlg(parent); dlg.setWindowTitle(windowTitle); dlg.setSidebarUrls(urls); + dlg.setIconProvider(new FileIconProvider()); dlg.setFileMode(QFileDialog::AnyFile); dlg.setAcceptMode(QFileDialog::AcceptSave); dlg.setDirectory(dirName); @@ -183,7 +188,36 @@ QString FileDialog::getOpenFileName(QWidget * parent, const QString & caption, c #if defined(FC_OS_MACOSX) options |= QFileDialog::DontUseNativeDialog; #endif + +#if defined(FC_OS_LINUX) + QList urls; + urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::DesktopLocation)); + urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation)); + urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::HomeLocation)); + urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::MusicLocation)); + urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); + urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::MoviesLocation)); + urls << QUrl::fromLocalFile(getWorkingDirectory()); + + QString file; + FileDialog dlg(parent); + dlg.setWindowTitle(windowTitle); + dlg.setSidebarUrls(urls); + dlg.setIconProvider(new FileIconProvider()); + dlg.setFileMode(QFileDialog::ExistingFile); + dlg.setAcceptMode(QFileDialog::AcceptOpen); + dlg.setDirectory(dirName); + dlg.setOptions(options); + dlg.setFilters(filter.split(QLatin1String(";;"))); + dlg.setNameFilterDetailsVisible(true); + if (dlg.exec() == QDialog::Accepted) { + if (selectedFilter) + *selectedFilter = dlg.selectedFilter(); + file = dlg.selectedFiles().front(); + } +#else QString file = QFileDialog::getOpenFileName(parent, windowTitle, dirName, filter, selectedFilter, options); +#endif if (!file.isEmpty()) { setWorkingDirectory(file); return file; @@ -209,7 +243,36 @@ QStringList FileDialog::getOpenFileNames (QWidget * parent, const QString & capt #if defined(FC_OS_MACOSX) options |= QFileDialog::DontUseNativeDialog; #endif + +#if defined(FC_OS_LINUX) + QList urls; + urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::DesktopLocation)); + urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation)); + urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::HomeLocation)); + urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::MusicLocation)); + urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); + urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::MoviesLocation)); + urls << QUrl::fromLocalFile(getWorkingDirectory()); + + QStringList files; + FileDialog dlg(parent); + dlg.setWindowTitle(windowTitle); + dlg.setSidebarUrls(urls); + dlg.setIconProvider(new FileIconProvider()); + dlg.setFileMode(QFileDialog::ExistingFiles); + dlg.setAcceptMode(QFileDialog::AcceptOpen); + dlg.setDirectory(dirName); + dlg.setOptions(options); + dlg.setFilters(filter.split(QLatin1String(";;"))); + dlg.setNameFilterDetailsVisible(true); + if (dlg.exec() == QDialog::Accepted) { + if (selectedFilter) + *selectedFilter = dlg.selectedFilter(); + files = dlg.selectedFiles(); + } +#else QStringList files = QFileDialog::getOpenFileNames(parent, windowTitle, dirName, filter, selectedFilter, options); +#endif if (!files.isEmpty()) { setWorkingDirectory(files.front()); } @@ -376,17 +439,17 @@ FileIconProvider::~FileIconProvider() { } -QIcon FileIconProvider::icon ( IconType type ) const +QIcon FileIconProvider::icon(IconType type) const { return QFileIconProvider::icon(type); } -QIcon FileIconProvider::icon ( const QFileInfo & info ) const +QIcon FileIconProvider::icon(const QFileInfo & info) const { return QFileIconProvider::icon(info); } -QString FileIconProvider::type ( const QFileInfo & info ) const +QString FileIconProvider::type(const QFileInfo & info) const { return QFileIconProvider::type(info); } diff --git a/src/Gui/FileDialog.h b/src/Gui/FileDialog.h index 56e0717b2..ddca6a647 100644 --- a/src/Gui/FileDialog.h +++ b/src/Gui/FileDialog.h @@ -113,9 +113,9 @@ public: FileIconProvider(); ~FileIconProvider(); - QIcon icon ( IconType type ) const; - QIcon icon ( const QFileInfo & info ) const; - QString type ( const QFileInfo & info ) const; + QIcon icon(IconType type) const; + QIcon icon(const QFileInfo & info) const; + QString type(const QFileInfo & info) const; }; // ---------------------------------------------------------------------- From 75755c62a435af842f92d50e433eb61e8ddebf14 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 29 Jun 2013 15:52:55 +0200 Subject: [PATCH 118/160] 0001026: Suppress CMake warning if OCE wasn't found but OCC was found --- CMakeLists.txt | 86 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c45d8da3..2912ffcbe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -209,30 +209,64 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X) #first, look for OpenCASCADE Community Edition (OCE) #if OCE is installed in a nonstandard location, add -DOCE_DIR=/path/to/dir/containing/OCEConfig.cmake # when configuring with cmake, i.e. cmake .. -DOCE_DIR=/usr/share/cmake - if( NOT DEFINED OCE_DIR ) - if( UNIX ) - set( OCE_DIR "/usr/local/share/cmake/" ) - else() - set( OCE_DIR "c:/OCE-0.4.0/share/cmake" ) - endif() - endif() - find_package ( OCE ) - if( ${OCE_FOUND} ) - message("-- OpenCASCADE Community Edition has been found.") - add_definitions ( -DHAVE_CONFIG_H ) - set( OCC_LIBRARIES "TKFeat;TKFillet;TKMesh;TKernel;TKG2d;TKG3d;TKMath;TKIGES;TKSTL;TKShHealing;TKXSBase;TKBool;TKBO;TKBRep;TKTopAlgo;TKGeomAlgo;TKGeomBase;TKOffset;TKPrim;TKSTEP;TKSTEPBase;TKSTEPAttr;TKHLR" ) #lib list copied from FreeCAD's FindOpenCasCade.cmake - set( OCC_OCAF_LIBRARIES "TKCAF;TKXCAF;TKLCAF;TKXDESTEP;TKXDEIGES;TKMeshVS;TKAdvTools" ) #lib list copied from FreeCAD's FindOpenCasCade.cmake - set( OCC_INCLUDE_DIR ${OCE_INCLUDE_DIRS} ) - set( OCC_FOUND ${OCE_FOUND} ) - else() #look for OpenCASCADE - find_package(OpenCasCade) - IF(NOT OCC_FOUND) - MESSAGE("Neither OpenCASCADE Community Edition nor OpenCasCade were found: will not build CAD modules!") - ELSE() - MESSAGE("-- OpenCASCADE include directory: ${OCC_INCLUDE_PATH}") - MESSAGE("-- OpenCASCADE shared libraries directory: ${OCC_LIB_PATH}") - ENDIF() - endif() + if(NOT DEFINED OCE_DIR) + if(UNIX) + set(OCE_DIR "/usr/local/share/cmake/") + elif(WIN32) + set(OCE_DIR "c:/OCE-0.4.0/share/cmake") + endif() + endif() + find_package (OCE QUIET) + if(${OCE_FOUND}) + message("-- OpenCASCADE Community Edition has been found.") + add_definitions (-DHAVE_CONFIG_H) + #lib list copied from FreeCAD's FindOpenCasCade.cmake + set(OCC_LIBRARIES + TKFillet + TKMesh + TKernel + TKG2d + TKG3d + TKMath + TKIGES + TKSTL + TKShHealing + TKXSBase + TKBool + TKBO + TKBRep + TKTopAlgo + TKGeomAlgo + TKGeomBase + TKOffset + TKPrim + TKSTEP + TKSTEPBase + TKSTEPAttr + TKHLR + TKFeat + ) + #lib list copied from FreeCAD's FindOpenCasCade.cmake + set(OCC_OCAF_LIBRARIES + TKCAF + TKXCAF + TKLCAF + TKXDESTEP + TKXDEIGES + TKMeshVS + TKAdvTools + ) + set(OCC_INCLUDE_DIR ${OCE_INCLUDE_DIRS}) + set(OCC_FOUND ${OCE_FOUND}) + else() #look for OpenCASCADE + find_package(OpenCasCade) + if(NOT OCC_FOUND) + message("Neither OpenCASCADE Community Edition nor OpenCasCade were found: will not build CAD modules!") + else() + message("-- OpenCASCADE include directory: ${OCC_INCLUDE_PATH}") + message("-- OpenCASCADE shared libraries directory: ${OCC_LIB_PATH}") + endif() + endif() # -------------------------------- Salome SMESH -------------------------- @@ -364,11 +398,11 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X) # -------------------------------- Shiboken/PySide ------------------------ - find_package(Shiboken) + find_package(Shiboken QUIET) IF(SHIBOKEN_INCLUDE_DIR) message("-- Shiboken has been found.") ENDIF(SHIBOKEN_INCLUDE_DIR) - find_package(PySide) + find_package(PySide QUIET) IF(PYSIDE_INCLUDE_DIR) message("-- PySide has been found.") ENDIF(PYSIDE_INCLUDE_DIR) From 5df0638aecf96568e7e33c7bf396b782c8cb694c Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sat, 29 Jun 2013 12:05:45 -0300 Subject: [PATCH 119/160] Arch: Removed obsolete ArchCell.py --- src/Mod/Arch/Arch.py | 1 - src/Mod/Arch/ArchCell.py | 155 ------------------------------- src/Mod/Arch/CMakeLists.txt | 1 - src/WindowsInstaller/ModArch.wxi | 1 - 4 files changed, 158 deletions(-) delete mode 100644 src/Mod/Arch/ArchCell.py diff --git a/src/Mod/Arch/Arch.py b/src/Mod/Arch/Arch.py index fc537d85a..77c0b9534 100644 --- a/src/Mod/Arch/Arch.py +++ b/src/Mod/Arch/Arch.py @@ -30,7 +30,6 @@ import FreeCADGui FreeCADGui.updateLocale() from ArchWall import * -from ArchCell import * from ArchFloor import * from ArchSite import * from ArchBuilding import * diff --git a/src/Mod/Arch/ArchCell.py b/src/Mod/Arch/ArchCell.py deleted file mode 100644 index 73fa2d21f..000000000 --- a/src/Mod/Arch/ArchCell.py +++ /dev/null @@ -1,155 +0,0 @@ -#*************************************************************************** -#* * -#* Copyright (c) 2011 * -#* Yorik van Havre * -#* * -#* 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 * -#* * -#*************************************************************************** - -#### WARNING: CELL OBJECT IS OBSOLETED - -import FreeCAD,FreeCADGui,Draft,ArchComponent,ArchCommands -from FreeCAD import Vector -from PyQt4 import QtCore - -__title__="FreeCAD Cell" -__author__ = "Yorik van Havre" -__url__ = "http://free-cad.sourceforge.net" - -def makeCell(objectslist=None,join=True,name="Cell"): - '''makeCell([objectslist],[joinmode]): creates a cell including the - objects from the given list. If joinmode is False, contents will - not be joined.''' - obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name) - _Cell(obj) - _ViewProviderCell(obj.ViewObject) - if objectslist: - obj.Components = objectslist - for comp in obj.Components: - comp.ViewObject.hide() - obj.JoinMode = join - return obj - -class _CommandCell: - "the Arch Cell command definition" - def GetResources(self): - return {'Pixmap' : 'Arch_Cell', - 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_Cell","Cell"), - 'Accel': "C, E", - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Cell","Creates a cell object including selected objects")} - - def Activated(self): - sel = FreeCADGui.Selection.getSelection() - ok = False - if (len(sel) == 1): - if Draft.getType(sel[0]) in ["Floor","Site","Building"]: - FreeCAD.ActiveDocument.openTransaction("Type conversion") - nobj = makeCell() - ArchCommands.copyProperties(sel[0],nobj) - FreeCAD.ActiveDocument.removeObject(sel[0].Name) - FreeCAD.ActiveDocument.commitTransaction() - ok = True - if not ok: - FreeCAD.ActiveDocument.openTransaction("Cell") - makeCell(sel) - FreeCAD.ActiveDocument.commitTransaction() - FreeCAD.ActiveDocument.recompute() - -class _Cell(ArchComponent.Component): - "The Cell object" - def __init__(self,obj): - obj.addProperty("App::PropertyLinkList","Components","Base", - "The objects that make part of this cell") - obj.addProperty("App::PropertyBool","JoinMode","Base", - "If True, underlying geometry will be joined") - obj.Proxy = self - self.Type = "Cell" - - def execute(self,obj): - self.createGeometry(obj) - - def onChanged(self,obj,prop): - if prop in ["Components","JoinMode"]: - self.createGeometry(obj) - - def createGeometry(self,obj): - import Part - pl = obj.Placement - if obj.Components: - shapes = [] - if obj.JoinMode: - walls = [] - structs = [] - for c in obj.Components: - if Draft.getType(c) == "Wall": - walls.append(c.Shape) - elif Draft.getType(c) == "Structure": - structs.append(c.Shape) - else: - shapes.append(c.Shape) - for group in [walls,structs]: - if group: - sh = group.pop(0).copy() - for subsh in group: - sh = sh.oldFuse(subsh) - shapes.append(sh) - else: - for c in obj.Components: - shapes.append(c.Shape) - if shapes: - obj.Shape = Part.makeCompound(shapes) - obj.Placement = pl - -class _ViewProviderCell(ArchComponent.ViewProviderComponent): - "A View Provider for the Cell object" - def __init__(self,vobj): - ArchComponent.ViewProviderComponent.__init__(self,vobj) - vobj.Proxy = self - self.Object = vobj.Object - - def getIcon(self): - import Arch_rc - return ":/icons/Arch_Cell_Tree.svg" - - def updateData(self,obj,prop): - return - - def onChanged(self,vobj,prop): - return - - def claimChildren(self): - return self.Object.Components - - def attach(self,vobj): - self.Object = vobj.Object - return - - def getDisplayModes(self,obj): - modes=[] - return modes - - def setDisplayMode(self,mode): - return mode - - def __getstate__(self): - return None - - def __setstate__(self,state): - return None - -FreeCADGui.addCommand('Arch_Cell',_CommandCell()) diff --git a/src/Mod/Arch/CMakeLists.txt b/src/Mod/Arch/CMakeLists.txt index 28f691455..76d09e80d 100644 --- a/src/Mod/Arch/CMakeLists.txt +++ b/src/Mod/Arch/CMakeLists.txt @@ -3,7 +3,6 @@ SET(Arch_SRCS Init.py InitGui.py ArchComponent.py - ArchCell.py ArchWall.py importIFC.py ifcReader.py diff --git a/src/WindowsInstaller/ModArch.wxi b/src/WindowsInstaller/ModArch.wxi index d43d16aef..7e28c9302 100644 --- a/src/WindowsInstaller/ModArch.wxi +++ b/src/WindowsInstaller/ModArch.wxi @@ -29,7 +29,6 @@ - From 215775b7f217ef3a9527310f3695f257415ebb41 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 30 Jun 2013 11:00:54 +0200 Subject: [PATCH 120/160] Fix error in CMake file --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2912ffcbe..91d447c10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -212,7 +212,7 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X) if(NOT DEFINED OCE_DIR) if(UNIX) set(OCE_DIR "/usr/local/share/cmake/") - elif(WIN32) + elseif(WIN32) set(OCE_DIR "c:/OCE-0.4.0/share/cmake") endif() endif() From 873730effec1e5915cf67e6c9dde264b447d77d7 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 30 Jun 2013 11:01:09 +0200 Subject: [PATCH 121/160] PySide stuff --- src/Gui/WidgetFactory.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Gui/WidgetFactory.cpp b/src/Gui/WidgetFactory.cpp index 2996f2592..a499c326b 100644 --- a/src/Gui/WidgetFactory.cpp +++ b/src/Gui/WidgetFactory.cpp @@ -23,7 +23,10 @@ #include "PreCompiled.h" -#if 0 // disable for now +// Remove this block when activating PySide support! +#undef HAVE_SHIBOKEN +#undef HAVE_PYSIDE + #ifdef HAVE_SHIBOKEN # undef _POSIX_C_SOURCE # undef _XOPEN_SOURCE @@ -35,7 +38,6 @@ PyTypeObject** SbkPySide_QtCoreTypes=NULL; # endif #endif -#endif #include #include @@ -57,9 +59,8 @@ PythonWrapper::PythonWrapper() QObject* PythonWrapper::toQObject(const Py::Object& pyobject) { -#if 0 // http://pastebin.com/JByDAF5Z -//#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) +#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) PyTypeObject * type = Shiboken::SbkType(); if (type) { if (Shiboken::Object::checkType(pyobject.ptr())) { @@ -95,8 +96,7 @@ Py::Object PythonWrapper::toPython(QWidget* widget) bool PythonWrapper::loadModule() { -#if 0 -//#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) +#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) if (SbkPySide_QtCoreTypes) return true; // already loaded Shiboken::AutoDecRef requiredModule(Shiboken::Module::import("PySide.QtCore")); From c6d23d15980056eecd230b8cfc6d05e82e8843a1 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 30 Jun 2013 15:14:02 +0200 Subject: [PATCH 122/160] PySide binding --- src/Gui/CMakeLists.txt | 2 ++ src/Gui/TaskView/TaskDialogPython.cpp | 4 +-- src/Gui/WidgetFactory.cpp | 48 +++++++++++++++++++++------ src/Gui/WidgetFactory.h | 3 +- 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 20849aedc..3c442c80f 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -75,6 +75,8 @@ if(PYSIDE_INCLUDE_DIR) add_definitions(-DHAVE_PYSIDE) include_directories( ${PYSIDE_INCLUDE_DIR} + ${PYSIDE_INCLUDE_DIR}/QtCore + ${PYSIDE_INCLUDE_DIR}/QtGui ) set(FreeCADGui_LIBS ${FreeCADGui_LIBS} diff --git a/src/Gui/TaskView/TaskDialogPython.cpp b/src/Gui/TaskView/TaskDialogPython.cpp index c087e051e..71c9e02ea 100644 --- a/src/Gui/TaskView/TaskDialogPython.cpp +++ b/src/Gui/TaskView/TaskDialogPython.cpp @@ -195,7 +195,7 @@ TaskWatcherPython::TaskWatcherPython(const Py::Object& o) Py::List list(watcher.getAttr(std::string("widgets"))); Gui::PythonWrapper wrap; - if (wrap.loadModule()) { + if (wrap.loadCoreModule()) { for (Py::List::iterator it = list.begin(); it != list.end(); ++it) { QObject* object = wrap.toQObject(*it); if (object) { @@ -293,7 +293,7 @@ TaskDialogPython::TaskDialogPython(const Py::Object& o) : dlg(o) } Gui::PythonWrapper wrap; - if (wrap.loadModule()) { + if (wrap.loadCoreModule()) { for (Py::List::iterator it = widgets.begin(); it != widgets.end(); ++it) { QObject* object = wrap.toQObject(*it); if (object) { diff --git a/src/Gui/WidgetFactory.cpp b/src/Gui/WidgetFactory.cpp index a499c326b..12f5b9a5e 100644 --- a/src/Gui/WidgetFactory.cpp +++ b/src/Gui/WidgetFactory.cpp @@ -34,8 +34,10 @@ # include # include # ifdef HAVE_PYSIDE -# include +# include +# include PyTypeObject** SbkPySide_QtCoreTypes=NULL; +PyTypeObject** SbkPySide_QtGuiTypes=NULL; # endif #endif @@ -84,7 +86,16 @@ QObject* PythonWrapper::toQObject(const Py::Object& pyobject) Py::Object PythonWrapper::toPython(QWidget* widget) { - // todo: Port to PySide +#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) + PyTypeObject * type = Shiboken::SbkType(); + if (type) { + SbkObjectType* sbk_type = reinterpret_cast(type); + std::string typeName = widget->metaObject()->className(); + PyObject* pyobj = Shiboken::Object::newObject(sbk_type, widget, false, false, typeName.c_str()); + return Py::Object(pyobj); + } + throw Py::RuntimeError("Failed to wrap widget"); +#else Py::Module sipmod(PyImport_AddModule((char*)"sip")); Py::Callable func = sipmod.getDict().getItem("wrapinstance"); Py::Tuple arguments(2); @@ -92,17 +103,33 @@ Py::Object PythonWrapper::toPython(QWidget* widget) Py::Module qtmod(PyImport_ImportModule((char*)"PyQt4.Qt")); arguments[1] = qtmod.getDict().getItem("QWidget"); return func.apply(arguments); +#endif } -bool PythonWrapper::loadModule() +bool PythonWrapper::loadCoreModule() { #if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) - if (SbkPySide_QtCoreTypes) - return true; // already loaded - Shiboken::AutoDecRef requiredModule(Shiboken::Module::import("PySide.QtCore")); - if (requiredModule.isNull()) - return false; - SbkPySide_QtCoreTypes = Shiboken::Module::getTypes(requiredModule); + // QtCore + if (!SbkPySide_QtCoreTypes) { + Shiboken::AutoDecRef requiredModule(Shiboken::Module::import("PySide.QtCore")); + if (requiredModule.isNull()) + return false; + SbkPySide_QtCoreTypes = Shiboken::Module::getTypes(requiredModule); + } +#endif + return true; +} + +bool PythonWrapper::loadGuiModule() +{ +#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) + // QtGui + if (!SbkPySide_QtGuiTypes) { + Shiboken::AutoDecRef requiredModule(Shiboken::Module::import("PySide.QtGui")); + if (requiredModule.isNull()) + return false; + SbkPySide_QtGuiTypes = Shiboken::Module::getTypes(requiredModule); + } #endif return true; } @@ -311,7 +338,7 @@ Py::Object UiLoaderPy::createWidget(const Py::Tuple& args) // 2nd argument QWidget* parent = 0; - if (wrap.loadModule() && args.size() > 1) { + if (wrap.loadCoreModule() && args.size() > 1) { QObject* object = wrap.toQObject(args[1]); if (object) parent = qobject_cast(object); @@ -325,6 +352,7 @@ Py::Object UiLoaderPy::createWidget(const Py::Tuple& args) QWidget* widget = loader.createWidget(QString::fromAscii(className.c_str()), parent, QString::fromAscii(objectName.c_str())); + wrap.loadGuiModule(); return wrap.toPython(widget); } diff --git a/src/Gui/WidgetFactory.h b/src/Gui/WidgetFactory.h index 5442c7efc..7f5faa0cf 100644 --- a/src/Gui/WidgetFactory.h +++ b/src/Gui/WidgetFactory.h @@ -43,7 +43,8 @@ class GuiExport PythonWrapper { public: PythonWrapper(); - bool loadModule(); + bool loadCoreModule(); + bool loadGuiModule(); QObject* toQObject(const Py::Object&); Py::Object toPython(QWidget*); From 9e546120bc63a95a21a56981a67a3a027964a26b Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 30 Jun 2013 19:07:41 +0200 Subject: [PATCH 123/160] 0000920: Hide turntable dialog when in fullscreen mode --- src/Gui/DemoMode.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ src/Gui/DemoMode.h | 7 +++++++ 2 files changed, 50 insertions(+) diff --git a/src/Gui/DemoMode.cpp b/src/Gui/DemoMode.cpp index 2d36af572..6afc147d4 100644 --- a/src/Gui/DemoMode.cpp +++ b/src/Gui/DemoMode.cpp @@ -26,6 +26,7 @@ # include # include # include +# include # include #include #endif @@ -53,6 +54,11 @@ DemoMode::DemoMode(QWidget* parent, Qt::WFlags fl) timer->setInterval(1000 * ui->timeout->value()); connect(timer, SIGNAL(timeout()), this, SLOT(onAutoPlay())); oldvalue = ui->angleSlider->value(); + + wasHidden = false; + showHideTimer = new QTimer(this); + showHideTimer->setInterval(5000); + connect(showHideTimer, SIGNAL(timeout()), this, SLOT(hide())); } /** Destroys the object and frees any allocated resources */ @@ -82,6 +88,35 @@ void DemoMode::reject() QDialog::reject(); } +bool DemoMode::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::MouseMove) { + if (ui->fullscreen->isChecked()) { + QPoint point = QCursor::pos() - oldPos; + if (point.manhattanLength() > 10) { + show(); + showHideTimer->start(); + } + } + } + return QDialog::eventFilter(obj, event); +} + +void DemoMode::showEvent(QShowEvent *) +{ + if (this->wasHidden) + this->move(this->pnt); + this->wasHidden = false; +} + +void DemoMode::hideEvent(QHideEvent *) +{ + this->pnt = this->pos(); + this->wasHidden = true; + this->oldPos = QCursor::pos(); + showHideTimer->stop(); +} + Gui::View3DInventor* DemoMode::activeView() const { Document* doc = Application::Instance->activeDocument(); @@ -186,6 +221,14 @@ void DemoMode::on_fullscreen_toggled(bool on) view->setCurrentViewMode(on ? MDIView::/*TopLevel*/FullScreen : MDIView::Child); this->activateWindow(); } + if (on) { + qApp->installEventFilter(this); + showHideTimer->start(); + } + else { + qApp->removeEventFilter(this); + showHideTimer->stop(); + } } void DemoMode::on_timeout_valueChanged(int v) diff --git a/src/Gui/DemoMode.h b/src/Gui/DemoMode.h index 0c047005c..1f4fb67ea 100644 --- a/src/Gui/DemoMode.h +++ b/src/Gui/DemoMode.h @@ -68,12 +68,19 @@ private: Gui::View3DInventor* activeView() const; void startAnimation(Gui::View3DInventor*); void changeEvent(QEvent *e); + bool eventFilter(QObject *, QEvent *); + void showEvent(QShowEvent *); + void hideEvent(QHideEvent *); private: int oldvalue; SbVec3f viewAxis; + bool wasHidden; + QPoint pnt; + QPoint oldPos; Ui_DemoMode* ui; QTimer* timer; + QTimer* showHideTimer; }; } // namespace Dialog From 112b25f9fcf7c5bab39cde3d291c840c3fe9ec3d Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 30 Jun 2013 23:34:24 +0200 Subject: [PATCH 124/160] Expose getMainWindow() to Python --- src/Gui/Application.h | 1 + src/Gui/ApplicationPy.cpp | 19 +++++++++++++++++++ src/Gui/WidgetFactory.cpp | 12 ++++++++---- src/Gui/WidgetFactory.h | 2 +- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/Gui/Application.h b/src/Gui/Application.h index 73945fca4..8d4aefe5a 100644 --- a/src/Gui/Application.h +++ b/src/Gui/Application.h @@ -211,6 +211,7 @@ public: PYFUNCDEF_S(sSendActiveView); + PYFUNCDEF_S(sGetMainWindow); PYFUNCDEF_S(sUpdateGui); PYFUNCDEF_S(sUpdateLocale); PYFUNCDEF_S(sGetLocale); diff --git a/src/Gui/ApplicationPy.cpp b/src/Gui/ApplicationPy.cpp index 31df22271..fb3de1211 100644 --- a/src/Gui/ApplicationPy.cpp +++ b/src/Gui/ApplicationPy.cpp @@ -83,6 +83,9 @@ PyMethodDef Application::Methods[] = { {"addIcon", (PyCFunction) Application::sAddIcon, 1, "addIcon(string, string or list) -> None\n\n" "Add an icon as file name or in XPM format to the system"}, + {"getMainWindow", (PyCFunction) Application::sGetMainWindow, 1, + "getMainWindow() -> QMainWindow\n\n" + "Return the main window instance"}, {"updateGui", (PyCFunction) Application::sUpdateGui, 1, "updateGui() -> None\n\n" "Update the main window and all its windows"}, @@ -418,6 +421,22 @@ PyObject* Application::sSendActiveView(PyObject * /*self*/, PyObject *args,PyObj return Py_None; } +PyObject* Application::sGetMainWindow(PyObject * /*self*/, PyObject *args,PyObject * /*kwd*/) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + + PythonWrapper wrap; + wrap.loadCoreModule(); + wrap.loadGuiModule(); + try { + return Py::new_reference_to(wrap.fromQWidget(Gui::getMainWindow(), "QMainWindow")); + } + catch (const Py::Exception&) { + return 0; + } +} + PyObject* Application::sUpdateGui(PyObject * /*self*/, PyObject *args,PyObject * /*kwd*/) { if (!PyArg_ParseTuple(args, "")) // convert args: Python->C diff --git a/src/Gui/WidgetFactory.cpp b/src/Gui/WidgetFactory.cpp index 12f5b9a5e..caf4b9be2 100644 --- a/src/Gui/WidgetFactory.cpp +++ b/src/Gui/WidgetFactory.cpp @@ -84,15 +84,19 @@ QObject* PythonWrapper::toQObject(const Py::Object& pyobject) return 0; } -Py::Object PythonWrapper::toPython(QWidget* widget) +Py::Object PythonWrapper::fromQWidget(QWidget* widget, const char* className) { #if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) PyTypeObject * type = Shiboken::SbkType(); if (type) { SbkObjectType* sbk_type = reinterpret_cast(type); - std::string typeName = widget->metaObject()->className(); + std::string typeName; + if (className) + typeName = className; + else + typeName = widget->metaObject()->className(); PyObject* pyobj = Shiboken::Object::newObject(sbk_type, widget, false, false, typeName.c_str()); - return Py::Object(pyobj); + return Py::asObject(pyobj); } throw Py::RuntimeError("Failed to wrap widget"); #else @@ -353,7 +357,7 @@ Py::Object UiLoaderPy::createWidget(const Py::Tuple& args) QWidget* widget = loader.createWidget(QString::fromAscii(className.c_str()), parent, QString::fromAscii(objectName.c_str())); wrap.loadGuiModule(); - return wrap.toPython(widget); + return wrap.fromQWidget(widget); } // ---------------------------------------------------- diff --git a/src/Gui/WidgetFactory.h b/src/Gui/WidgetFactory.h index 7f5faa0cf..44690d587 100644 --- a/src/Gui/WidgetFactory.h +++ b/src/Gui/WidgetFactory.h @@ -47,7 +47,7 @@ public: bool loadGuiModule(); QObject* toQObject(const Py::Object&); - Py::Object toPython(QWidget*); + Py::Object fromQWidget(QWidget*, const char* className=0); }; /** From 0361730d986b382639a4985d7db9909829ddc023 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 1 Jul 2013 12:50:00 +0200 Subject: [PATCH 125/160] + do not reset viewing mode when animating 3d view --- src/Gui/BlenderNavigationStyle.cpp | 2 +- src/Gui/CADNavigationStyle.cpp | 2 +- src/Gui/DemoMode.cpp | 2 +- src/Gui/InventorNavigationStyle.cpp | 2 +- src/Gui/TouchpadNavigationStyle.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Gui/BlenderNavigationStyle.cpp b/src/Gui/BlenderNavigationStyle.cpp index 2b782a19f..1769cdf90 100644 --- a/src/Gui/BlenderNavigationStyle.cpp +++ b/src/Gui/BlenderNavigationStyle.cpp @@ -84,7 +84,7 @@ SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev) // up the inheritance hierarchy. if (this->isSeekMode()) { return inherited::processSoEvent(ev); } // Switch off viewing mode (Bug #0000911) - if (!this->isSeekMode() && this->isViewing()) + if (!this->isSeekMode() && !this->isAnimating() && this->isViewing()) this->setViewing(false); // by default disable viewing mode to render the scene const SoType type(ev->getTypeId()); diff --git a/src/Gui/CADNavigationStyle.cpp b/src/Gui/CADNavigationStyle.cpp index 0aded9a73..8b3687bbe 100644 --- a/src/Gui/CADNavigationStyle.cpp +++ b/src/Gui/CADNavigationStyle.cpp @@ -86,7 +86,7 @@ SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev) if (this->isSeekMode()) { return inherited::processSoEvent(ev); } #else // Switch off viewing mode (Bug #0000911) - if (!this->isSeekMode() && this->isViewing()) + if (!this->isSeekMode() && !this->isAnimating() && this->isViewing()) this->setViewing(false); // by default disable viewing mode to render the scene #endif diff --git a/src/Gui/DemoMode.cpp b/src/Gui/DemoMode.cpp index 6afc147d4..50217352e 100644 --- a/src/Gui/DemoMode.cpp +++ b/src/Gui/DemoMode.cpp @@ -93,7 +93,7 @@ bool DemoMode::eventFilter(QObject *obj, QEvent *event) if (event->type() == QEvent::MouseMove) { if (ui->fullscreen->isChecked()) { QPoint point = QCursor::pos() - oldPos; - if (point.manhattanLength() > 10) { + if (point.manhattanLength() > 5) { show(); showHideTimer->start(); } diff --git a/src/Gui/InventorNavigationStyle.cpp b/src/Gui/InventorNavigationStyle.cpp index 1f48dd4b1..b8a3659cc 100644 --- a/src/Gui/InventorNavigationStyle.cpp +++ b/src/Gui/InventorNavigationStyle.cpp @@ -84,7 +84,7 @@ SbBool InventorNavigationStyle::processSoEvent(const SoEvent * const ev) // up the inheritance hierarchy. if (this->isSeekMode()) { return inherited::processSoEvent(ev); } // Switch off viewing mode (Bug #0000911) - if (!this->isSeekMode() && this->isViewing()) + if (!this->isSeekMode()&& !this->isAnimating() && this->isViewing() ) this->setViewing(false); // by default disable viewing mode to render the scene const SoType type(ev->getTypeId()); diff --git a/src/Gui/TouchpadNavigationStyle.cpp b/src/Gui/TouchpadNavigationStyle.cpp index cef63a384..a8552ac79 100644 --- a/src/Gui/TouchpadNavigationStyle.cpp +++ b/src/Gui/TouchpadNavigationStyle.cpp @@ -84,7 +84,7 @@ SbBool TouchpadNavigationStyle::processSoEvent(const SoEvent * const ev) // up the inheritance hierarchy. if (this->isSeekMode()) { return inherited::processSoEvent(ev); } // Switch off viewing mode (Bug #0000911) - if (!this->isSeekMode() && this->isViewing()) + if (!this->isSeekMode() && !this->isAnimating() && this->isViewing()) this->setViewing(false); // by default disable viewing mode to render the scene const SoType type(ev->getTypeId()); From f5d091fc9619b161b57de0f6f5c2e9da2abd1f0f Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 1 Jul 2013 13:08:47 +0200 Subject: [PATCH 126/160] 0000849: [Sketcher] Small inconsistency with update --- src/Mod/Sketcher/Gui/EditDatumDialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Mod/Sketcher/Gui/EditDatumDialog.cpp b/src/Mod/Sketcher/Gui/EditDatumDialog.cpp index 80de72074..31a60bced 100644 --- a/src/Mod/Sketcher/Gui/EditDatumDialog.cpp +++ b/src/Mod/Sketcher/Gui/EditDatumDialog.cpp @@ -131,6 +131,7 @@ void EditDatumDialog::exec(bool atCursor) sketch->getNameInDocument(), ConstrNbr, newDatum); Gui::Command::commitCommand(); + Gui::Command::updateActive(); } catch (const Base::Exception& e) { QMessageBox::critical(qApp->activeWindow(), QObject::tr("Dimensional constraint"), QString::fromUtf8(e.what())); From 0de46dcd0e6717018114d0403431f6d185fb8c15 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 1 Jul 2013 14:00:55 +0200 Subject: [PATCH 127/160] 0001025: wireframe mode should include vertices in display --- src/Mod/Part/Gui/ViewProviderExt.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Mod/Part/Gui/ViewProviderExt.cpp b/src/Mod/Part/Gui/ViewProviderExt.cpp index cf35e4a14..57eae9145 100644 --- a/src/Mod/Part/Gui/ViewProviderExt.cpp +++ b/src/Mod/Part/Gui/ViewProviderExt.cpp @@ -349,8 +349,14 @@ void ViewProviderPartExt::attach(App::DocumentObject *pcFeat) // The correct order is Edges, Polygon offset, Faces. SoPolygonOffset* offset = new SoPolygonOffset(); + // wireframe node + SoSeparator* wireframe = new SoSeparator(); + wireframe->addChild(pcLineMaterial); + wireframe->addChild(pcLineStyle); + wireframe->addChild(lineset); + // normal viewing with edges and points - pcNormalRoot->addChild(pcWireframeRoot); + pcNormalRoot->addChild(wireframe); pcNormalRoot->addChild(offset); pcNormalRoot->addChild(pcFlatRoot); pcNormalRoot->addChild(pcPointsRoot); @@ -366,10 +372,9 @@ void ViewProviderPartExt::attach(App::DocumentObject *pcFeat) pcFlatRoot->addChild(normb); pcFlatRoot->addChild(faceset); - // only edges - pcWireframeRoot->addChild(pcLineMaterial); - pcWireframeRoot->addChild(pcLineStyle); - pcWireframeRoot->addChild(lineset); + // edges and points + pcWireframeRoot->addChild(wireframe); + pcWireframeRoot->addChild(pcPointsRoot); // normal viewing with edges and points pcPointsRoot->addChild(pcPointMaterial); From 7533517bb2e2616ad2bcac30f5ac74d089a88202 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 1 Jul 2013 14:03:45 +0200 Subject: [PATCH 128/160] 0001021: add directory to findCoin cmake --- cMake/FindCoin3D.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cMake/FindCoin3D.cmake b/cMake/FindCoin3D.cmake index 710768740..5f09c3dbe 100644 --- a/cMake/FindCoin3D.cmake +++ b/cMake/FindCoin3D.cmake @@ -13,6 +13,7 @@ IF (WIN32) FIND_PATH(COIN3D_INCLUDE_DIR Inventor/So.h /usr/include /usr/local/include + /usr/include/coin ) FIND_LIBRARY(COIN3D_LIBRARY Coin From 7501475e66519d1d3c57feadb9521c7e6f0e70c2 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Mon, 1 Jul 2013 12:53:43 -0300 Subject: [PATCH 129/160] Draft: Fixed bug in trim tool --- src/Mod/Draft/Draft.py | 2 ++ src/Mod/Draft/DraftTools.py | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index c59f77466..d44414748 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -165,6 +165,8 @@ def getType(obj): return obj.Proxy.Type if obj.isDerivedFrom("Sketcher::SketchObject"): return "Sketch" + if (obj.TypeId == "Part::Line"): + return "Part::Line" if obj.isDerivedFrom("Part::Feature"): return "Part" if (obj.TypeId == "App::Annotation"): diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index e310e9b84..128f1a1eb 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -2551,7 +2551,7 @@ class Trimex(Modifier): sw = self.obj.ViewObject.LineWidth import DraftGeomUtils for e in self.edges: - if DraftGeomUtils(e) == "Line": + if DraftGeomUtils.geomType(e) == "Line": self.ghost.append(lineTracker(scolor=sc,swidth=sw)) else: self.ghost.append(arcTracker(scolor=sc,swidth=sw)) @@ -2739,12 +2739,39 @@ class Trimex(Modifier): self.doc.openTransaction("Trim/extend") if Draft.getType(self.obj) in ["Wire","BSpline"]: p = [] - if self.placement: invpl = self.placement.inverse() + if self.placement: + invpl = self.placement.inverse() for v in newshape.Vertexes: np = v.Point - if self.placement: np = invpl.multVec(np) + if self.placement: + np = invpl.multVec(np) p.append(np) self.obj.Points = p + elif Draft.getType(self.obj) == "Part::Line": + p = [] + if self.placement: + invpl = self.placement.inverse() + for v in newshape.Vertexes: + np = v.Point + if self.placement: + np = invpl.multVec(np) + p.append(np) + if ((p[0].x == self.obj.X1) and (p[0].y == self.obj.Y1) and (p[0].z == self.obj.Z1)): + self.obj.X2 = p[-1].x + self.obj.Y2 = p[-1].y + self.obj.Z2 = p[-1].z + elif ((p[-1].x == self.obj.X1) and (p[-1].y == self.obj.Y1) and (p[-1].z == self.obj.Z1)): + self.obj.X2 = p[0].x + self.obj.Y2 = p[0].y + self.obj.Z2 = p[0].z + elif ((p[0].x == self.obj.X2) and (p[0].y == self.obj.Y2) and (p[0].z == self.obj.Z2)): + self.obj.X1 = p[-1].x + self.obj.Y1 = p[-1].y + self.obj.Z1 = p[-1].z + else: + self.obj.X1 = p[0].x + self.obj.Y1 = p[0].y + self.obj.Z1 = p[0].z elif Draft.getType(self.obj) == "Circle": angles = self.ghost[0].getAngles() print "original",self.obj.FirstAngle," ",self.obj.LastAngle From 64ed1d97b2c7d3d7376ff40b36be5a68c096920d Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Mon, 1 Jul 2013 16:28:00 -0300 Subject: [PATCH 130/160] Draft: Added commands for snapping tools Snap tools now also appear in the Draft menu, so users can give them keyboard shortcuts. --- src/Mod/Arch/InitGui.py | 5 ++ src/Mod/Draft/DraftTools.py | 162 +++++++++++++++++++++++++++++++++++- src/Mod/Draft/InitGui.py | 5 ++ 3 files changed, 171 insertions(+), 1 deletion(-) diff --git a/src/Mod/Arch/InitGui.py b/src/Mod/Arch/InitGui.py index 94f34788a..4a8d4ee9f 100644 --- a/src/Mod/Arch/InitGui.py +++ b/src/Mod/Arch/InitGui.py @@ -91,6 +91,10 @@ class ArchWorkbench(Workbench): "Draft_SelectGroup","Draft_SelectPlane","Draft_ToggleSnap", "Draft_ShowSnapBar","Draft_ToggleGrid","Draft_UndoLine", "Draft_FinishLine","Draft_CloseLine"] + self.snapList = ['Draft_Snap_Lock','Draft_Snap_Midpoint','Draft_Snap_Perpendicular', + 'Draft_Snap_Grid','Draft_Snap_Intersection','Draft_Snap_Parallel', + 'Draft_Snap_Endpoint','Draft_Snap_Angle','Draft_Snap_Center', + 'Draft_Snap_Extension','Draft_Snap_Near','Draft_Snap_Ortho'] self.appendToolbar(str(translate("arch","Arch tools")),self.archtools) self.appendToolbar(str(translate("arch","Draft tools")),self.drafttools) @@ -100,6 +104,7 @@ class ArchWorkbench(Workbench): self.appendMenu(str(translate("arch","&Architecture")),self.archtools) self.appendMenu(str(translate("arch","&Draft")),self.drafttools+self.draftmodtools) self.appendMenu([str(translate("arch","&Draft")),str(translate("arch","Context Tools"))],self.draftcontexttools) + self.appendMenu([str(translate("arch","&Draft")),str(translate("arch","Snapping"))],self.snapList) FreeCADGui.addIconPath(":/icons") FreeCADGui.addLanguagePath(":/translations") FreeCADGui.addPreferencePage(":/ui/archprefs-base.ui","Arch") diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index 128f1a1eb..7568c5dd9 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -3725,8 +3725,154 @@ class Heal(): else: Draft.heal() FreeCAD.ActiveDocument.commitTransaction() + +#--------------------------------------------------------------------------- +# Snap tools +#--------------------------------------------------------------------------- + +class Draft_Snap_Lock(): + def GetResources(self): + return {'Pixmap' : 'Snap_Lock', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Lock", "Toggle On/Off"), + 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Lock", "Activates/deactivates all snap tools at once")} + def Activated(self): + if hasattr(FreeCADGui,"Snapper"): + if hasattr(FreeCADGui.Snapper,"masterbutton"): + print FreeCADGui.Snapper.masterbutton + FreeCADGui.Snapper.masterbutton.toggle() + +class Draft_Snap_Midpoint(): + def GetResources(self): + return {'Pixmap' : 'Snap_Midpoint', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Midpoint", "Midpoint"), + 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Midpoint", "Snaps to midpoints of edges")} + def Activated(self): + if hasattr(FreeCADGui,"Snapper"): + if hasattr(FreeCADGui.Snapper,"toolbarButtons"): + for b in FreeCADGui.Snapper.toolbarButtons: + if b.objectName() == "SnapButtonmidpoint": + b.toggle() + +class Draft_Snap_Perpendicular(): + def GetResources(self): + return {'Pixmap' : 'Snap_Perpendicular', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Perpendicular", "Perpendicular"), + 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Perpendicular", "Snaps to perpendicular points on edges")} + def Activated(self): + if hasattr(FreeCADGui,"Snapper"): + if hasattr(FreeCADGui.Snapper,"toolbarButtons"): + for b in FreeCADGui.Snapper.toolbarButtons: + if b.objectName() == "SnapButtonperpendicular": + b.toggle() + +class Draft_Snap_Grid(): + def GetResources(self): + return {'Pixmap' : 'Snap_Grid', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Grid", "Grid"), + 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Grid", "Snaps to grid points")} + def Activated(self): + if hasattr(FreeCADGui,"Snapper"): + if hasattr(FreeCADGui.Snapper,"toolbarButtons"): + for b in FreeCADGui.Snapper.toolbarButtons: + if b.objectName() == "SnapButtongrid": + b.toggle() + +class Draft_Snap_Intersection(): + def GetResources(self): + return {'Pixmap' : 'Snap_Intersection', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Intersection", "Intersection"), + 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Intersection", "Snaps to edges intersections")} + def Activated(self): + if hasattr(FreeCADGui,"Snapper"): + if hasattr(FreeCADGui.Snapper,"toolbarButtons"): + for b in FreeCADGui.Snapper.toolbarButtons: + if b.objectName() == "SnapButtonintersection": + b.toggle() + +class Draft_Snap_Parallel(): + def GetResources(self): + return {'Pixmap' : 'Snap_Parallel', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Parallel", "Parallel"), + 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Parallel", "Snaps to parallel directions of edges")} + def Activated(self): + if hasattr(FreeCADGui,"Snapper"): + if hasattr(FreeCADGui.Snapper,"toolbarButtons"): + for b in FreeCADGui.Snapper.toolbarButtons: + if b.objectName() == "SnapButtonparallel": + b.toggle() + +class Draft_Snap_Endpoint(): + def GetResources(self): + return {'Pixmap' : 'Snap_Endpoint', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Endpoint", "Endpoint"), + 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Endpoint", "Snaps to endpoints of edges")} + def Activated(self): + if hasattr(FreeCADGui,"Snapper"): + if hasattr(FreeCADGui.Snapper,"toolbarButtons"): + for b in FreeCADGui.Snapper.toolbarButtons: + if b.objectName() == "SnapButtonendpoint": + b.toggle() + +class Draft_Snap_Angle(): + def GetResources(self): + return {'Pixmap' : 'Snap_Angle', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Angle", "Angles"), + 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Angle", "Snaps to 45 and 90 degrees points on arcs and circles")} + def Activated(self): + if hasattr(FreeCADGui,"Snapper"): + if hasattr(FreeCADGui.Snapper,"toolbarButtons"): + for b in FreeCADGui.Snapper.toolbarButtons: + if b.objectName() == "SnapButtonangle": + b.toggle() + +class Draft_Snap_Center(): + def GetResources(self): + return {'Pixmap' : 'Snap_Center', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Center", "Center"), + 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Center", "Snaps to center of circles and arcs")} + def Activated(self): + if hasattr(FreeCADGui,"Snapper"): + if hasattr(FreeCADGui.Snapper,"toolbarButtons"): + for b in FreeCADGui.Snapper.toolbarButtons: + if b.objectName() == "SnapButtoncenter": + b.toggle() + +class Draft_Snap_Extension(): + def GetResources(self): + return {'Pixmap' : 'Snap_Extension', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Extension", "Extension"), + 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Extension", "Snaps to extension of edges")} + def Activated(self): + if hasattr(FreeCADGui,"Snapper"): + if hasattr(FreeCADGui.Snapper,"toolbarButtons"): + for b in FreeCADGui.Snapper.toolbarButtons: + if b.objectName() == "SnapButtonextension": + b.toggle() + +class Draft_Snap_Near(): + def GetResources(self): + return {'Pixmap' : 'Snap_Near', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Near", "Nearest"), + 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Near", "Snaps to nearest point on edges")} + def Activated(self): + if hasattr(FreeCADGui,"Snapper"): + if hasattr(FreeCADGui.Snapper,"toolbarButtons"): + for b in FreeCADGui.Snapper.toolbarButtons: + if b.objectName() == "SnapButtonnear": + b.toggle() + +class Draft_Snap_Ortho(): + def GetResources(self): + return {'Pixmap' : 'Snap_Ortho', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Ortho", "Ortho"), + 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Ortho", "Snaps to orthogonal and 45 degrees directions")} + def Activated(self): + if hasattr(FreeCADGui,"Snapper"): + if hasattr(FreeCADGui.Snapper,"toolbarButtons"): + for b in FreeCADGui.Snapper.toolbarButtons: + if b.objectName() == "SnapButtonortho": + b.toggle() - #--------------------------------------------------------------------------- # Adds the icons & commands to the FreeCAD command manager, and sets defaults #--------------------------------------------------------------------------- @@ -3779,6 +3925,20 @@ FreeCADGui.addCommand('Draft_ToggleSnap',ToggleSnap()) FreeCADGui.addCommand('Draft_ShowSnapBar',ShowSnapBar()) FreeCADGui.addCommand('Draft_ToggleGrid',ToggleGrid()) +# snap commands +FreeCADGui.addCommand('Draft_Snap_Lock',Draft_Snap_Lock()) +FreeCADGui.addCommand('Draft_Snap_Midpoint',Draft_Snap_Midpoint()) +FreeCADGui.addCommand('Draft_Snap_Perpendicular',Draft_Snap_Perpendicular()) +FreeCADGui.addCommand('Draft_Snap_Grid',Draft_Snap_Grid()) +FreeCADGui.addCommand('Draft_Snap_Intersection',Draft_Snap_Intersection()) +FreeCADGui.addCommand('Draft_Snap_Parallel',Draft_Snap_Parallel()) +FreeCADGui.addCommand('Draft_Snap_Endpoint',Draft_Snap_Endpoint()) +FreeCADGui.addCommand('Draft_Snap_Angle',Draft_Snap_Angle()) +FreeCADGui.addCommand('Draft_Snap_Center',Draft_Snap_Center()) +FreeCADGui.addCommand('Draft_Snap_Extension',Draft_Snap_Extension()) +FreeCADGui.addCommand('Draft_Snap_Near',Draft_Snap_Near()) +FreeCADGui.addCommand('Draft_Snap_Ortho',Draft_Snap_Ortho()) + # a global place to look for active draft Command FreeCAD.activeDraftCommand = None diff --git a/src/Mod/Draft/InitGui.py b/src/Mod/Draft/InitGui.py index 1b2e7732f..f1ae9612c 100644 --- a/src/Mod/Draft/InitGui.py +++ b/src/Mod/Draft/InitGui.py @@ -117,11 +117,16 @@ class DraftWorkbench (Workbench): "Draft_SelectGroup","Draft_SelectPlane","Draft_ToggleSnap", "Draft_ShowSnapBar","Draft_ToggleGrid"] self.lineList = ["Draft_UndoLine","Draft_FinishLine","Draft_CloseLine"] + self.snapList = ['Draft_Snap_Lock','Draft_Snap_Midpoint','Draft_Snap_Perpendicular', + 'Draft_Snap_Grid','Draft_Snap_Intersection','Draft_Snap_Parallel', + 'Draft_Snap_Endpoint','Draft_Snap_Angle','Draft_Snap_Center', + 'Draft_Snap_Extension','Draft_Snap_Near','Draft_Snap_Ortho'] self.appendToolbar(QT_TRANSLATE_NOOP("Workbench","Draft creation tools"),self.cmdList) self.appendToolbar(QT_TRANSLATE_NOOP("Workbench","Draft modification tools"),self.modList) self.appendMenu(str(translate("draft","&Draft")),self.cmdList+self.modList) self.appendMenu([str(translate("draft","&Draft")),str(translate("draft","Context tools"))],self.treecmdList) self.appendMenu([str(translate("draft","&Draft")),str(translate("draft","Wire tools"))],self.lineList) + self.appendMenu([str(translate("draft","&Draft")),str(translate("draft","Snapping"))],self.snapList) if hasattr(FreeCADGui,"draftToolBar"): if not hasattr(FreeCADGui.draftToolBar,"loadedPreferences"): FreeCADGui.addPreferencePage(":/ui/userprefs-base.ui","Draft") From 20c57d3a33721d05e2c62047a603856ac8ae2533 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 2 Jul 2013 10:04:33 +0200 Subject: [PATCH 131/160] Use rubberband for box selection --- src/Gui/CommandView.cpp | 2 +- src/Gui/Document.cpp | 1 - src/Gui/MouseSelection.cpp | 20 ++++++++++---------- src/Gui/MouseSelection.h | 8 ++++---- src/Gui/NavigationStyle.cpp | 3 +++ src/Gui/NavigationStyle.h | 5 +++-- src/Gui/View3DInventorViewer.h | 5 +++-- 7 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/Gui/CommandView.cpp b/src/Gui/CommandView.cpp index 4b2d5b410..3cc407ff0 100644 --- a/src/Gui/CommandView.cpp +++ b/src/Gui/CommandView.cpp @@ -1972,7 +1972,7 @@ void StdBoxSelection::activated(int iMsg) if (view) { View3DInventorViewer* viewer = view->getViewer(); if (!viewer->isSelecting()) { - viewer->startSelection(View3DInventorViewer::Rectangle); + viewer->startSelection(View3DInventorViewer::Rubberband); viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), selectionCallback); } } diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index 1629c026a..84aac6696 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -576,7 +576,6 @@ bool Document::saveAs(void) if (!fn.isEmpty()) { QFileInfo fi; fi.setFile(fn); - QString bn = fi.baseName(); const char * DocName = App::GetApplication().getDocumentName(getDocument()); diff --git a/src/Gui/MouseSelection.cpp b/src/Gui/MouseSelection.cpp index 6a3b52d8d..41f1cae41 100644 --- a/src/Gui/MouseSelection.cpp +++ b/src/Gui/MouseSelection.cpp @@ -755,7 +755,7 @@ int RectangleSelection::keyboardEvent( const SoKeyboardEvent * const e ) // ----------------------------------------------------------------------------------- -class Rubberband::Private : public Gui::GLGraphicsItem +class RubberbandSelection::Private : public Gui::GLGraphicsItem { Gui::View3DInventorViewer* viewer; int x_old, y_old, x_new, y_new; @@ -813,16 +813,16 @@ public: } }; -Rubberband::Rubberband() +RubberbandSelection::RubberbandSelection() { d = 0; } -Rubberband::~Rubberband() +RubberbandSelection::~RubberbandSelection() { } -void Rubberband::initialize() +void RubberbandSelection::initialize() { d = new Private(_pcView3D); _pcView3D->addGraphicsItem(d); @@ -830,7 +830,7 @@ void Rubberband::initialize() _pcView3D->scheduleRedraw(); } -void Rubberband::terminate() +void RubberbandSelection::terminate() { _pcView3D->removeGraphicsItem(d); delete d; d = 0; @@ -838,11 +838,11 @@ void Rubberband::terminate() _pcView3D->scheduleRedraw(); } -void Rubberband::draw () +void RubberbandSelection::draw () { } -int Rubberband::mouseButtonEvent(const SoMouseButtonEvent * const e, const QPoint& pos) +int RubberbandSelection::mouseButtonEvent(const SoMouseButtonEvent * const e, const QPoint& pos) { const int button = e->getButton(); const SbBool press = e->getState() == SoButtonEvent::DOWN ? TRUE : FALSE; @@ -881,7 +881,7 @@ int Rubberband::mouseButtonEvent(const SoMouseButtonEvent * const e, const QPoin return ret; } -int Rubberband::locationEvent(const SoLocation2Event * const e, const QPoint& pos) +int RubberbandSelection::locationEvent(const SoLocation2Event * const e, const QPoint& pos) { m_iXnew = pos.x(); m_iYnew = pos.y(); @@ -890,7 +890,7 @@ int Rubberband::locationEvent(const SoLocation2Event * const e, const QPoint& po return Continue; } -int Rubberband::keyboardEvent(const SoKeyboardEvent * const e) +int RubberbandSelection::keyboardEvent(const SoKeyboardEvent * const e) { return Continue; } @@ -907,7 +907,7 @@ BoxZoomSelection::~BoxZoomSelection() void BoxZoomSelection::terminate() { - Rubberband::terminate(); + RubberbandSelection::terminate(); int xmin = std::min(m_iXold, m_iXnew); int xmax = std::max(m_iXold, m_iXnew); diff --git a/src/Gui/MouseSelection.h b/src/Gui/MouseSelection.h index 0ebb4601f..70aa8548d 100644 --- a/src/Gui/MouseSelection.h +++ b/src/Gui/MouseSelection.h @@ -231,11 +231,11 @@ private: * Draws a rectangle for selection * \author Werner Mayer */ -class GuiExport Rubberband : public BaseMouseSelection +class GuiExport RubberbandSelection : public BaseMouseSelection { public: - Rubberband(); - virtual ~Rubberband(); + RubberbandSelection(); + virtual ~RubberbandSelection(); /// do nothing virtual void initialize(); @@ -262,7 +262,7 @@ private: * Draws a rectangle for box zooming * \author Werner Mayer */ -class GuiExport BoxZoomSelection : public Rubberband +class GuiExport BoxZoomSelection : public RubberbandSelection { public: BoxZoomSelection(); diff --git a/src/Gui/NavigationStyle.cpp b/src/Gui/NavigationStyle.cpp index b7380aaad..4e802362f 100644 --- a/src/Gui/NavigationStyle.cpp +++ b/src/Gui/NavigationStyle.cpp @@ -1068,6 +1068,9 @@ void NavigationStyle::startSelection(NavigationStyle::SelectionMode mode) case Rectangle: mouseSelection = new RectangleSelection(); break; + case Rubberband: + mouseSelection = new RubberbandSelection(); + break; case BoxZoom: mouseSelection = new BoxZoomSelection(); break; diff --git a/src/Gui/NavigationStyle.h b/src/Gui/NavigationStyle.h index 2e4900173..b801857ea 100644 --- a/src/Gui/NavigationStyle.h +++ b/src/Gui/NavigationStyle.h @@ -87,8 +87,9 @@ public: enum SelectionMode { Lasso = 0, /**< Select objects using a lasso. */ Rectangle = 1, /**< Select objects using a rectangle. */ - BoxZoom = 2, /**< Perform a box zoom. */ - Clip = 3, /**< Clip objects using a lasso. */ + Rubberband = 2, /**< Select objects using a rubberband. */ + BoxZoom = 3, /**< Perform a box zoom. */ + Clip = 4, /**< Clip objects using a lasso. */ }; enum OrbitStyle { diff --git a/src/Gui/View3DInventorViewer.h b/src/Gui/View3DInventorViewer.h index c8e2384ac..44c474761 100644 --- a/src/Gui/View3DInventorViewer.h +++ b/src/Gui/View3DInventorViewer.h @@ -78,8 +78,9 @@ public: enum SelectionMode { Lasso = 0, /**< Select objects using a lasso. */ Rectangle = 1, /**< Select objects using a rectangle. */ - BoxZoom = 2, /**< Perform a box zoom. */ - Clip = 3, /**< Clip objects using a lasso. */ + Rubberband = 2, /**< Select objects using a rubberband. */ + BoxZoom = 3, /**< Perform a box zoom. */ + Clip = 4, /**< Clip objects using a lasso. */ }; /** @name Modus handling of the viewer * Here the you can switch on/off several features From 8c6f77bb2b2b4ef3202d4fa2f3469539c17a2462 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 2 Jul 2013 14:52:32 +0200 Subject: [PATCH 132/160] Fix weird behaviour for 64-bit version on Windows --- src/App/Document.cpp | 4 ++-- src/Mod/Part/Init.py | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 8454df3ea..ee92e46da 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -803,8 +803,8 @@ Document::readObjects(Base::XMLReader& reader) reader.addName(name.c_str(), obj->getNameInDocument()); } } - catch (Base::Exception&) { - Base::Console().Message("Cannot create object '%s'\n", name.c_str()); + catch (const Base::Exception& e) { + Base::Console().Error("Cannot create object '%s': (%s)\n", name.c_str(), e.what()); } } reader.readEndElement("Objects"); diff --git a/src/Mod/Part/Init.py b/src/Mod/Part/Init.py index b81a441b4..6423a47ae 100644 --- a/src/Mod/Part/Init.py +++ b/src/Mod/Part/Init.py @@ -51,3 +51,11 @@ FreeCAD.addImportType("IGES format (*.iges *.igs)","Part") FreeCAD.addExportType("IGES format (*.iges *.igs)","Part") FreeCAD.addImportType("STEP with colors (*.step *.stp)","ImportGui") FreeCAD.addExportType("STEP with colors (*.step *.stp)","ImportGui") + +# weird behaviour as 64-bit application on Windows: +# some modules like Sketcher doesn't load if Part is not loaded before with this error: +# DLL load failed: The specified procedure could not be found +import platform +if platform.architecture()[0] == '64bit' and platform.system() == 'Windows': + import Part + From 902ce7871f4315a7b8169fcbe8f7d93eccbf8603 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 2 Jul 2013 18:49:53 +0200 Subject: [PATCH 133/160] 0000803: Feature request - box selection for faces in set color mode --- src/Mod/Part/Gui/TaskFaceColors.cpp | 84 +++++++++++++++++++++++++++++ src/Mod/Part/Gui/TaskFaceColors.h | 1 + src/Mod/Part/Gui/TaskFaceColors.ui | 11 +++- 3 files changed, 94 insertions(+), 2 deletions(-) diff --git a/src/Mod/Part/Gui/TaskFaceColors.cpp b/src/Mod/Part/Gui/TaskFaceColors.cpp index ba593b5da..4d2a3b192 100644 --- a/src/Mod/Part/Gui/TaskFaceColors.cpp +++ b/src/Mod/Part/Gui/TaskFaceColors.cpp @@ -24,10 +24,18 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include +# include +# include +# include +# include # include +# include # include # include # include +# include +# include #endif #include @@ -40,7 +48,11 @@ #include #include #include +#include #include +#include +#include +#include #include #include @@ -106,6 +118,66 @@ public: { delete ui; } + void addFacesToSelection(const Gui::ViewVolumeProjection& proj, const Base::Polygon2D& polygon, const TopoDS_Shape& shape) + { + try { + TopTools_IndexedMapOfShape M; + + TopExp_Explorer xp_face(shape,TopAbs_FACE); + while (xp_face.More()) { + M.Add(xp_face.Current()); + xp_face.Next(); + } + + App::Document* appdoc = doc->getDocument(); + for (Standard_Integer k = 1; k <= M.Extent(); k++) { + const TopoDS_Shape& face = M(k); + + GProp_GProps props; + BRepGProp::SurfaceProperties(face, props); + gp_Pnt c = props.CentreOfMass(); + Base::Vector3d pt2d; + pt2d = proj(Base::Vector3d(c.X(), c.Y(), c.Z())); + if (polygon.Contains(Base::Vector2D(pt2d.x, pt2d.y))) { + std::stringstream str; + str << "Face" << k; + Gui::Selection().addSelection(appdoc->getName(), obj->getNameInDocument(), str.str().c_str()); + } + } + } + catch (...) { + } + } + static void selectionCallback(void * ud, SoEventCallback * cb) + { + Gui::View3DInventorViewer* view = reinterpret_cast(cb->getUserData()); + view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), selectionCallback, ud); + + std::vector picked = view->getGLPolygon(); + SoCamera* cam = view->getCamera(); + SbViewVolume vv = cam->getViewVolume(); + Gui::ViewVolumeProjection proj(vv); + Base::Polygon2D polygon; + if (picked.size() == 2) { + SbVec2f pt1 = picked[0]; + SbVec2f pt2 = picked[1]; + polygon.Add(Base::Vector2D(pt1[0], pt1[1])); + polygon.Add(Base::Vector2D(pt1[0], pt2[1])); + polygon.Add(Base::Vector2D(pt2[0], pt2[1])); + polygon.Add(Base::Vector2D(pt2[0], pt1[1])); + } + else { + for (std::vector::const_iterator it = picked.begin(); it != picked.end(); ++it) + polygon.Add(Base::Vector2D((*it)[0],(*it)[1])); + } + + FaceColors* self = reinterpret_cast(ud); + if (self->d->obj && self->d->obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + cb->setHandled(); + const TopoDS_Shape& shape = static_cast(self->d->obj)->Shape.getValue(); + self->d->addFacesToSelection(proj, polygon, shape); + } + } }; /* TRANSLATOR PartGui::TaskFaceColors */ @@ -146,6 +218,18 @@ void FaceColors::slotDeleteObject(const Gui::ViewProvider& obj) Gui::Control().closeDialog(); } +void FaceColors::on_boxSelection_clicked() +{ + Gui::View3DInventor* view = qobject_cast(Gui::getMainWindow()->activeWindow()); + if (view) { + Gui::View3DInventorViewer* viewer = view->getViewer(); + if (!viewer->isSelecting()) { + viewer->startSelection(Gui::View3DInventorViewer::Rubberband); + viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), Private::selectionCallback, this); + } + } +} + 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 3ba96c9ce..be4e0e0ea 100644 --- a/src/Mod/Part/Gui/TaskFaceColors.h +++ b/src/Mod/Part/Gui/TaskFaceColors.h @@ -50,6 +50,7 @@ public: private Q_SLOTS: void on_colorButton_changed(); void on_defaultButton_clicked(); + void on_boxSelection_clicked(); protected: void onSelectionChanged(const Gui::SelectionChanges& msg); diff --git a/src/Mod/Part/Gui/TaskFaceColors.ui b/src/Mod/Part/Gui/TaskFaceColors.ui index 06da3c717..4ce48b820 100644 --- a/src/Mod/Part/Gui/TaskFaceColors.ui +++ b/src/Mod/Part/Gui/TaskFaceColors.ui @@ -14,14 +14,14 @@ Set color per face - + Click on the faces in the 3d view to select them. - + Group box @@ -61,6 +61,13 @@ + + + Box selection + + + + Qt::Vertical From 14ced6b20277bc099dacc08dec5fc13f60720760 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 3 Jul 2013 07:56:36 +0200 Subject: [PATCH 134/160] 0001133: crash at padding a sketch with 42 holes --- src/Mod/PartDesign/App/FeatureFace.cpp | 18 +++++++++------- src/Mod/PartDesign/App/FeatureFace.h | 3 +++ src/Mod/PartDesign/App/FeatureSketchBased.cpp | 21 +++++++++++-------- src/Mod/PartDesign/App/FeatureSketchBased.h | 2 ++ 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureFace.cpp b/src/Mod/PartDesign/App/FeatureFace.cpp index 55030f6c9..fb4b81dcf 100644 --- a/src/Mod/PartDesign/App/FeatureFace.cpp +++ b/src/Mod/PartDesign/App/FeatureFace.cpp @@ -105,23 +105,25 @@ App::DocumentObjectExecReturn *Face::execute(void) return App::DocumentObject::StdReturn; } -namespace PartDesign { - // sort bounding boxes according to diagonal length -struct Wire_Compare { +class Face::Wire_Compare { +public: bool operator() (const TopoDS_Wire& w1, const TopoDS_Wire& w2) { Bnd_Box box1, box2; - BRepBndLib::Add(w1, box1); - box1.SetGap(0.0); + if (!w1.IsNull()) { + BRepBndLib::Add(w1, box1); + box1.SetGap(0.0); + } - BRepBndLib::Add(w2, box2); - box2.SetGap(0.0); + if (!w2.IsNull()) { + BRepBndLib::Add(w2, box2); + box2.SetGap(0.0); + } return box1.SquareExtent() < box2.SquareExtent(); } }; -} TopoDS_Shape Face::makeFace(std::list& wires) const { diff --git a/src/Mod/PartDesign/App/FeatureFace.h b/src/Mod/PartDesign/App/FeatureFace.h index b30ec92ef..2cb69bd91 100644 --- a/src/Mod/PartDesign/App/FeatureFace.h +++ b/src/Mod/PartDesign/App/FeatureFace.h @@ -48,6 +48,9 @@ public: protected: TopoDS_Shape makeFace(const std::vector&) const; TopoDS_Shape makeFace(std::list&) const; // for internal use only + +private: + class Wire_Compare; }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index c5c856761..0e2027160 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -69,18 +69,21 @@ using namespace PartDesign; -namespace PartDesign { - // sort bounding boxes according to diagonal length -struct Wire_Compare { +class SketchBased::Wire_Compare { +public: bool operator() (const TopoDS_Wire& w1, const TopoDS_Wire& w2) { Bnd_Box box1, box2; - BRepBndLib::Add(w1, box1); - box1.SetGap(0.0); + if (!w1.IsNull()) { + BRepBndLib::Add(w1, box1); + box1.SetGap(0.0); + } - BRepBndLib::Add(w2, box2); - box2.SetGap(0.0); + if (!w2.IsNull()) { + BRepBndLib::Add(w2, box2); + box2.SetGap(0.0); + } return box1.SquareExtent() < box2.SquareExtent(); } @@ -799,6 +802,7 @@ void SketchBased::remapSupportShape(const TopoDS_Shape& newShape) } } +namespace PartDesign { struct gp_Pnt_Less : public std::binary_function { @@ -814,6 +818,7 @@ struct gp_Pnt_Less : public std::binary_function Date: Wed, 3 Jul 2013 15:04:47 +0200 Subject: [PATCH 135/160] Call releaseMouseModel() in stopSelection() of navigation style --- src/Gui/MouseSelection.cpp | 12 +++++++----- src/Gui/NavigationStyle.cpp | 7 +++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/Gui/MouseSelection.cpp b/src/Gui/MouseSelection.cpp index 41f1cae41..2aec13351 100644 --- a/src/Gui/MouseSelection.cpp +++ b/src/Gui/MouseSelection.cpp @@ -53,7 +53,7 @@ AbstractMouseSelection::AbstractMouseSelection() : _pcView3D(0) void AbstractMouseSelection::grabMouseModel( Gui::View3DInventorViewer* viewer ) { - _pcView3D=viewer; + _pcView3D = viewer; m_cPrevCursor = _pcView3D->getWidget()->cursor(); // do initialization of your mousemodel @@ -62,11 +62,13 @@ void AbstractMouseSelection::grabMouseModel( Gui::View3DInventorViewer* viewer ) void AbstractMouseSelection::releaseMouseModel() { - // do termination of your mousemodel - terminate(); + if (_pcView3D) { + // do termination of your mousemodel + terminate(); - _pcView3D->getWidget()->setCursor(m_cPrevCursor); - _pcView3D = 0; + _pcView3D->getWidget()->setCursor(m_cPrevCursor); + _pcView3D = 0; + } } void AbstractMouseSelection::redraw() diff --git a/src/Gui/NavigationStyle.cpp b/src/Gui/NavigationStyle.cpp index 4e802362f..48fb8c01e 100644 --- a/src/Gui/NavigationStyle.cpp +++ b/src/Gui/NavigationStyle.cpp @@ -1088,8 +1088,11 @@ void NavigationStyle::startSelection(NavigationStyle::SelectionMode mode) void NavigationStyle::stopSelection() { pcPolygon.clear(); - delete mouseSelection; - mouseSelection = 0; + if (mouseSelection) { + mouseSelection->releaseMouseModel(); + delete mouseSelection; + mouseSelection = 0; + } } SbBool NavigationStyle::isSelecting() const From a367b2e1e30f31cc3f73f74ba32a9e7a9b078c79 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Wed, 3 Jul 2013 13:10:49 -0300 Subject: [PATCH 136/160] Arch: Allow windows to have different colors + When editing window components, a new "type" setting is available + In Arch preferences there is a new "Window Glass Color" preference + When a window component is set to "Glass panel" type it takes the glass color --- src/Mod/Arch/ArchCommands.py | 10 +- src/Mod/Arch/ArchWindow.py | 62 +++- src/Mod/Arch/Arch_rc.py | 315 ++++++++++---------- src/Mod/Arch/Resources/ui/archprefs-base.ui | 53 +++- 4 files changed, 266 insertions(+), 174 deletions(-) diff --git a/src/Mod/Arch/ArchCommands.py b/src/Mod/Arch/ArchCommands.py index 52cf96397..96da0d2bd 100644 --- a/src/Mod/Arch/ArchCommands.py +++ b/src/Mod/Arch/ArchCommands.py @@ -45,14 +45,16 @@ def getStringList(objects): def getDefaultColor(objectType): '''getDefaultColor(string): returns a color value for the given object - type (Wall, Structure, Window)''' + type (Wall, Structure, Window, WindowGlass)''' p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") if objectType == "Wall": - c = p.GetUnsigned("WallColor") + c = p.GetUnsigned("WallColor",4294967295) elif objectType == "Structure": - c = p.GetUnsigned("StructureColor") + c = p.GetUnsigned("StructureColor",2847259391) + elif objectType == "WindowGlass": + c = p.GetUnsigned("WindowGlassColor",1772731135) else: - c = p.GetUnsigned("WindowsColor") + c = p.GetUnsigned("WindowsColor",810781695) r = float((c>>24)&0xFF)/255.0 g = float((c>>16)&0xFF)/255.0 b = float((c>>8)&0xFF)/255.0 diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py index 9768caf00..5d6436020 100644 --- a/src/Mod/Arch/ArchWindow.py +++ b/src/Mod/Arch/ArchWindow.py @@ -30,6 +30,8 @@ __title__="FreeCAD Wall" __author__ = "Yorik van Havre" __url__ = "http://free-cad.sourceforge.net" +WindowPartTypes = ["Frame","Solid panel","Glass panel"] + def makeWindow(baseobj=None,width=None,name=str(translate("Arch","Window"))): '''makeWindow(obj,[name]): creates a window based on the given object''' @@ -64,7 +66,7 @@ def makeDefaultWindowPart(obj): if ws: ws += "," ws += "Wire" + str(i) i += 1 - part = ["Default","Panel",ws,"1","0"] + part = ["Default","Frame",ws,"1","0"] return part class _CommandWindow: @@ -183,6 +185,15 @@ class _ViewProviderWindow(ArchComponent.ViewProviderComponent): def getIcon(self): import Arch_rc return ":/icons/Arch_Window_Tree.svg" + + def updateData(self,obj,prop): + if (prop in ["WindowParts","Shape"]) and obj.ViewObject: + self.colorize(obj) + + def onChanged(self,vobj,prop): + if (prop == "DiffuseColor") and vobj.Object: + if len(vobj.DiffuseColor) < 2: + self.colorize(vobj.Object) def setEdit(self,vobj,mode): taskd = _ArchWindowTaskPanel() @@ -203,6 +214,23 @@ class _ViewProviderWindow(ArchComponent.ViewProviderComponent): self.Object.Base.ViewObject.hide() FreeCADGui.Control.closeDialog() return + + def colorize(self,obj): + "setting different part colors" + print "Colorizing ", obj.Shape.Solids + colors = [] + base = obj.ViewObject.ShapeColor + for i in range(len(obj.Shape.Solids)): + ccol = base + typeidx = (i*5)+1 + if typeidx < len(obj.WindowParts): + typ = obj.WindowParts[typeidx] + if typ == WindowPartTypes[2]: # transparent parts + ccol = ArchCommands.getDefaultColor("WindowGlass") + for f in obj.Shape.Solids[i].Faces: + colors.append(ccol) + print "colors: ",colors + obj.ViewObject.DiffuseColor = colors class _ArchWindowTaskPanel: '''The TaskPanel for Arch Windows''' @@ -262,10 +290,10 @@ class _ArchWindowTaskPanel: self.new4 = QtGui.QLabel(self.form) self.new5 = QtGui.QLabel(self.form) self.field1 = QtGui.QLineEdit(self.form) - self.field2 = QtGui.QLineEdit(self.form) + self.field2 = QtGui.QComboBox(self.form) self.field3 = QtGui.QLineEdit(self.form) self.field4 = QtGui.QLineEdit(self.form) - self.field5 = QtGui.QLineEdit(self.form) + self.field5 = QtGui.QLineEdit(self.form) self.createButton = QtGui.QPushButton(self.form) self.createButton.setObjectName("createButton") self.createButton.setIcon(QtGui.QIcon(":/icons/Arch_Add.svg")) @@ -289,6 +317,8 @@ class _ArchWindowTaskPanel: self.new5.setVisible(False) self.field1.setVisible(False) self.field2.setVisible(False) + for t in WindowPartTypes: + self.field2.addItem("") self.field3.setVisible(False) self.field3.setReadOnly(True) self.field4.setVisible(False) @@ -370,18 +400,17 @@ class _ArchWindowTaskPanel: def addElement(self): 'opens the component creation dialog' self.field1.setText('') - self.field2.setText('') self.field3.setText('') self.field4.setText('') self.field5.setText('') self.newtitle.setVisible(True) self.new1.setVisible(True) - #self.new2.setVisible(True) + self.new2.setVisible(True) self.new3.setVisible(True) self.new4.setVisible(True) self.new5.setVisible(True) self.field1.setVisible(True) - #self.field2.setVisible(True) + self.field2.setVisible(True) self.field3.setVisible(True) self.field4.setVisible(True) self.field5.setVisible(True) @@ -414,7 +443,14 @@ class _ArchWindowTaskPanel: for i in range(5): f = getattr(self,"field"+str(i+1)) t = self.obj.WindowParts[ind+i] - f.setText(t) + if i == 1: + # special behaviour for types + if t in WindowPartTypes: + f.setCurrentIndex(WindowPartTypes.index(t)) + else: + f.setCurrentIndex(0) + else: + f.setText(t) def create(self): 'adds a new component' @@ -422,7 +458,15 @@ class _ArchWindowTaskPanel: ok = True ar = [] for i in range(5): - t = str(getattr(self,"field"+str(i+1)).text()) + if i == 1: + n = getattr(self,"field"+str(i+1)).currentIndex() + if n in range(len(WindowPartTypes)): + t = WindowPartTypes[n] + else: + # if type was not specified or is invalid, we set a default + t = WindowPartTypes[0] + else: + t = str(getattr(self,"field"+str(i+1)).text()) if t == "": if not(i in [1,5]): ok = False @@ -483,5 +527,7 @@ class _ArchWindowTaskPanel: self.new3.setText(QtGui.QApplication.translate("Arch", "Wires", None, QtGui.QApplication.UnicodeUTF8)) self.new4.setText(QtGui.QApplication.translate("Arch", "Thickness", None, QtGui.QApplication.UnicodeUTF8)) self.new5.setText(QtGui.QApplication.translate("Arch", "Z offset", None, QtGui.QApplication.UnicodeUTF8)) + for i in range(len(WindowPartTypes)): + self.field2.setItemText(i, QtGui.QApplication.translate("Arch", WindowPartTypes[i], None, QtGui.QApplication.UnicodeUTF8)) FreeCADGui.addCommand('Arch_Window',_CommandWindow()) diff --git a/src/Mod/Arch/Arch_rc.py b/src/Mod/Arch/Arch_rc.py index 2bc77e48c..870ae8d4f 100644 --- a/src/Mod/Arch/Arch_rc.py +++ b/src/Mod/Arch/Arch_rc.py @@ -2,8 +2,8 @@ # Resource object code # -# Created: Wed Apr 17 16:59:58 2013 -# by: The Resource Compiler for PyQt (Qt v4.8.2) +# Created: Wed Jul 3 13:10:05 2013 +# by: The Resource Compiler for PyQt (Qt v4.8.4) # # WARNING! All changes made in this file will be lost! @@ -27568,130 +27568,133 @@ qt_resource_data = "\ \x6c\x6c\x61\x64\x61\x20\x73\x75\x70\x70\x6f\x72\x74\x20\x77\x69\ \x6c\x6c\x20\x62\x65\x20\x64\x69\x73\x61\x62\x6c\x65\x64\x2e\x0a\ \x07\x00\x00\x00\x04\x61\x72\x63\x68\x01\ -\x00\x00\x07\x98\ +\x00\x00\x07\xcc\ \x00\ -\x00\x38\x4e\x78\x9c\xed\x5b\x6d\x73\xd3\x38\x10\xfe\xce\xaf\xd0\ -\xe4\xd3\xdd\x0c\x90\x36\xf4\x85\x76\xdc\x30\x40\x29\xf4\x06\x8e\ -\x72\xe9\xc1\x47\x46\xb1\x37\xb1\xa8\x2c\xf9\x24\xb9\x49\xf8\xf5\ -\xb7\x92\xed\x38\x8e\x1d\xb7\x69\x5e\x3a\xd3\x09\x03\x83\xad\x55\ -\x76\x57\xeb\xdd\x67\x77\x65\xd9\x7b\x33\x8e\x38\xb9\x05\xa5\x99\ -\x14\x67\xad\xfd\x97\x7b\x2d\x02\xc2\x97\x01\x13\xc3\xb3\xd6\xbf\ -\xd7\x17\x2f\x5e\xb7\xde\x74\x9f\x79\x09\x2b\x26\x1d\xe0\xa4\xee\ -\x33\xe2\xf9\x9c\x6a\xdd\xfd\x98\xb0\xd3\xd3\x73\x46\xb9\x1c\xe2\ -\xff\x7c\xd8\x03\x63\xf0\xc7\xfa\xad\xf2\x43\xaf\x9d\xce\xc1\xc9\ -\x23\x16\x0c\xc1\x10\x77\x7f\xd6\xfa\xf6\xc3\xdd\xb6\x88\xa0\x11\ -\x9c\xb5\x9a\x78\x58\x51\xc4\x8b\x95\x8c\x41\x99\x49\xf6\x83\x21\ -\xc8\x08\x8c\x9a\x38\x22\xf1\x14\xf8\xc6\x5d\x11\x6f\xdc\xdd\xf3\ -\xda\xe3\xec\x66\x62\x6f\x26\xd9\x0d\x6a\x60\xc2\xee\xe1\xf1\xa1\ -\xd7\x4e\x2f\xd3\xe1\x10\xd8\x30\x34\xdd\xa3\xce\x89\xd7\xce\xae\ -\x1d\xcf\x76\xce\xd4\x6b\xe7\xc2\xeb\x34\x19\x31\x11\xc8\xd1\x35\ -\x33\x1c\x32\x65\xb4\x51\xa8\x7b\xf7\x23\x08\x50\x94\x13\x9d\xad\ -\xc5\x6b\x67\x84\x2a\x4b\x4e\x27\x32\x29\x6c\xf3\xfd\x9d\x1c\x7f\ -\x76\x43\x19\xc7\x39\x91\x3a\xa6\x3e\x32\x6a\x65\x0b\x10\x49\xd4\ -\x07\xd5\x3d\xf2\xda\xd9\x55\xaa\xfe\xac\x84\x0a\x8b\x88\xaa\x21\ -\x13\x73\x1c\x4e\x1a\x39\x30\x03\x51\x61\xc9\xd9\x67\xf9\x51\xc9\ -\x24\x46\x9d\xf3\xa7\x39\xcc\xef\xd3\xe9\x15\xe1\xa6\x30\x56\x8d\ -\xbd\xec\x33\x27\xbd\x1a\xa3\x55\x75\x6a\x34\x5d\x26\x0c\xbd\xd6\ -\x30\x9f\xf2\x74\xf4\x67\xa7\x90\x5b\x2c\xa8\x86\xd1\xa7\x0a\xa3\ -\x50\x2a\xf6\x5b\x0a\x53\xc3\x6a\x9e\x59\xd5\x44\x9f\x69\x1f\x78\ -\xce\x89\xdb\x9b\xd2\xcf\x6b\x6c\x04\x63\x53\x9a\x30\xb5\xd3\x39\ -\x0c\x68\xc2\x91\xb5\xe4\x52\x91\x01\xfe\x1b\x51\xce\xe7\x2d\x55\ -\x6f\xae\x74\x30\xd5\x6d\x46\xf9\x76\x59\xfb\xca\x62\xac\xc3\x81\ -\xaa\xd8\xa1\xe7\x86\x1b\x97\x81\x73\x01\xa7\x1a\xc4\x8d\xb9\xd5\ -\x00\xba\x5a\xf7\x9b\x39\x3d\xfd\x34\xe5\xe7\xb5\xdd\xe0\x5d\x0b\ -\xa8\xc6\x03\xfb\x0d\x9f\x98\xc0\x27\xa5\x4d\x80\xe1\x76\xd6\xda\ -\x9b\x37\x1d\xce\x28\x8d\xe4\x68\x70\xb0\x57\x02\x83\x29\x35\x03\ -\x82\xce\x5e\x09\x13\x0a\xb5\xe6\x19\x2e\xb0\x74\x6a\xb8\x25\x2c\ -\x5d\x76\x1b\x07\x8b\x57\x0a\x06\xef\xed\xb3\x7e\x97\x18\x83\x66\ -\xcc\x83\xcc\xd2\x62\xa4\x39\x3f\xe8\xa7\xb4\x46\x8f\x92\x92\x5f\ -\xb3\xb8\xde\xa9\xae\x43\xa6\x09\xfe\x35\x21\x90\xa0\xe2\x60\x02\ -\x46\xe4\x07\x3a\x19\x91\xfd\x5f\x08\x8a\xf7\xf7\xb5\x8a\x12\x8e\ -\xe7\x9c\x0a\x6e\x6c\xce\xfe\x0a\x82\x6e\xe7\xf0\xd0\x82\x70\x30\ -\x47\x1a\x2a\x00\xd1\xdd\x3f\xc1\x47\x93\x5e\x96\xc9\x7d\x9e\x40\ -\x77\xff\x18\xa9\xee\xaa\xfc\xd8\x2a\xa2\xee\xa7\xb5\x35\xf3\x07\ -\x61\xd3\xcd\x42\x0f\xf3\x33\x8b\x58\x33\xb9\xa7\x85\xc2\x1e\x6a\ -\x24\x2b\xee\x8a\x9a\xf0\x6e\x69\x5f\x64\xd0\xce\xf2\xec\xba\xa2\ -\xdf\x6b\xa7\x48\x38\x85\xc9\x12\x79\x55\xd0\x5c\x09\x32\xd7\x06\ -\x98\x48\x48\x7c\x93\x28\x78\x3c\xd4\xbc\x03\xfe\x77\xb8\xb9\x4d\ -\xdc\xbc\x2b\x17\xaf\x86\x9c\xbd\xdc\xdb\xb6\x0b\x9f\xfb\x87\x7b\ -\x0d\xf0\x79\x74\xd2\x04\x9f\xaf\x8f\x1e\x09\x3e\xa7\xb6\xda\x61\ -\xe8\xe2\xc2\xf3\x68\xb5\xc2\xf3\x70\x7d\x85\xa7\xeb\x7d\x1e\x11\ -\x44\x0f\x76\x20\xba\xd8\xd6\xdb\x06\xd1\x57\x8d\x0f\x63\x19\xe8\ -\x3a\x3c\x69\x40\xae\x57\x9d\x26\xe4\x3a\x78\x2c\xe4\xfa\xe1\x62\ -\x61\x07\x5b\x8b\x61\x6b\x7f\xef\xfe\xb8\x55\x38\x5f\x08\xfe\xcd\ -\xec\xde\xc2\xd4\xf3\x2c\xa1\x2f\xc7\x3f\x5f\x3f\x3c\x77\x5f\x0e\ -\x30\x6d\xa7\xe9\xdb\xb1\x83\xe0\x39\x19\x85\x20\x48\x87\x68\x16\ -\x31\x4e\xb3\xde\x9a\x50\x4c\xde\x7d\xc0\x9f\x20\xf8\x09\x81\x39\ -\xdc\xce\xc4\x8c\xcf\x14\x49\x44\x00\x8a\x4f\x2c\x4d\xdf\x80\x41\ -\x3e\x1a\x71\x11\x7b\xa5\x3e\x90\x5f\x92\x09\x08\x08\xa2\x83\x24\ -\x52\xc0\x73\x42\x45\xe0\x0a\x05\x33\x92\x19\xe7\x6c\xaa\x2f\x23\ -\xb0\x53\x1e\x5e\x1a\x2c\xc6\xed\xbf\x50\x8b\x4c\x5a\x9f\x6a\x98\ -\x51\xd3\x2e\x35\x96\x5a\xb3\x3e\x5f\x41\xf2\x12\x41\x62\x0d\x62\ -\x3b\xa4\x5e\xa6\xc2\x93\x8c\x94\x32\xb1\xc4\x6b\x66\xde\x03\xf6\ -\xd3\x8a\x32\xf5\x7e\x3b\x6a\x97\x17\xef\x09\x8b\x62\xa9\xcc\xba\ -\xb7\xd1\xd6\xb7\x89\x76\xb2\x11\x4c\xb8\xa3\xc4\x69\xc2\x04\xc7\ -\x3c\x85\x05\x8c\xda\x80\xe9\x18\x17\x85\x95\x7d\x3f\x19\x92\x08\ -\xb4\xa6\x43\x17\x39\x8c\x43\x66\x5b\x1b\xf9\xd6\xd2\x03\x1c\x5a\ -\xa1\xb4\x5f\x1c\xbf\xbd\x50\x8e\xe6\x14\xd8\x4a\xb0\xb2\x81\x7f\ -\x6e\xa5\x3e\xc9\x20\x5d\xdd\x73\x0f\x37\xe1\xb9\xeb\xcd\x65\x53\ -\xb7\x4c\xd3\x0c\xe5\x23\x3a\xd1\x36\x31\xa5\x9e\x8b\xa9\x69\xc4\ -\x4c\xe8\x32\x12\xe6\x28\x50\x82\x72\x12\x4f\x4c\x28\x31\x2d\x50\ -\xa5\x41\x3d\x27\x70\x8b\x39\x82\x0d\xc8\xe5\xc0\xff\x1a\x83\xe8\ -\x85\x80\x8c\xac\x18\xa1\xd1\x14\x1c\x82\x4d\x78\xfc\x85\x54\x3e\ -\x94\x35\xd9\x8a\xc7\x0f\xac\x5c\x5c\xe9\x95\x93\x7c\x95\x09\xde\ -\x79\x7f\x8d\xf7\xbf\xda\x08\x6e\xaf\xb0\x0f\xf3\x5e\x01\x35\xe8\ -\xe9\x2e\x59\x6a\xd7\x9e\x02\xf5\xc3\xf4\x75\x52\xba\xf1\x42\xcc\ -\x24\xde\x48\x85\xe5\x12\x36\x96\x86\x18\x55\x02\x3b\x4e\x0c\xb1\ -\x89\x93\xb5\x1d\x9c\xf6\xdd\xca\xd1\x6d\x9d\x1a\x4f\xb3\xa6\x5a\ -\xdd\x61\x0f\x36\xe2\xb0\xcd\x3d\xef\x62\x8f\xb9\x74\x00\x4c\x06\ -\x89\x12\xcc\x6d\x0d\xfe\xe1\x53\x41\x22\x7a\x03\x0e\x8d\x23\x19\ -\x00\x27\x21\xd0\xdb\xc9\x9f\xdb\xc9\xf5\x4e\x1f\xf4\xa1\x8b\x5c\ -\xa3\x9d\x1b\xd5\x37\xb1\xfb\x1b\xf1\xa3\xa3\xf5\x26\x7e\xfc\xb5\ -\xb0\xaf\xcf\xa7\x9d\xe8\x34\xe1\x53\x4d\x74\xd2\x37\x8a\xfa\x76\ -\x5b\x4c\xe3\x54\xf4\x37\x35\x62\xd8\x17\xda\x16\x91\xe8\x90\xc6\ -\x45\xbd\x80\xc8\x12\x4c\x48\x48\x6f\x21\xeb\x76\xa7\x8c\x73\x26\ -\x9b\x29\x00\x7a\x80\x59\x1f\x41\x6d\x2a\x6f\x5b\x05\x6f\x2e\xf8\ -\xeb\x54\xee\x2e\x0a\xea\xa2\x60\x89\xb3\x0f\x4b\x44\xc1\xf1\x9a\ -\xa3\x20\xcd\xfa\xf6\xd7\x45\x24\x58\x81\x6c\x3c\x5b\xfa\xda\x2a\ -\xf9\xf2\x9c\xa4\x47\x5f\x36\xe1\xcd\x57\x4e\xe4\x54\x0f\x14\xbb\ -\x06\x71\xcb\xf9\x75\xaa\xc2\xdf\x4e\xe6\xce\xa9\x17\x38\xf5\x12\ -\x35\x6d\xdd\x7b\x95\xe6\x97\x11\x8b\xdd\xe3\xc3\xd8\xe7\x49\x00\ -\x84\x33\x6d\x4e\xc9\x26\x5f\xa6\x2c\x08\xcc\xcf\x4c\xc0\x87\x80\ -\x99\x4a\x60\x72\x24\x80\x25\x3c\x38\x2c\xdf\xda\xaa\x38\xa2\x2f\ -\x74\x86\xab\x81\x5b\x25\x91\xae\xa1\x24\x58\x2b\x33\xc3\xc0\xed\ -\xb4\x40\x66\x85\x81\x92\x51\xfd\xae\xd5\x62\x53\xdc\xdf\xd8\xed\ -\x07\xb8\x3c\xa7\x3e\x84\x92\x07\xa0\xae\x17\xd7\x73\x98\x3a\xec\ -\xeb\x96\xe7\x78\xf1\x2e\x61\xdc\x1e\x9f\xfc\xc0\x21\xc2\x15\x5e\ -\x29\x39\x9e\xd8\xf1\x0b\x2e\x47\xd7\xa0\x22\x26\xec\xdb\xa6\x2d\ -\xe5\xb3\x1b\x16\x3f\xc9\x70\xdf\xdc\x26\xeb\x14\x05\xee\xb7\xc9\ -\xda\x39\x27\x0a\xec\x3b\x00\xbc\x59\xfb\x69\xc5\x02\x91\x56\x46\ -\xb7\xe3\x8d\x64\xec\x3b\x30\xaf\x09\x1a\x66\xb6\x35\x99\xc0\x76\ -\x3d\x72\x2f\x6a\x49\x90\x58\x2a\x69\x30\xeb\x12\xfe\x7b\xc7\xa6\ -\x6a\x2a\x01\xd4\x63\xec\xae\x5a\x05\xbe\xff\xf3\x65\xb7\xc3\xba\ -\xd8\x65\x5f\xaf\x96\x8f\x1f\xda\x9b\xbf\x47\x2d\x29\x76\x3e\x9a\ -\xd8\xfc\x67\xcb\x4a\xff\x46\xa0\x6b\x10\x65\x3d\xf4\xf1\x0e\x3b\ -\x34\xaf\x67\x77\xd8\x61\x2d\x87\x1d\xce\x65\xd2\xe7\xd0\x8b\x99\ -\xa8\xc3\xbd\xc0\x51\x35\x52\x57\xda\xab\xef\xc5\xe0\xb3\x81\x2d\ -\x7c\x2c\x0a\x45\x54\x4c\x88\x61\xb6\x39\xb0\xed\xc8\x2d\x83\x91\ -\xab\x93\x4a\xbe\x17\x25\x58\x36\x61\xfb\x42\xe3\x98\x33\x24\x63\ -\xc5\xe4\xa3\x9f\xda\x59\x2b\xe0\xd5\x2d\xe5\x09\xcc\xe9\x98\xae\ -\xb1\xdb\x79\xb9\x57\xfe\xe3\xb5\x33\xca\x26\x51\x11\x63\xcf\x56\ -\xa3\xd7\xf9\xba\x9f\x24\x32\x2e\x5f\xbb\x94\x80\x21\xaf\x11\xca\ -\xc7\xef\xef\x83\x07\x05\x14\x7c\xcf\x78\x94\x80\xa0\x5a\xaf\x2c\ -\x11\xfe\xe5\xc8\xcf\x82\xbe\x53\x09\xfa\x3c\xde\x0f\x2a\xf1\x5e\ -\x0a\xf5\x79\x55\x4a\x01\x5e\x18\x69\xc6\x92\x33\x66\xcc\x52\x4d\ -\x7e\x1a\x33\xfb\x5c\xe6\xac\x75\xd4\x22\xe9\x77\x2f\x67\xad\xfd\ -\xfd\x96\x6d\x05\xbc\x98\x8d\x23\x1a\x0f\x12\xe1\xb6\xc3\xba\xff\ -\x5d\xb9\xfb\x0b\xec\x41\xbe\x60\x40\xf6\x64\xa2\x7c\x40\x5d\xca\ -\xb3\xec\xa7\x4f\x18\x8e\x32\x4a\x25\x6a\xa7\xc9\xec\x48\xaa\xe5\ -\xcc\xe7\x51\x33\x47\xa8\x8a\x4f\xa2\xec\xf3\x18\x1b\x2c\x41\x74\ -\xf7\xdb\x55\xa2\xc3\x9c\x9e\x0f\x3e\x4b\xcd\x45\xb1\x44\xb1\x5c\ -\xda\xe9\x27\x53\xfa\x65\x68\x2d\xe7\x46\x9d\x05\xe6\x05\x37\x6b\ -\x32\x77\xa0\xab\x56\x9b\xaa\xca\x8b\x54\xb2\xdc\xd6\xa7\x56\x56\ -\x6d\xd6\x5b\xa8\xa0\x6e\x45\x99\xbc\x27\xae\x57\xa6\xa0\x6e\x45\ -\x99\x52\x52\xaa\xd7\x68\x6e\xca\xea\x6a\x95\x07\xdc\x27\x7c\x0a\ -\xb4\x0b\x08\xed\x42\x27\x3b\x09\x65\x77\x91\xf1\xde\x6b\x27\xac\ -\xfb\xec\x7f\x23\x8e\x6e\x06\ +\x00\x3d\x0e\x78\x9c\xed\x5b\x6d\x6f\xdb\x36\x10\xfe\xde\x5f\x41\ +\xf8\xd3\x06\x74\xb5\x9d\xb7\x26\x81\xe2\x61\x6d\x9a\x36\x43\xbb\ +\xa5\x73\xd6\x7e\x1c\x68\xe9\x6c\x71\xa1\x48\x8d\xa4\x62\xbb\xbf\ +\x7e\x47\x4a\xb2\x2c\x5b\x52\xe2\xf8\x25\x40\xe0\xa2\x45\x25\x1e\ +\x7d\x77\x3c\xdd\x3d\x77\x47\x4a\xde\xaf\x93\x88\x93\x7b\x50\x9a\ +\x49\x71\xd1\xea\xbe\xe9\xb4\x08\x08\x5f\x06\x4c\x8c\x2e\x5a\x7f\ +\xdf\x5e\xfd\x72\xda\xfa\xb5\xf7\xca\x4b\x58\x31\xe9\x08\x27\xf5\ +\x5e\x11\xcf\xe7\x54\xeb\xde\xc7\x84\x9d\x9f\x5f\x32\xca\xe5\x08\ +\xff\xe7\xa3\x3e\x18\x83\x3f\xd6\xbf\x29\x3f\xf4\xda\xe9\x1c\x9c\ +\x3c\x66\xc1\x08\x0c\x71\xf7\x17\xad\xaf\xdf\xdd\x6d\x8b\x08\x1a\ +\xc1\x45\xab\x89\x87\x15\x45\xbc\x58\xc9\x18\x94\x99\x66\x3f\x18\ +\x81\x8c\xc0\xa8\xa9\x23\x12\x4f\x81\x6f\xdc\x15\xf1\x26\xbd\x8e\ +\xd7\x9e\x64\x37\x53\x7b\x33\xcd\x6e\x50\x03\x13\xf6\x8e\xdf\x1e\ +\x7b\xed\xf4\x32\x1d\x0e\x81\x8d\x42\xd3\x3b\x39\x38\xf3\xda\xd9\ +\xb5\xe3\xd9\xce\x99\x7a\xed\x5c\x78\x95\x26\x63\x26\x02\x39\xbe\ +\x65\x86\x43\xa6\x8c\x36\x0a\x75\xef\x7d\x04\x01\x8a\x72\xa2\xb3\ +\xb5\x78\xed\x8c\xb0\xcc\x92\xd3\xa9\x4c\x0a\xdb\x7c\x7b\x27\x27\ +\x9f\xdd\x50\xc6\x71\x41\xa4\x8e\xa9\x8f\x8c\x5a\xd9\x02\x44\x12\ +\x0d\x40\xf5\x4e\xbc\x76\x76\x95\xaa\x3f\x2f\x61\x89\x45\x44\xd5\ +\x88\x89\x05\x0e\x67\x8d\x1c\x98\x81\xa8\xb0\xe4\xfc\xb3\xfc\xa8\ +\x64\x12\xa3\xce\xf9\xd3\x1c\xe5\xf7\xe9\xf4\x25\xe1\xa6\x30\x56\ +\x85\xbd\xec\x33\x27\xfd\x0a\xa3\x2d\xeb\xd4\x68\xba\x4c\x18\x7a\ +\xad\x61\x3e\xe5\xe9\xe8\x3f\x07\x85\xdc\x62\x41\x15\x8c\x3e\x2d\ +\x31\x0a\xa5\x62\x3f\xa4\x30\x15\xac\x16\x99\x2d\x9b\xe8\x33\x1d\ +\x00\xcf\x39\x71\x7b\x53\xfa\x79\x85\x8d\x60\x62\x4a\x13\x66\x76\ +\xba\x84\x21\x4d\x38\xb2\x96\x5c\x2a\x32\xc4\x7f\x63\xca\xf9\xa2\ +\xa5\xaa\xcd\x95\x0e\xa6\xba\xcd\x29\xdf\x2e\x6b\xbf\xb4\x18\xeb\ +\x70\xa0\x96\xec\xd0\x77\xc3\x8d\xcb\xc0\xb9\x80\x53\x0d\xe2\xc6\ +\xc2\x6a\x00\x5d\xad\xf7\xd5\x9c\x9f\x7f\x9a\xf1\xf3\xda\x6e\xf0\ +\xa1\x05\x2c\xc7\x03\xfb\x01\x9f\x98\xc0\x27\xa5\x4d\x80\xe1\x76\ +\xd1\xea\x2c\x9a\x0e\x67\x94\x46\x72\x34\x38\xea\x94\xc0\x60\x46\ +\xcd\x80\xe0\xa0\x53\xc2\x84\x42\xad\x45\x86\x35\x96\x4e\x0d\xb7\ +\x82\xa5\xcb\x6e\xe3\x60\xf1\x46\xc1\xf0\xbd\x7d\xd6\xef\x12\x63\ +\xd0\x8c\x79\x90\x59\x5a\x8c\x34\xe7\x07\x83\x94\xd6\xe8\x51\x52\ +\xf2\x5b\x16\x57\x3b\xd5\x6d\xc8\x34\xc1\xbf\x26\x04\x12\x2c\x39\ +\x98\x80\x31\xf9\x8e\x4e\x46\xe4\xe0\x5f\x04\xc5\xc7\xfb\xda\x92\ +\x12\x8e\xe7\x82\x0a\x6e\x6c\xc1\xfe\x0a\x82\xde\x41\xf7\xc8\x82\ +\x70\xb0\x40\x1a\x29\x00\x91\x12\xd3\xcb\x32\x79\xc0\x13\x48\xa9\ +\xee\xaa\xfc\xd8\x96\x44\x3d\x4e\x6b\x6b\xe6\x0f\xc2\xa6\x9b\x5a\ +\x0f\xf3\x33\x8b\x58\x33\xb9\xa7\x85\xc2\x9e\x6a\x24\x2b\xee\x86\ +\x9a\xf0\x61\x69\x5f\x64\xd0\xce\xf2\xec\xa6\xa2\xdf\x6b\xa7\x48\ +\x38\x83\xc9\x12\x79\x5d\xd0\x5c\x0b\x32\x37\x06\x98\x48\x48\x7c\ +\x93\x28\x78\x3e\xd4\x7c\x00\xfe\xf7\xb8\xb9\x4b\xdc\x7c\x28\x17\ +\xaf\x87\x9c\xfd\xdc\xdb\x76\x0b\x9f\xdd\xe3\x4e\x3d\x7c\x76\x4f\ +\xce\x1a\xe0\xb3\x7b\x7a\xf2\x4c\xf0\x39\xb3\xd5\x1e\x43\xeb\x0b\ +\xcf\x93\xf5\x0a\xcf\xe3\xcd\x15\x9e\xae\xf7\x79\x46\x10\x3d\xda\ +\x83\x68\xbd\xad\x77\x0d\xa2\x87\x8d\x0f\x63\x15\xe8\x3a\x3c\xac\ +\x47\xae\xa3\xe3\x06\xe0\x3a\x79\x2e\xdc\xfa\xee\x22\x61\x0f\x5a\ +\xf5\xa0\xd5\x3d\x5a\x0f\xb5\x4e\x36\x8c\x5a\x64\x64\x65\x3d\x1f\ +\x74\x35\xa3\xf0\x1e\xba\x76\x0a\x5d\xcd\x79\x64\x15\xe8\x3a\x6b\ +\x80\xae\xee\xe9\x61\x53\xcf\xda\x39\x7c\x56\xf0\xfa\x68\x6d\xb7\ +\x47\xb0\x06\x04\xeb\x3c\x1e\xc1\x0a\x0f\x0c\xc1\xbf\x9b\xdf\x1b\ +\x9d\xb9\x9f\x25\x0c\xe4\xe4\x9f\xd3\xa7\xf7\x1e\xd7\x43\x6c\x3b\ +\xd2\xf6\xc3\xb1\x83\xe0\x35\x19\x87\x20\xc8\x01\xd1\x2c\x62\x9c\ +\x66\x7b\x83\x84\x62\xf3\x31\x00\xfc\x09\xc2\xa0\x10\xd8\x83\xd8\ +\x99\xd8\xb1\x30\x45\x12\x11\x80\xe2\x53\x4b\xd3\x77\x60\x90\x8f\ +\x46\x84\xe4\x1c\xe7\x93\x7f\x25\x13\x10\x10\x84\x08\x49\xa4\x80\ +\xd7\x84\x8a\xc0\x35\x3a\x66\x2c\x33\xce\xd9\x54\x5f\x46\x60\xa7\ +\x3c\xbd\xb5\xa9\x47\xf0\xdf\x51\x8b\x4c\xda\x80\x6a\x98\x53\xd3\ +\x2e\x35\x96\x5a\xb3\x01\x5f\x43\xf2\x0a\x91\x62\x0d\x62\x77\x78\ +\xfa\x99\x0a\x2f\x32\x52\xca\xc4\x12\xaf\xb9\x79\x4f\x38\x0f\x28\ +\xda\xec\xc7\x9d\x08\x5c\x5f\xbd\x27\x2c\x8a\xa5\x32\x9b\x3e\x06\ +\xd8\xdc\x21\xc0\xd9\x56\x30\xe1\x81\x16\xad\x09\x13\x1c\xf3\x14\ +\x16\x30\x6a\x03\xa6\x63\x5c\x14\x09\x60\x90\x8c\x48\x04\x5a\xd3\ +\x91\x8b\x1c\xc6\x21\xb3\xad\x8d\x7c\x6b\xe9\x21\x0e\xad\xb1\x35\ +\x51\x1f\xbf\xfd\x10\xab\xad\xb2\x02\x3b\x09\x56\x36\xf4\x2f\xad\ +\xd4\x17\x19\xa4\xeb\x7b\xee\xf1\x36\x3c\x77\xb3\xb9\x6c\xe6\x96\ +\x69\x9a\xa1\x7c\x4c\xa7\xda\x26\xa6\xd4\x73\x31\x35\x8d\x99\x09\ +\x5d\x46\xc2\x1c\x05\x4a\x50\x4e\xe2\xa9\x09\x25\xa6\x05\xaa\x34\ +\xa8\xd7\x04\xee\x31\x47\xb0\x21\xb9\x1e\xfa\x7f\xc6\x20\xfa\x21\ +\x20\x23\x2b\x46\x68\x34\x05\x87\x60\x1b\x1e\x7f\x25\x95\x0f\x65\ +\x4d\x76\xe2\xf1\x43\x2b\x17\x57\x7a\xe3\x24\xdf\x64\x82\xf7\xde\ +\x5f\xe1\xfd\x87\x5b\xc1\xed\x35\xf6\x91\xdf\x2b\xa0\x06\x3d\xdd\ +\x25\x4b\xed\x1a\x55\xa0\x7e\x98\x1e\x87\xa7\x1b\xc7\xc4\x4c\xe3\ +\xad\x54\x58\x2e\x61\x63\x69\x88\x51\x25\xb0\xed\xc4\x10\x9b\x3a\ +\x59\xbb\xc1\x69\xdf\xad\x1c\xdd\xd6\xa9\xf1\x32\x6b\xaa\xf5\x1d\ +\x76\x85\xed\x93\x15\x1c\xb6\x79\xcf\xae\xde\x63\xae\x1d\x00\x93\ +\x61\xa2\x04\x73\x47\x1b\x3f\xf9\x54\x90\x88\xde\x81\x43\xe3\x48\ +\x06\xc0\x49\x08\xf4\x7e\xfa\xf3\x6e\x72\xbd\xd3\x07\x7d\xe8\x2a\ +\xd7\x68\xef\x46\xd5\x4d\x6c\x77\x2b\x7e\xf4\xc0\xee\xdc\xaa\x89\ +\x1f\x7f\x2d\xec\xeb\x3f\xb3\x4e\x74\x96\xf0\xa9\x26\x3a\x19\x18\ +\x45\x7d\xbb\x37\xa6\x71\x2a\xfa\x9b\x1a\x33\xec\x0b\x6d\x8b\x48\ +\x74\x48\xe3\xa2\x5e\x40\x64\x09\xa6\x24\xa4\xf7\x90\x75\xbb\x33\ +\xc6\x39\x93\xed\x14\x00\x7d\xc0\xac\x8f\xa0\x36\x93\xb7\xab\x82\ +\x37\x17\xfc\xe7\x4c\xee\x3e\x0a\xaa\xa2\x60\x85\x77\xb7\x56\x88\ +\x82\xb7\x1b\x8e\x82\x34\xeb\xdb\x5f\x17\x91\x60\x05\xb2\xc9\x7c\ +\xe9\x6b\xab\xe4\xeb\x4b\x92\xbe\xba\xb7\x0d\x6f\xbe\x71\x22\x67\ +\x7a\xa0\xd8\x0d\x88\x5b\xcd\xaf\x53\x15\xfe\x70\x32\xf7\x4e\x5d\ +\xe3\xd4\x2b\xd4\xb4\x55\x27\x2c\xcd\x9b\xe0\xf5\xee\xf1\x61\xe2\ +\xf3\x24\x00\xc2\x99\x36\xe7\x64\x9b\x27\x2a\x35\x81\xf9\x99\x09\ +\xf8\x10\x30\xb3\x14\x98\x1c\x09\x60\x09\x4f\x0e\xcb\xdf\x6c\x55\ +\x1c\xd1\x5f\x74\x86\xab\x81\x5b\x25\x91\xae\xa1\x24\x58\x2b\x33\ +\xc3\xc0\xed\xb4\x40\x66\x85\xa1\x92\x51\xf5\xae\x55\xbd\x29\x1e\ +\x6f\xec\xf6\x13\x5c\x9e\x53\x1f\x42\xc9\x03\x50\xb7\xf5\xf5\x1c\ +\xa6\x0e\x7b\xe6\xf2\x1a\x2f\xde\x25\x8c\xdb\xd7\xbf\x3f\x70\x88\ +\x70\x85\x37\x4a\x4e\xa6\x76\xfc\x8a\xcb\xf1\x2d\xa8\x88\x09\x7b\ +\xe4\xb4\xa3\x7c\x76\xc7\xe2\x17\x19\xee\xdb\xdb\x64\x9d\xa1\xc0\ +\xe3\x36\x59\x0f\x2e\x89\x02\x7b\x06\x80\x37\x1b\x7f\xdb\xba\x40\ +\xa4\xb5\xd1\xed\xed\x56\x32\xf6\x03\x98\xd7\x04\x0d\x73\xdb\x9a\ +\x4c\x60\xbb\x1e\xb9\xd3\x5a\x12\x24\x96\x4a\x1a\xcc\xba\x82\xff\ +\x3e\xb0\xa9\x9a\x4a\x00\xf5\x1c\xbb\xab\x56\x81\x6f\x7f\x7d\xd9\ +\xef\xb0\xd6\xbb\xec\xe9\x7a\xf9\xf8\xa9\xbd\xf9\x7b\xd4\x92\x62\ +\xe7\xa3\x89\xcd\x7f\xb6\xac\xf4\xef\x04\xba\x06\x51\xd6\x43\x9f\ +\xef\x8d\x87\xe6\xf5\xec\xdf\x78\xd8\xc8\x1b\x0f\x97\x32\x19\x70\ +\xe8\xc7\x4c\x54\xe1\x5e\xe0\xa8\x1a\xa9\x6b\xed\xd5\xf7\x63\xf0\ +\xd9\xd0\x16\x3e\x16\x85\x22\x2a\xa6\xc4\x30\xdb\x1c\xd8\x76\xe4\ +\x9e\xc1\xd8\xd5\x49\x25\xdf\x8b\x12\x2c\x9b\xb0\x7d\xa1\x71\xcc\ +\x19\x92\xb1\x62\xf2\xd1\x4f\xed\xac\x35\xf0\xea\x9e\xf2\x04\x16\ +\x74\x4c\xd7\xd8\x3b\x78\xd3\x29\xff\xf1\xda\x19\x65\x9b\xa8\x88\ +\xb1\x67\xab\xd1\xdb\x7c\xdd\x2f\x12\x19\x57\xaf\x5d\x4a\xc0\x90\ +\xd7\x08\xe5\xcf\x87\x1e\x83\x07\x05\x14\x7c\xcb\x78\x94\x80\x60\ +\xb9\x5e\x59\x21\xfc\xcb\x91\x9f\x05\xfd\xc1\x52\xd0\xe7\xf1\x7e\ +\xb4\x14\xef\xa5\x50\x5f\x54\xa5\x14\xe0\x85\x91\xe6\x2c\x39\x67\ +\xc6\x2c\xd5\xe4\x6f\x93\x67\x9f\xfb\x5d\xb4\x4e\x5a\x24\xfd\x6e\ +\xef\xa2\xd5\xed\xb6\x6c\x2b\xe0\xc5\x6c\x12\xd1\x78\x98\x08\xb7\ +\x1d\xd6\xfb\xef\xc6\xdd\x5f\x61\x0f\xf2\x05\x03\xb2\x2f\x13\xe5\ +\x03\xea\x52\x9e\x65\x3f\xdd\xc4\x70\x94\x51\x2a\x51\x3b\x4d\xe6\ +\x47\x52\x2d\xe7\x3e\xef\x9c\x7b\x8f\xaa\xf8\xa4\xd3\x3e\x8f\x89\ +\xc1\x12\x44\xf7\xbe\xde\x24\x3a\xcc\xe9\xf9\xe0\xab\xd4\x5c\x14\ +\x4b\x14\xcb\xa5\x9d\x7e\xf2\xa9\xdf\x84\xd6\x72\x6e\xd4\x59\x60\ +\x51\x70\xb3\x26\x0b\x6f\x75\x55\x6a\xb3\xac\x72\x9d\x4a\x96\xdb\ +\xe6\xd4\xca\xaa\xcd\x6a\x0b\x15\xd4\x9d\x28\x93\xf7\xc4\xd5\xca\ +\x14\xd4\x9d\x28\x53\x4a\x4a\xd5\x1a\x2d\x4c\x59\x5f\xad\xf2\x80\ +\xfb\x04\x59\x81\x76\x01\xa1\x5d\xe8\x64\x6f\x42\xd9\x5d\x64\xbc\ +\xf7\xda\x09\xeb\xbd\xfa\x1f\x60\x53\xb8\xc3\ \x00\x00\x07\x4c\ \x00\ \x00\x29\xd1\x78\x9c\xed\x59\x5b\x8f\xe2\x46\x16\x7e\xef\x5f\xe1\ @@ -33367,37 +33370,37 @@ qt_resource_struct = "\ \x00\x00\x01\x14\x00\x00\x00\x00\x00\x01\x00\x02\x52\xbc\ \x00\x00\x00\xe0\x00\x00\x00\x00\x00\x01\x00\x01\xbc\xaa\ \x00\x00\x02\x3e\x00\x00\x00\x00\x00\x01\x00\x05\x84\xf1\ -\x00\x00\x06\x96\x00\x01\x00\x00\x00\x01\x00\x07\xac\x45\ -\x00\x00\x05\x76\x00\x00\x00\x00\x00\x01\x00\x07\x63\x49\ -\x00\x00\x04\x12\x00\x00\x00\x00\x00\x01\x00\x07\x05\x4d\ -\x00\x00\x07\xc6\x00\x01\x00\x00\x00\x01\x00\x08\x04\x1a\ -\x00\x00\x06\x68\x00\x01\x00\x00\x00\x01\x00\x07\xa5\x70\ -\x00\x00\x04\x4c\x00\x01\x00\x00\x00\x01\x00\x07\x13\xbc\ -\x00\x00\x04\x9e\x00\x01\x00\x00\x00\x01\x00\x07\x27\x43\ -\x00\x00\x03\xb6\x00\x01\x00\x00\x00\x01\x00\x06\xea\xab\ -\x00\x00\x07\x60\x00\x00\x00\x00\x00\x01\x00\x07\xe0\xd6\ -\x00\x00\x05\xb6\x00\x00\x00\x00\x00\x01\x00\x07\x7d\x23\ -\x00\x00\x05\x56\x00\x01\x00\x00\x00\x01\x00\x07\x5b\x81\ -\x00\x00\x03\x94\x00\x01\x00\x00\x00\x01\x00\x06\xe1\xb2\ -\x00\x00\x06\x3c\x00\x01\x00\x00\x00\x01\x00\x07\x9a\x46\ -\x00\x00\x03\x38\x00\x01\x00\x00\x00\x01\x00\x06\xcf\x91\ -\x00\x00\x07\x36\x00\x01\x00\x00\x00\x01\x00\x07\xd9\x41\ -\x00\x00\x04\x7a\x00\x01\x00\x00\x00\x01\x00\x07\x1d\x14\ -\x00\x00\x03\x0e\x00\x01\x00\x00\x00\x01\x00\x06\xc5\xe9\ -\x00\x00\x03\x74\x00\x01\x00\x00\x00\x01\x00\x06\xd9\x44\ -\x00\x00\x05\xe6\x00\x01\x00\x00\x00\x01\x00\x07\x8c\x91\ -\x00\x00\x05\x0a\x00\x00\x00\x00\x00\x01\x00\x07\x43\x3e\ -\x00\x00\x06\x14\x00\x01\x00\x00\x00\x01\x00\x07\x91\xe1\ -\x00\x00\x05\x34\x00\x01\x00\x00\x00\x01\x00\x07\x53\xbf\ -\x00\x00\x06\xc0\x00\x00\x00\x00\x00\x01\x00\x07\xb4\x8a\ -\x00\x00\x04\xc2\x00\x01\x00\x00\x00\x01\x00\x07\x2c\x5a\ -\x00\x00\x07\x0a\x00\x01\x00\x00\x00\x01\x00\x07\xd0\xc7\ -\x00\x00\x06\xea\x00\x01\x00\x00\x00\x01\x00\x07\xc6\x8d\ -\x00\x00\x05\x96\x00\x01\x00\x00\x00\x01\x00\x07\x77\x0b\ -\x00\x00\x07\x8c\x00\x00\x00\x00\x00\x01\x00\x07\xf2\xa5\ -\x00\x00\x03\xe8\x00\x00\x00\x00\x00\x01\x00\x06\xf2\xed\ -\x00\x00\x04\xec\x00\x00\x00\x00\x00\x01\x00\x07\x34\x42\ -\x00\x00\x02\xda\x00\x01\x00\x00\x00\x01\x00\x06\xbe\x99\ +\x00\x00\x06\x96\x00\x01\x00\x00\x00\x01\x00\x07\xac\x79\ +\x00\x00\x05\x76\x00\x00\x00\x00\x00\x01\x00\x07\x63\x7d\ +\x00\x00\x04\x12\x00\x00\x00\x00\x00\x01\x00\x07\x05\x81\ +\x00\x00\x07\xc6\x00\x01\x00\x00\x00\x01\x00\x08\x04\x4e\ +\x00\x00\x06\x68\x00\x01\x00\x00\x00\x01\x00\x07\xa5\xa4\ +\x00\x00\x04\x4c\x00\x01\x00\x00\x00\x01\x00\x07\x13\xf0\ +\x00\x00\x04\x9e\x00\x01\x00\x00\x00\x01\x00\x07\x27\x77\ +\x00\x00\x03\xb6\x00\x01\x00\x00\x00\x01\x00\x06\xea\xdf\ +\x00\x00\x07\x60\x00\x00\x00\x00\x00\x01\x00\x07\xe1\x0a\ +\x00\x00\x05\xb6\x00\x00\x00\x00\x00\x01\x00\x07\x7d\x57\ +\x00\x00\x05\x56\x00\x01\x00\x00\x00\x01\x00\x07\x5b\xb5\ +\x00\x00\x03\x94\x00\x01\x00\x00\x00\x01\x00\x06\xe1\xe6\ +\x00\x00\x06\x3c\x00\x01\x00\x00\x00\x01\x00\x07\x9a\x7a\ +\x00\x00\x03\x38\x00\x01\x00\x00\x00\x01\x00\x06\xcf\xc5\ +\x00\x00\x07\x36\x00\x01\x00\x00\x00\x01\x00\x07\xd9\x75\ +\x00\x00\x04\x7a\x00\x01\x00\x00\x00\x01\x00\x07\x1d\x48\ +\x00\x00\x03\x0e\x00\x01\x00\x00\x00\x01\x00\x06\xc6\x1d\ +\x00\x00\x03\x74\x00\x01\x00\x00\x00\x01\x00\x06\xd9\x78\ +\x00\x00\x05\xe6\x00\x01\x00\x00\x00\x01\x00\x07\x8c\xc5\ +\x00\x00\x05\x0a\x00\x00\x00\x00\x00\x01\x00\x07\x43\x72\ +\x00\x00\x06\x14\x00\x01\x00\x00\x00\x01\x00\x07\x92\x15\ +\x00\x00\x05\x34\x00\x01\x00\x00\x00\x01\x00\x07\x53\xf3\ +\x00\x00\x06\xc0\x00\x00\x00\x00\x00\x01\x00\x07\xb4\xbe\ +\x00\x00\x04\xc2\x00\x01\x00\x00\x00\x01\x00\x07\x2c\x8e\ +\x00\x00\x07\x0a\x00\x01\x00\x00\x00\x01\x00\x07\xd0\xfb\ +\x00\x00\x06\xea\x00\x01\x00\x00\x00\x01\x00\x07\xc6\xc1\ +\x00\x00\x05\x96\x00\x01\x00\x00\x00\x01\x00\x07\x77\x3f\ +\x00\x00\x07\x8c\x00\x00\x00\x00\x00\x01\x00\x07\xf2\xd9\ +\x00\x00\x03\xe8\x00\x00\x00\x00\x00\x01\x00\x06\xf3\x21\ +\x00\x00\x04\xec\x00\x00\x00\x00\x00\x01\x00\x07\x34\x76\ +\x00\x00\x02\xda\x00\x01\x00\x00\x00\x01\x00\x06\xbe\xcd\ \x00\x00\x02\xb2\x00\x01\x00\x00\x00\x01\x00\x06\xb6\xfd\ " diff --git a/src/Mod/Arch/Resources/ui/archprefs-base.ui b/src/Mod/Arch/Resources/ui/archprefs-base.ui index 47baea738..4741046ae 100644 --- a/src/Mod/Arch/Resources/ui/archprefs-base.ui +++ b/src/Mod/Arch/Resources/ui/archprefs-base.ui @@ -55,9 +55,9 @@ - 255 - 190 - 170 + 214 + 214 + 214 @@ -140,9 +140,9 @@ - 59 - 132 - 146 + 33 + 45 + 66 @@ -155,6 +155,47 @@ + + + + + + Default color for window glass + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 93 + 183 + 203 + + + + WindowGlassColor + + + Mod/Arch + + + + + From ed6a820f9f6b0f77bd8ca5ba4506a38e2069786d Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 3 Jul 2013 19:30:10 +0200 Subject: [PATCH 137/160] 0000803: Feature request - box selection for faces in set color mode --- src/Mod/Part/Gui/TaskFaceColors.cpp | 106 +++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 11 deletions(-) diff --git a/src/Mod/Part/Gui/TaskFaceColors.cpp b/src/Mod/Part/Gui/TaskFaceColors.cpp index 4d2a3b192..ef1c1804e 100644 --- a/src/Mod/Part/Gui/TaskFaceColors.cpp +++ b/src/Mod/Part/Gui/TaskFaceColors.cpp @@ -34,8 +34,13 @@ # include # include # include +# include +# include +# include +# include # include # include +# include #endif #include @@ -44,12 +49,14 @@ #include "ui_TaskFaceColors.h" #include "TaskFaceColors.h" #include "ViewProviderExt.h" +#include "SoBrepShape.h" #include #include #include #include #include +#include #include #include #include @@ -87,6 +94,7 @@ class FaceColors::Private public: typedef boost::signals::connection Connection; Ui_TaskFaceColors* ui; + Gui::View3DInventorViewer* view; ViewProviderPartExt* vp; App::DocumentObject* obj; Gui::Document* doc; @@ -118,7 +126,45 @@ public: { delete ui; } - void addFacesToSelection(const Gui::ViewVolumeProjection& proj, const Base::Polygon2D& polygon, const TopoDS_Shape& shape) + bool isVisibleFace(int faceIndex, const SbVec2f& pos, Gui::View3DInventorViewer* viewer) + { + SoSeparator* root = new SoSeparator; + root->ref(); + root->addChild(viewer->getCamera()); + root->addChild(vp->getRoot()); + + SoSearchAction searchAction; + searchAction.setType(PartGui::SoBrepFaceSet::getClassTypeId()); + searchAction.setInterest(SoSearchAction::FIRST); + searchAction.apply(root); + SoPath* selectionPath = searchAction.getPath(); + + SoRayPickAction rp(viewer->getViewportRegion()); + rp.setNormalizedPoint(pos); + rp.apply(selectionPath); + root->unref(); + + SoPickedPoint* pick = rp.getPickedPoint(); + if (pick) { + const SoDetail* detail = pick->getDetail(); + if (detail && detail->isOfType(SoFaceDetail::getClassTypeId())) { + int index = static_cast(detail)->getPartIndex(); + if (faceIndex != index) + return false; + SbVec3f dir = viewer->getViewDirection(); + const SbVec3f& nor = pick->getNormal(); + if (dir.dot(nor) > 0) + return false; // bottom side points to user + return true; + } + } + + return false; + } + void addFacesToSelection(Gui::View3DInventorViewer* viewer, + const Gui::ViewVolumeProjection& proj, + const Base::Polygon2D& polygon, + const TopoDS_Shape& shape) { try { TopTools_IndexedMapOfShape M; @@ -133,16 +179,38 @@ public: for (Standard_Integer k = 1; k <= M.Extent(); k++) { const TopoDS_Shape& face = M(k); - GProp_GProps props; - BRepGProp::SurfaceProperties(face, props); - gp_Pnt c = props.CentreOfMass(); - Base::Vector3d pt2d; - pt2d = proj(Base::Vector3d(c.X(), c.Y(), c.Z())); - if (polygon.Contains(Base::Vector2D(pt2d.x, pt2d.y))) { - std::stringstream str; - str << "Face" << k; - Gui::Selection().addSelection(appdoc->getName(), obj->getNameInDocument(), str.str().c_str()); + TopExp_Explorer xp_vertex(face,TopAbs_VERTEX); + while (xp_vertex.More()) { + gp_Pnt p = BRep_Tool::Pnt(TopoDS::Vertex(xp_vertex.Current())); + Base::Vector3d pt2d; + pt2d = proj(Base::Vector3d(p.X(), p.Y(), p.Z())); + if (polygon.Contains(Base::Vector2D(pt2d.x, pt2d.y))) { +#if 0 + // TODO + if (isVisibleFace(k-1, SbVec2f(pt2d.x, pt2d.y), viewer)) +#endif + { + std::stringstream str; + str << "Face" << k; + Gui::Selection().addSelection(appdoc->getName(), obj->getNameInDocument(), str.str().c_str()); + break; + } + } + xp_vertex.Next(); } + + //GProp_GProps props; + //BRepGProp::SurfaceProperties(face, props); + //gp_Pnt c = props.CentreOfMass(); + //Base::Vector3d pt2d; + //pt2d = proj(Base::Vector3d(c.X(), c.Y(), c.Z())); + //if (polygon.Contains(Base::Vector2D(pt2d.x, pt2d.y))) { + // if (isVisibleFace(k-1, SbVec2f(pt2d.x, pt2d.y), viewer)) { + // std::stringstream str; + // str << "Face" << k; + // Gui::Selection().addSelection(appdoc->getName(), obj->getNameInDocument(), str.str().c_str()); + // } + //} } } catch (...) { @@ -152,6 +220,8 @@ public: { Gui::View3DInventorViewer* view = reinterpret_cast(cb->getUserData()); view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), selectionCallback, ud); + SoNode* root = view->getSceneGraph(); + static_cast(root)->selectionRole.setValue(TRUE); std::vector picked = view->getGLPolygon(); SoCamera* cam = view->getCamera(); @@ -172,10 +242,12 @@ public: } FaceColors* self = reinterpret_cast(ud); + self->d->view = 0; if (self->d->obj && self->d->obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { cb->setHandled(); const TopoDS_Shape& shape = static_cast(self->d->obj)->Shape.getValue(); - self->d->addFacesToSelection(proj, polygon, shape); + self->d->addFacesToSelection(view, proj, polygon, shape); + view->render(); } } }; @@ -200,6 +272,13 @@ FaceColors::FaceColors(ViewProviderPartExt* vp, QWidget* parent) FaceColors::~FaceColors() { + if (d->view) { + d->view->stopSelection(); + d->view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), + Private::selectionCallback, this); + SoNode* root = d->view->getSceneGraph(); + static_cast(root)->selectionRole.setValue(TRUE); + } Gui::Selection().rmvSelectionGate(); d->connectDelDoc.disconnect(); d->connectDelObj.disconnect(); @@ -226,6 +305,11 @@ void FaceColors::on_boxSelection_clicked() if (!viewer->isSelecting()) { viewer->startSelection(Gui::View3DInventorViewer::Rubberband); viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), Private::selectionCallback, this); + // avoid that the selection node handles the event otherwise the callback function won't be + // called immediately + SoNode* root = viewer->getSceneGraph(); + static_cast(root)->selectionRole.setValue(FALSE); + d->view = viewer; } } } From bd303074322542fb0c20a9415f1436b72fd2aa78 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 3 Jul 2013 19:31:00 +0200 Subject: [PATCH 138/160] disable selection node during box selection --- src/Gui/CommandView.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Gui/CommandView.cpp b/src/Gui/CommandView.cpp index 3cc407ff0..bdcbb1336 100644 --- a/src/Gui/CommandView.cpp +++ b/src/Gui/CommandView.cpp @@ -49,6 +49,7 @@ #include "Selection.h" #include "SoFCOffscreenRenderer.h" #include "SoFCBoundingBox.h" +#include "SoFCUnifiedSelection.h" #include "SoAxisCrossKit.h" #include "View3DInventor.h" #include "View3DInventorViewer.h" @@ -1922,6 +1923,9 @@ static void selectionCallback(void * ud, SoEventCallback * cb) { Gui::View3DInventorViewer* view = reinterpret_cast(cb->getUserData()); view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), selectionCallback, ud); + SoNode* root = view->getSceneGraph(); + static_cast(root)->selectionRole.setValue(TRUE); + std::vector picked = view->getGLPolygon(); SoCamera* cam = view->getCamera(); SbViewVolume vv = cam->getViewVolume(); @@ -1974,6 +1978,8 @@ void StdBoxSelection::activated(int iMsg) if (!viewer->isSelecting()) { viewer->startSelection(View3DInventorViewer::Rubberband); viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), selectionCallback); + SoNode* root = viewer->getSceneGraph(); + static_cast(root)->selectionRole.setValue(FALSE); } } } From e811e0954577c673cb890bdd9b0f34f4f8dad845 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Thu, 4 Jul 2013 12:50:02 -0300 Subject: [PATCH 139/160] Draft: Small bugfix in wire tool --- src/Mod/Draft/Draft.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index d44414748..a9c2f1491 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -3177,7 +3177,10 @@ class _Wire(_DraftObject): w = DraftGeomUtils.filletWire(shape,fp.FilletRadius) if w: shape = w - shape = Part.Face(shape) + try: + shape = Part.Face(shape) + except: + pass else: edges = [] pts = fp.Points[1:] From 6fde5d764bec488b88d9c15eaf528067c0e51627 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 5 Jul 2013 15:29:04 +0200 Subject: [PATCH 140/160] + in setPyObject() only use classes derived from Base::Exception --- src/App/PropertyFile.cpp | 8 +-- src/App/PropertyGeo.cpp | 16 ++--- src/App/PropertyLinks.cpp | 12 ++-- src/App/PropertyStandard.cpp | 68 +++++++++---------- src/App/PropertyUnits.cpp | 4 +- src/Base/Exception.cpp | 68 +++++++++++++++++++ src/Base/Exception.h | 64 +++++++++++++++++ src/Mod/Fem/App/FemMeshProperty.cpp | 2 +- src/Mod/Mesh/App/MeshProperties.cpp | 4 +- src/Mod/Part/App/PropertyGeometryList.cpp | 4 +- src/Mod/Part/App/PropertyTopoShape.cpp | 2 +- src/Mod/Points/App/PropertyPointKernel.cpp | 2 +- src/Mod/Robot/App/PropertyTrajectory.cpp | 2 +- .../Sketcher/App/PropertyConstraintList.cpp | 4 +- 14 files changed, 196 insertions(+), 64 deletions(-) diff --git a/src/App/PropertyFile.cpp b/src/App/PropertyFile.cpp index 221ad82c3..5858d8e1e 100644 --- a/src/App/PropertyFile.cpp +++ b/src/App/PropertyFile.cpp @@ -260,7 +260,7 @@ void PropertyFileIncluded::setPyObject(PyObject *value) } else if (PyTuple_Check(value)) { if (PyTuple_Size(value) != 2) - throw Py::TypeError("Tuple needs size of (filePath,newFileName)"); + throw Base::TypeError("Tuple needs size of (filePath,newFileName)"); PyObject* file = PyTuple_GetItem(value,0); PyObject* name = PyTuple_GetItem(value,1); @@ -281,7 +281,7 @@ void PropertyFileIncluded::setPyObject(PyObject *value) else { std::string error = std::string("First item in tuple must be a file or string"); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } // decoding name @@ -296,7 +296,7 @@ void PropertyFileIncluded::setPyObject(PyObject *value) else { std::string error = std::string("Second item in tuple must be a string"); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } setValue(fileStr.c_str(),nameStr.c_str()); @@ -305,7 +305,7 @@ void PropertyFileIncluded::setPyObject(PyObject *value) else { std::string error = std::string("Type must be string or file"); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } // assign the string diff --git a/src/App/PropertyGeo.cpp b/src/App/PropertyGeo.cpp index 5a1adb114..47b718d67 100644 --- a/src/App/PropertyGeo.cpp +++ b/src/App/PropertyGeo.cpp @@ -117,7 +117,7 @@ void PropertyVector::setPyObject(PyObject *value) else if (PyInt_Check(item)) cVec.x = (float)PyInt_AsLong(item); else - throw Base::Exception("Not allowed type used in tuple (float expected)..."); + throw Base::TypeError("Not allowed type used in tuple (float expected)..."); // y item = PyTuple_GetItem(value,1); if (PyFloat_Check(item)) @@ -125,7 +125,7 @@ void PropertyVector::setPyObject(PyObject *value) else if (PyInt_Check(item)) cVec.y = (float)PyInt_AsLong(item); else - throw Base::Exception("Not allowed type used in tuple (float expected)..."); + throw Base::TypeError("Not allowed type used in tuple (float expected)..."); // z item = PyTuple_GetItem(value,2); if (PyFloat_Check(item)) @@ -133,13 +133,13 @@ void PropertyVector::setPyObject(PyObject *value) else if (PyInt_Check(item)) cVec.z = (float)PyInt_AsLong(item); else - throw Base::Exception("Not allowed type used in tuple (float expected)..."); + throw Base::TypeError("Not allowed type used in tuple (float expected)..."); setValue( cVec ); } else { std::string error = std::string("type must be 'Vector' or tuple of three floats, not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -271,7 +271,7 @@ void PropertyVectorList::setPyObject(PyObject *value) else { std::string error = std::string("type must be 'Vector' or list of 'Vector', not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -396,7 +396,7 @@ void PropertyMatrix::setPyObject(PyObject *value) else if (PyInt_Check(item)) cMatrix[x][y] = (double)PyInt_AsLong(item); else - throw Base::Exception("Not allowed type used in matrix tuple (a number expected)..."); + throw Base::TypeError("Not allowed type used in matrix tuple (a number expected)..."); } } @@ -405,7 +405,7 @@ void PropertyMatrix::setPyObject(PyObject *value) else { std::string error = std::string("type must be 'Matrix' or tuple of 16 float or int, not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -520,7 +520,7 @@ void PropertyPlacement::setPyObject(PyObject *value) else { std::string error = std::string("type must be 'Matrix' or 'Placement', not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } diff --git a/src/App/PropertyLinks.cpp b/src/App/PropertyLinks.cpp index bba19fcd1..7cc729aee 100644 --- a/src/App/PropertyLinks.cpp +++ b/src/App/PropertyLinks.cpp @@ -110,7 +110,7 @@ void PropertyLink::setPyObject(PyObject *value) else { std::string error = std::string("type must be 'DocumentObject' or 'NoneType', not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -257,7 +257,7 @@ void PropertyLinkSub::setPyObject(PyObject *value) else { std::string error = std::string("type of first element in tuple must be 'DocumentObject', not "); error += tup[0].ptr()->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } else if(Py_None == value) { @@ -266,7 +266,7 @@ void PropertyLinkSub::setPyObject(PyObject *value) else { std::string error = std::string("type must be 'DocumentObject', 'NoneType' or ('DocumentObject',['String',]) not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -409,7 +409,7 @@ void PropertyLinkList::setPyObject(PyObject *value) if (!PyObject_TypeCheck(*item, &(DocumentObjectPy::Type))) { std::string error = std::string("type in list must be 'DocumentObject', not "); error += (*item)->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } values[i] = static_cast(*item)->getDocumentObjectPtr(); @@ -424,7 +424,7 @@ void PropertyLinkList::setPyObject(PyObject *value) else { std::string error = std::string("type must be 'DocumentObject' or list of 'DocumentObject', not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -609,7 +609,7 @@ void PropertyLinkSubList::setPyObject(PyObject *value) else { std::string error = std::string("type must be 'DocumentObject' or list of 'DocumentObject', not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } diff --git a/src/App/PropertyStandard.cpp b/src/App/PropertyStandard.cpp index 4ec89060d..573538d6c 100644 --- a/src/App/PropertyStandard.cpp +++ b/src/App/PropertyStandard.cpp @@ -98,7 +98,7 @@ void PropertyInteger::setPyObject(PyObject *value) else { std::string error = std::string("type must be int, not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -211,7 +211,7 @@ void PropertyPath::setPyObject(PyObject *value) else { std::string error = std::string("type must be str or unicode, not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } // assign the path @@ -472,7 +472,7 @@ void PropertyEnumeration::setPyObject(PyObject *value) long i=0; while(*(plEnums++) != NULL)i++; if (val < 0 || i <= val) - throw Py::ValueError("Out of range"); + throw Base::ValueError("Out of range"); PropertyInteger::setValue(val); } } @@ -481,7 +481,7 @@ void PropertyEnumeration::setPyObject(PyObject *value) if (_EnumArray && isPartOf(str)) setValue(PyString_AsString (value)); else - throw Py::ValueError("not part of the enum"); + throw Base::ValueError("not part of the enum"); } else if (PyList_Check(value)) { Py_ssize_t nSize = PyList_Size(value); @@ -493,7 +493,7 @@ void PropertyEnumeration::setPyObject(PyObject *value) if (!PyString_Check(item)) { std::string error = std::string("type in list must be str, not "); error += item->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } values[i] = PyString_AsString(item); } @@ -505,7 +505,7 @@ void PropertyEnumeration::setPyObject(PyObject *value) else { std::string error = std::string("type must be int or str, not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -582,7 +582,7 @@ void PropertyIntegerConstraint::setPyObject(PyObject *value) else { std::string error = std::string("type must be int, not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -677,7 +677,7 @@ void PropertyIntegerList::setPyObject(PyObject *value) if (!PyInt_Check(item)) { std::string error = std::string("type in list must be int, not "); error += item->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } values[i] = PyInt_AsLong(item); } @@ -690,7 +690,7 @@ void PropertyIntegerList::setPyObject(PyObject *value) else { std::string error = std::string("type must be int or list of int, not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -805,7 +805,7 @@ void PropertyIntegerSet::setPyObject(PyObject *value) if (!PyInt_Check(item)) { std::string error = std::string("type in list must be int, not "); error += item->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } values.insert(PyInt_AsLong(item)); } @@ -818,7 +818,7 @@ void PropertyIntegerSet::setPyObject(PyObject *value) else { std::string error = std::string("type must be int or list of int, not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -928,7 +928,7 @@ void PropertyFloat::setPyObject(PyObject *value) else { std::string error = std::string("type must be float or int, not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -1022,7 +1022,7 @@ void PropertyFloatConstraint::setPyObject(PyObject *value) else { std::string error = std::string("type must be float, not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -1095,7 +1095,7 @@ void PropertyFloatList::setPyObject(PyObject *value) if (!PyFloat_Check(item)) { std::string error = std::string("type in list must be float, not "); error += item->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } values[i] = (float) PyFloat_AsDouble(item); @@ -1109,7 +1109,7 @@ void PropertyFloatList::setPyObject(PyObject *value) else { std::string error = std::string("type must be float or list of float, not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -1240,7 +1240,7 @@ void PropertyString::setPyObject(PyObject *value) else { std::string error = std::string("type must be str or unicode, not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } // assign the string @@ -1345,7 +1345,7 @@ void PropertyUUID::setPyObject(PyObject *value) else { std::string error = std::string("type must be a str, not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } try { @@ -1355,7 +1355,7 @@ void PropertyUUID::setPyObject(PyObject *value) setValue(uid); } catch (const std::exception& e) { - throw Py::RuntimeError(e.what()); + throw Base::RuntimeError(e.what()); } } @@ -1495,7 +1495,7 @@ void PropertyStringList::setPyObject(PyObject *value) else { std::string error = std::string("type in list must be str or unicode, not "); error += item->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -1507,7 +1507,7 @@ void PropertyStringList::setPyObject(PyObject *value) else { std::string error = std::string("type must be str or list of str, not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -1655,7 +1655,7 @@ void PropertyMap::setPyObject(PyObject *value) else { std::string error = std::string("type of the key need to be a string, not"); error += key->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } // check on the item: @@ -1671,7 +1671,7 @@ void PropertyMap::setPyObject(PyObject *value) else { std::string error = std::string("type in list must be string or unicode, not "); error += item->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -1680,7 +1680,7 @@ void PropertyMap::setPyObject(PyObject *value) else { std::string error = std::string("type must be a dict object"); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -1794,7 +1794,7 @@ void PropertyBool::setPyObject(PyObject *value) else { std::string error = std::string("type must be bool, not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -1906,17 +1906,17 @@ void PropertyColor::setPyObject(PyObject *value) if (PyFloat_Check(item)) cCol.r = (float)PyFloat_AsDouble(item); else - throw Base::Exception("Type in tuple must be float"); + throw Base::TypeError("Type in tuple must be float"); item = PyTuple_GetItem(value,1); if (PyFloat_Check(item)) cCol.g = (float)PyFloat_AsDouble(item); else - throw Base::Exception("Type in tuple must be float"); + throw Base::TypeError("Type in tuple must be float"); item = PyTuple_GetItem(value,2); if (PyFloat_Check(item)) cCol.b = (float)PyFloat_AsDouble(item); else - throw Base::Exception("Type in tuple must be float"); + throw Base::TypeError("Type in tuple must be float"); } else if (PyTuple_Check(value) && PyTuple_Size(value) == 4) { PyObject* item; @@ -1924,22 +1924,22 @@ void PropertyColor::setPyObject(PyObject *value) if (PyFloat_Check(item)) cCol.r = (float)PyFloat_AsDouble(item); else - throw Base::Exception("Type in tuple must be float"); + throw Base::TypeError("Type in tuple must be float"); item = PyTuple_GetItem(value,1); if (PyFloat_Check(item)) cCol.g = (float)PyFloat_AsDouble(item); else - throw Base::Exception("Type in tuple must be float"); + throw Base::TypeError("Type in tuple must be float"); item = PyTuple_GetItem(value,2); if (PyFloat_Check(item)) cCol.b = (float)PyFloat_AsDouble(item); else - throw Base::Exception("Type in tuple must be float"); + throw Base::TypeError("Type in tuple must be float"); item = PyTuple_GetItem(value,3); if (PyFloat_Check(item)) cCol.a = (float)PyFloat_AsDouble(item); else - throw Base::Exception("Type in tuple must be float"); + throw Base::TypeError("Type in tuple must be float"); } else if (PyLong_Check(value)) { cCol.setPackedValue(PyLong_AsUnsignedLong(value)); @@ -1947,7 +1947,7 @@ void PropertyColor::setPyObject(PyObject *value) else { std::string error = std::string("type must be int or tuple of float, not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } setValue( cCol ); @@ -2080,7 +2080,7 @@ void PropertyColorList::setPyObject(PyObject *value) else { std::string error = std::string("not allowed type, "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } @@ -2231,7 +2231,7 @@ void PropertyMaterial::setPyObject(PyObject *value) else { std::string error = std::string("type must be 'Material', not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } diff --git a/src/App/PropertyUnits.cpp b/src/App/PropertyUnits.cpp index fae1df405..e20f3e698 100644 --- a/src/App/PropertyUnits.cpp +++ b/src/App/PropertyUnits.cpp @@ -102,11 +102,11 @@ void PropertyLength::setPyObject(PyObject *value) else { std::string error = std::string("type must be float or int, not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } if (val < 0.0f) - throw Py::ValueError("value must be nonnegative"); + throw Base::ValueError("value must be nonnegative"); setValue(val); #endif diff --git a/src/Base/Exception.cpp b/src/Base/Exception.cpp index 4ca62890c..2d7b58c25 100644 --- a/src/Base/Exception.cpp +++ b/src/Base/Exception.cpp @@ -236,6 +236,74 @@ ProgramInformation::ProgramInformation(const ProgramInformation &inst) // --------------------------------------------------------- +TypeError::TypeError(const char * sMessage) + : Exception(sMessage) +{ +} + +TypeError::TypeError(const std::string& sMessage) + : Exception(sMessage) +{ +} + +TypeError::TypeError(const TypeError &inst) + : Exception(inst) +{ +} + +// --------------------------------------------------------- + +ValueError::ValueError(const char * sMessage) + : Exception(sMessage) +{ +} + +ValueError::ValueError(const std::string& sMessage) + : Exception(sMessage) +{ +} + +ValueError::ValueError(const ValueError &inst) + : Exception(inst) +{ +} + +// --------------------------------------------------------- + +AttributeError::AttributeError(const char * sMessage) + : Exception(sMessage) +{ +} + +AttributeError::AttributeError(const std::string& sMessage) + : Exception(sMessage) +{ +} + +AttributeError::AttributeError(const AttributeError &inst) + : Exception(inst) +{ +} + +// --------------------------------------------------------- + +RuntimeError::RuntimeError(const char * sMessage) + : Exception(sMessage) +{ +} + +RuntimeError::RuntimeError(const std::string& sMessage) + : Exception(sMessage) +{ +} + +RuntimeError::RuntimeError(const RuntimeError &inst) + : Exception(inst) +{ +} + +// --------------------------------------------------------- + #if defined(__GNUC__) && defined (FC_OS_LINUX) #include #include diff --git a/src/Base/Exception.h b/src/Base/Exception.h index d2c4a1ecd..391cc443d 100644 --- a/src/Base/Exception.h +++ b/src/Base/Exception.h @@ -206,6 +206,70 @@ public: virtual ~ProgramInformation() throw() {} }; +/** + * The TypeError can be used to indicate the usage of a wrong type. + * @author Werner Mayer + */ +class BaseExport TypeError : public Exception +{ +public: + /// Construction + TypeError(const char * sMessage); + TypeError(const std::string& sMessage); + /// Construction + TypeError(const TypeError &inst); + /// Destruction + virtual ~TypeError() throw() {} +}; + +/** + * The ValueError can be used to indicate the usage of a wrong value. + * @author Werner Mayer + */ +class BaseExport ValueError : public Exception +{ +public: + /// Construction + ValueError(const char * sMessage); + ValueError(const std::string& sMessage); + /// Construction + ValueError(const ValueError &inst); + /// Destruction + virtual ~ValueError() throw() {} +}; + +/** + * The AttributeError can be used to indicate the usage of a wrong value. + * @author Werner Mayer + */ +class BaseExport AttributeError : public Exception +{ +public: + /// Construction + AttributeError(const char * sMessage); + AttributeError(const std::string& sMessage); + /// Construction + AttributeError(const AttributeError &inst); + /// Destruction + virtual ~AttributeError() throw() {} +}; + +/** + * The RuntimeError can be used to indicate an unknown exception at runtime. + * @author Werner Mayer + */ +class BaseExport RuntimeError : public Exception +{ +public: + /// Construction + RuntimeError(const char * sMessage); + RuntimeError(const std::string& sMessage); + /// Construction + RuntimeError(const RuntimeError &inst); + /// Destruction + virtual ~RuntimeError() throw() {} +}; + inline void Exception::setMessage(const char * sMessage) { diff --git a/src/Mod/Fem/App/FemMeshProperty.cpp b/src/Mod/Fem/App/FemMeshProperty.cpp index 10e01fa9f..022337471 100755 --- a/src/Mod/Fem/App/FemMeshProperty.cpp +++ b/src/Mod/Fem/App/FemMeshProperty.cpp @@ -113,7 +113,7 @@ void PropertyFemMesh::setPyObject(PyObject *value) else { std::string error = std::string("type must be 'FemMesh', not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } diff --git a/src/Mod/Mesh/App/MeshProperties.cpp b/src/Mod/Mesh/App/MeshProperties.cpp index 9e68cae10..552cf54bf 100644 --- a/src/Mod/Mesh/App/MeshProperties.cpp +++ b/src/Mod/Mesh/App/MeshProperties.cpp @@ -261,7 +261,7 @@ PyObject* PropertyCurvatureList::getPyObject(void) void PropertyCurvatureList::setPyObject(PyObject *value) { - throw Py::AttributeError(std::string("This attribute is read-only")); + throw Base::AttributeError(std::string("This attribute is read-only")); } App::Property *PropertyCurvatureList::Copy(void) const @@ -430,7 +430,7 @@ void PropertyMeshKernel::setPyObject(PyObject *value) else { std::string error = std::string("type must be 'Mesh', not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } diff --git a/src/Mod/Part/App/PropertyGeometryList.cpp b/src/Mod/Part/App/PropertyGeometryList.cpp index 947b2a91e..bf0583276 100644 --- a/src/Mod/Part/App/PropertyGeometryList.cpp +++ b/src/Mod/Part/App/PropertyGeometryList.cpp @@ -123,7 +123,7 @@ void PropertyGeometryList::setPyObject(PyObject *value) if (!PyObject_TypeCheck(item, &(GeometryPy::Type))) { std::string error = std::string("types in list must be 'Geometry', not "); error += item->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } values[i] = static_cast(item)->getGeometryPtr(); @@ -138,7 +138,7 @@ void PropertyGeometryList::setPyObject(PyObject *value) else { std::string error = std::string("type must be 'Geometry' or list of 'Geometry', not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } diff --git a/src/Mod/Part/App/PropertyTopoShape.cpp b/src/Mod/Part/App/PropertyTopoShape.cpp index 718e7fee9..7fddf8b01 100644 --- a/src/Mod/Part/App/PropertyTopoShape.cpp +++ b/src/Mod/Part/App/PropertyTopoShape.cpp @@ -200,7 +200,7 @@ void PropertyPartShape::setPyObject(PyObject *value) else { std::string error = std::string("type must be 'Shape', not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } diff --git a/src/Mod/Points/App/PropertyPointKernel.cpp b/src/Mod/Points/App/PropertyPointKernel.cpp index f0dcf9498..9134efd8d 100644 --- a/src/Mod/Points/App/PropertyPointKernel.cpp +++ b/src/Mod/Points/App/PropertyPointKernel.cpp @@ -99,7 +99,7 @@ void PropertyPointKernel::setPyObject(PyObject *value) else { std::string error = std::string("type must be 'Points', not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } diff --git a/src/Mod/Robot/App/PropertyTrajectory.cpp b/src/Mod/Robot/App/PropertyTrajectory.cpp index 4b449c462..8116f24fe 100644 --- a/src/Mod/Robot/App/PropertyTrajectory.cpp +++ b/src/Mod/Robot/App/PropertyTrajectory.cpp @@ -106,7 +106,7 @@ void PropertyTrajectory::setPyObject(PyObject *value) else { std::string error = std::string("type must be 'Trajectory', not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } diff --git a/src/Mod/Sketcher/App/PropertyConstraintList.cpp b/src/Mod/Sketcher/App/PropertyConstraintList.cpp index 6638c0a6c..b5825809e 100644 --- a/src/Mod/Sketcher/App/PropertyConstraintList.cpp +++ b/src/Mod/Sketcher/App/PropertyConstraintList.cpp @@ -126,7 +126,7 @@ void PropertyConstraintList::setPyObject(PyObject *value) if (!PyObject_TypeCheck(item, &(ConstraintPy::Type))) { std::string error = std::string("types in list must be 'Constraint', not "); error += item->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } values[i] = static_cast(item)->getConstraintPtr(); @@ -141,7 +141,7 @@ void PropertyConstraintList::setPyObject(PyObject *value) else { std::string error = std::string("type must be 'Constraint' or list of 'Constraint', not "); error += value->ob_type->tp_name; - throw Py::TypeError(error); + throw Base::TypeError(error); } } From 249e806a316b6802ea0595ee852efd2c687fa563 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 5 Jul 2013 15:31:54 +0200 Subject: [PATCH 141/160] + playing in sandbox --- src/Mod/Sandbox/App/DocumentProtector.cpp | 24 ++++++++++++++++ src/Mod/Sandbox/App/DocumentProtector.h | 1 + src/Mod/Sandbox/App/DocumentProtectorPy.cpp | 31 +++++++++++++++++---- src/Mod/Sandbox/App/DocumentProtectorPy.h | 2 ++ 4 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/Mod/Sandbox/App/DocumentProtector.cpp b/src/Mod/Sandbox/App/DocumentProtector.cpp index a9da9bddc..36cf6042b 100644 --- a/src/Mod/Sandbox/App/DocumentProtector.cpp +++ b/src/Mod/Sandbox/App/DocumentProtector.cpp @@ -160,6 +160,25 @@ protected: const AbstractCallable& callable; }; +class CustomPurgeEvent : public AbstractCustomProtectorEvent +{ +public: + CustomPurgeEvent(App::DocumentObject* o) + : obj(o) + { + } + ~CustomPurgeEvent() + { + } + void execute() + { + obj->purgeTouched(); + } + +protected: + App::DocumentObject* obj; +}; + class DocumentReceiver : public QObject { public: @@ -324,3 +343,8 @@ void DocumentObjectProtector::execute(const AbstractCallable& call) DocumentReceiver::globalInstance()->postEventAndWait(new CustomCallableEvent(call)); } +void DocumentObjectProtector::purgeTouched() +{ + validate(); + DocumentReceiver::globalInstance()->postEventAndWait(new CustomPurgeEvent(obj)); +} diff --git a/src/Mod/Sandbox/App/DocumentProtector.h b/src/Mod/Sandbox/App/DocumentProtector.h index 6502c2642..c3ad49125 100644 --- a/src/Mod/Sandbox/App/DocumentProtector.h +++ b/src/Mod/Sandbox/App/DocumentProtector.h @@ -127,6 +127,7 @@ public: App::DocumentObject* getObject() const; bool setProperty(const std::string& name, const App::Property& p); void execute(const AbstractCallable&); + void purgeTouched(); private: void validate(); diff --git a/src/Mod/Sandbox/App/DocumentProtectorPy.cpp b/src/Mod/Sandbox/App/DocumentProtectorPy.cpp index 7110935fb..319849fb3 100644 --- a/src/Mod/Sandbox/App/DocumentProtectorPy.cpp +++ b/src/Mod/Sandbox/App/DocumentProtectorPy.cpp @@ -162,6 +162,8 @@ void DocumentObjectProtectorPy::init_type() behaviors().supportRepr(); behaviors().supportGetattr(); behaviors().supportSetattr(); + + add_varargs_method("purgeTouched",&DocumentObjectProtectorPy::purgeTouched,"purgeTouched()"); } DocumentObjectProtectorPy::DocumentObjectProtectorPy(App::DocumentObject *obj) @@ -179,6 +181,13 @@ DocumentObjectProtectorPy::~DocumentObjectProtectorPy() delete _dp; } +Py::Object DocumentObjectProtectorPy::getObject() const +{ + App::DocumentObject* obj = _dp->getObject(); + PyObject* py = obj->getPyObject(); + return Py::Object(py, true); +} + Py::Object DocumentObjectProtectorPy::repr() { std::string s; @@ -201,10 +210,11 @@ Py::Object DocumentObjectProtectorPy::getattr(const char * attr) App::DocumentObject* obj = _dp->getObject(); App::Property* prop = obj->getPropertyByName(attr); if (!prop) { - std::string s; - std::ostringstream s_out; - s_out << "No such attribute '" << attr << "'"; - throw Py::AttributeError(s_out.str()); + return Py::PythonExtension::getattr(attr); + //std::string s; + //std::ostringstream s_out; + //s_out << "No such attribute '" << attr << "'"; + //throw Py::AttributeError(s_out.str()); } return Py::asObject(prop->getPyObject()); @@ -231,7 +241,18 @@ int DocumentObjectProtectorPy::setattr(const char * attr, const Py::Object & val Base::PyGILStateRelease unlock; std::auto_ptr copy(static_cast (prop->getTypeId().createInstance())); - copy->setPyObject(value.ptr()); + if (PyObject_TypeCheck(value.ptr(), DocumentObjectProtectorPy::type_object())) { + copy->setPyObject(static_cast(value.ptr())->getObject().ptr()); + } + else { + copy->setPyObject(value.ptr()); + } return _dp->setProperty(attr, *copy) ? 0 : -1; } } + +Py::Object DocumentObjectProtectorPy::purgeTouched(const Py::Tuple&) +{ + _dp->purgeTouched(); + return Py::None(); +} diff --git a/src/Mod/Sandbox/App/DocumentProtectorPy.h b/src/Mod/Sandbox/App/DocumentProtectorPy.h index 318aac529..368057e53 100644 --- a/src/Mod/Sandbox/App/DocumentProtectorPy.h +++ b/src/Mod/Sandbox/App/DocumentProtectorPy.h @@ -72,7 +72,9 @@ public: Py::Object repr(); Py::Object getattr(const char *); + Py::Object getObject() const; int setattr(const char *, const Py::Object &); + Py::Object purgeTouched(const Py::Tuple&); private: DocumentObjectProtector* _dp; From 0883e885b3849016823dbb7f29ef401396605138 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Fri, 5 Jul 2013 11:50:05 -0300 Subject: [PATCH 142/160] Draft: Small fix in Draft Wires --- src/Mod/Draft/Draft.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index a9c2f1491..52722cfd8 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -315,6 +315,27 @@ def printShape(shape): else: for v in shape.Vertexes: print " ",v.Point + +def compareObjects(obj1,obj2): + "Prints the differences between 2 objects" + + if obj1.TypeId != obj2.TypeId: + print obj1.Name + " and " + obj2.Name + " are of different types" + elif getType(obj1) != getType(obj2): + print obj1.Name + " and " + obj2.Name + " are of different types" + else: + for p in obj1.PropertiesList: + if p in obj2.PropertiesList: + if p in ["Shape","Label"]: + pass + elif p == "Placement": + delta = str((obj1.Placement.Base.sub(obj2.Placement.Base)).Length) + print "Objects have different placements. Distance between the 2: " + delta + " units" + else: + if getattr(obj1,p) != getattr(obj2,p): + print "Property " + p + " has a different value" + else: + print "Property " + p + " doesn't exist in one of the objects" def formatObject(target,origin=None): ''' @@ -3107,7 +3128,7 @@ class _Wire(_DraftObject): def updateProps(self,fp): "sets the start and end properties" pl = FreeCAD.Placement(fp.Placement) - if len(fp.Points) == 2: + if len(fp.Points) >= 2: displayfpstart = pl.multVec(fp.Points[0]) displayfpend = pl.multVec(fp.Points[-1]) if fp.Start != displayfpstart: From 321938c1f506ee2d494dd5e6fbe474cb1be35e6e Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Fri, 5 Jul 2013 13:44:31 -0300 Subject: [PATCH 143/160] Draft: small fixes + added svg scaling capability to Draft.loadTexture() + late-loading of svg patterns + fixed warnings in Draft Drawing tool --- src/Mod/Draft/Draft.py | 45 ++++++++++++++++++++++++++++++++----- src/Mod/Draft/DraftGui.py | 1 - src/Mod/Draft/DraftTools.py | 12 +--------- 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 52722cfd8..84135bc7e 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -158,6 +158,8 @@ def getRealName(name): def getType(obj): "getType(object): returns the Draft type of the given object" import Part + if not obj: + return None if isinstance(obj,Part.Shape): return "Shape" if "Proxy" in obj.PropertiesList: @@ -404,13 +406,38 @@ def select(objs=None): for obj in objs: FreeCADGui.Selection.addSelection(obj) -def loadTexture(filename): - "loadTexture(filename): returns a SoSFImage from a file" +def loadSvgPatterns(): + "loads the default Draft SVG patterns and custom patters if available" + import importSVG + FreeCAD.svgpatterns = importSVG.getContents(Draft_rc.qt_resource_data,'pattern',True) + altpat = getParam("patternFile") + if os.path.isdir(altpat): + for f in os.listdir(altpat): + if f[-4:].upper() == ".SVG": + p = importSVG.getContents(altpat+os.sep+f,'pattern') + if p: + FreeCAD.svgpatterns.update(p) + +def loadTexture(filename,size=None): + """loadTexture(filename,[size]): returns a SoSFImage from a file. If size + is defined (an int or a tuple), and provided the input image is a png file, + it will be scaled to match the given size.""" if gui: from pivy import coin - from PyQt4 import QtGui + from PyQt4 import QtGui,QtSvg try: - p = QtGui.QImage(filename) + if size and (".svg" in filename.lower()): + # we need to resize + if isinstance(size,int): + size = (size,size) + svgr = QtSvg.QSvgRenderer(filename) + p = QtGui.QImage(size[0],size[1],QtGui.QImage.Format_ARGB32_Premultiplied) + pa = QtGui.QPainter() + pa.begin(p) + svgr.render(pa) + pa.end() + else: + p = QtGui.QImage(filename) size = coin.SbVec2s(p.width(), p.height()) buffersize = p.numBytes() numcomponents = int (buffersize / ( size[0] * size[1] )) @@ -442,6 +469,7 @@ def loadTexture(filename): img.setValue(size, numcomponents, bytes) except: + print "Draft: unable to load texture" return None else: return img @@ -1330,6 +1358,8 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct return Vector(lx,ly,0) def getPattern(pat): + if not hasattr(FreeCAD,"svgpatterns"): + loadSvgPatterns() if pat in FreeCAD.svgpatterns: return FreeCAD.svgpatterns[pat] return '' @@ -1383,8 +1413,11 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct svg += ';fill:' + fill + '"' svg += '/>\n' return svg + + if not obj: + pass - if getType(obj) == "Dimension": + elif getType(obj) == "Dimension": p1,p2,p3,p4,tbase,norm,rot = obj.ViewObject.Proxy.calcGeom(obj) dimText = getParam("dimPrecision") dimText = "%."+str(dimText)+"f" @@ -3322,6 +3355,8 @@ class _DrawingView(_DraftObject): obj.addProperty("App::PropertyLink","Source","Base","The linked object") obj.addProperty("App::PropertyEnumeration","FillStyle","Drawing View","Shape Fill Style") fills = ['shape color'] + if not hasattr(FreeCAD,"svgpatterns"): + loadSvgPatterns() for f in FreeCAD.svgpatterns.keys(): fills.append(f) obj.FillStyle = fills diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py index 0cf0c6776..ff4d9e0da 100644 --- a/src/Mod/Draft/DraftGui.py +++ b/src/Mod/Draft/DraftGui.py @@ -563,7 +563,6 @@ class DraftToolBar: def redraw(self): "utility function that is performed after each clicked point" - print "redrawing" self.checkLocal() def selectPlaneUi(self): diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index 7568c5dd9..fe67b50f9 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -29,7 +29,7 @@ __url__ = "http://free-cad.sourceforge.net" # Generic stuff #--------------------------------------------------------------------------- -import os, FreeCAD, FreeCADGui, WorkingPlane, math, re, importSVG, Draft, Draft_rc, DraftVecUtils +import os, FreeCAD, FreeCADGui, WorkingPlane, math, re, Draft, Draft_rc, DraftVecUtils from FreeCAD import Vector from DraftGui import todo,QtCore,QtGui from DraftSnap import * @@ -43,16 +43,6 @@ from pivy import coin # update the translation engine FreeCADGui.updateLocale() -# loads the fill patterns -FreeCAD.svgpatterns = importSVG.getContents(Draft_rc.qt_resource_data,'pattern',True) -altpat = Draft.getParam("patternFile") -if os.path.isdir(altpat): - for f in os.listdir(altpat): - if f[-4:].upper() == ".SVG": - p = importSVG.getContents(altpat+os.sep+f,'pattern') - if p: - FreeCAD.svgpatterns.update(p) - # sets the default working plane plane = WorkingPlane.plane() FreeCAD.DraftWorkingPlane = plane From 634830e639623de2381fd0165853b51bc13d7a51 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Fri, 5 Jul 2013 17:18:34 -0300 Subject: [PATCH 144/160] New splashscreen --- src/Gui/Icons/freecadsplash.png | Bin 148474 -> 156367 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/Gui/Icons/freecadsplash.png b/src/Gui/Icons/freecadsplash.png index a0e8ad13dd843711641790d227ab448ee244febb..f1d1ef587fd5e7e4fbdbfe33bde2a88534442cf9 100644 GIT binary patch literal 156367 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 Date: Fri, 5 Jul 2013 23:04:50 -0300 Subject: [PATCH 145/160] Draft: Enabling svg hatch patterns --- src/Mod/Draft/Draft.py | 9 +- src/Mod/Draft/Draft_rc.py | 259 +++++++++++--------- src/Mod/Draft/Resources/patterns/simple.svg | 98 +++++++- 3 files changed, 251 insertions(+), 115 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 84135bc7e..713027aa8 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -3060,10 +3060,15 @@ class _ViewProviderRectangle(_ViewProviderDraft): def onChanged(self, vp, prop): from pivy import coin + from PyQt4 import QtCore if prop == "TextureImage": r = vp.RootNode - if os.path.exists(vp.TextureImage): - im = loadTexture(vp.TextureImage) + i = QtCore.QFileInfo(vp.TextureImage) + if i.exists(): + size = None + if ":/patterns" in vp.TextureImage: + size = 128 + im = loadTexture(vp.TextureImage, size) if im: self.texture = coin.SoTexture2() self.texture.image = im diff --git a/src/Mod/Draft/Draft_rc.py b/src/Mod/Draft/Draft_rc.py index b521dbd33..b14e8bfac 100644 --- a/src/Mod/Draft/Draft_rc.py +++ b/src/Mod/Draft/Draft_rc.py @@ -2,8 +2,8 @@ # Resource object code # -# Created: Mon Apr 15 12:19:38 2013 -# by: The Resource Compiler for PyQt (Qt v4.8.1) +# Created: Fri Jul 5 22:03:19 2013 +# by: The Resource Compiler for PyQt (Qt v4.8.4) # # WARNING! All changes made in this file will be lost! @@ -92,31 +92,70 @@ qt_resource_data = "\ \x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x2f\x67\x3e\x0a\x20\x20\ \x20\x20\x3c\x2f\x70\x61\x74\x74\x65\x72\x6e\x3e\x0a\x20\x20\x3c\ \x2f\x64\x65\x66\x73\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\ -\x00\x00\x01\x61\ -\x3c\ -\x73\x76\x67\x3e\x0a\x20\x20\x3c\x64\x65\x66\x73\x3e\x0a\x20\x20\ -\x20\x20\x3c\x70\x61\x74\x74\x65\x72\x6e\x0a\x20\x20\x20\x20\x20\ -\x20\x20\x69\x64\x3d\x22\x73\x69\x6d\x70\x6c\x65\x22\x0a\x20\x20\ -\x20\x20\x20\x20\x20\x70\x61\x74\x74\x65\x72\x6e\x55\x6e\x69\x74\ -\x73\x3d\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\x4f\x6e\x55\x73\ -\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x3d\x22\x30\x22\x0a\ -\x20\x20\x20\x20\x20\x20\x20\x79\x3d\x22\x30\x22\x0a\x20\x20\x20\ -\x20\x20\x20\x20\x77\x69\x64\x74\x68\x3d\x22\x2e\x31\x22\x0a\x20\ -\x20\x20\x20\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x2e\x31\ -\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x67\x0a\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\x6c\x6c\ -\x3a\x6e\x6f\x6e\x65\x3b\x20\x73\x74\x72\x6f\x6b\x65\x3a\x23\x30\ -\x30\x30\x30\x30\x30\x3b\x20\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\ -\x64\x74\x68\x3a\x2e\x30\x30\x35\x22\x0a\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x69\x64\x3d\x22\x67\x33\x33\x37\x37\x22\x3e\x0a\x20\ -\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x4d\x30\x2c\x30\x20\ -\x6c\x2e\x31\x32\x2c\x2e\x31\x32\x22\x0a\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\x33\x33\x37\ -\x39\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x2f\x67\x3e\ -\x0a\x20\x20\x20\x20\x3c\x2f\x70\x61\x74\x74\x65\x72\x6e\x3e\x0a\ -\x20\x20\x3c\x2f\x64\x65\x66\x73\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\ -\ +\x00\x00\x03\xdc\ +\x00\ +\x00\x0d\x76\x78\x9c\xd5\x56\x4d\x8f\xe3\x36\x0c\xbd\xcf\xaf\x30\ +\x34\xc7\x4e\xfc\x99\x71\x6c\x37\xce\x5e\x06\x0b\xf4\x50\x14\xe8\ +\xee\xa0\x67\xc5\x52\x12\xed\xd8\x92\x21\x29\x5f\xfb\xeb\x4b\xd9\ +\x92\xed\xc4\x41\xd1\x5b\x3b\x06\x0c\x58\x8f\x4f\xa4\x1e\x49\x31\ +\x59\x7f\xb9\x34\xb5\x77\xa2\x52\x31\xc1\x4b\x14\xf9\x21\xf2\x28\ +\xaf\x04\x61\x7c\x5f\xa2\xf7\xef\x5f\x17\x19\xf2\x94\xc6\x9c\xe0\ +\x5a\x70\x5a\x22\x2e\xd0\x97\xcd\xd3\x5a\x9d\xf6\x4f\x9e\xe7\xc1\ +\x66\xae\x0a\x52\x95\xe8\xa0\x75\x5b\x04\x41\x7b\x94\xb5\x2f\xe4\ +\x3e\x20\x55\x40\x6b\xda\x50\xae\x55\x10\xf9\x51\x80\x46\x7a\x35\ +\xd2\x2b\x49\xb1\x66\x27\x5a\x89\xa6\x11\x5c\x75\x3b\xb9\x7a\x9e\ +\x90\x25\xd9\x0d\xec\xf3\xf9\xec\x9f\x93\x8e\x14\xe5\x79\x1e\x84\ +\x71\x10\xc7\x0b\x60\x2c\xd4\x95\x6b\x7c\x59\xdc\x6e\x85\x33\x3e\ +\xda\x1a\x87\x61\x18\x80\x6d\x64\xfe\x3b\x56\xa1\x20\x2b\x2d\xbc\ +\x03\xdd\x01\xbe\x12\x47\x59\xd1\x1d\xec\xa3\x3e\xa7\x3a\x78\xfb\ +\xfe\x36\x18\x17\xa1\x4f\x34\x99\xb8\x61\xfc\x43\x55\xb8\xa5\x37\ +\x51\x1d\xd8\x67\x00\x37\x54\xb5\xb8\xa2\x2a\x70\x78\xb7\x9f\x91\ +\x12\xc1\x91\xe2\x3c\x7b\xed\xd6\x93\xb2\x45\x3d\xc1\xb2\x8b\xc1\ +\x12\xfa\xcb\xcc\x4f\xfc\xc8\x93\x79\x96\xa5\x1d\xe9\xcc\x88\x3e\ +\x94\x28\x5d\x76\xab\x03\x65\xfb\x83\x1e\x96\xee\xd4\x05\x11\x95\ +\x39\x06\x04\x64\x4d\x5b\x53\xdf\xa4\x62\x03\x8c\x75\x43\x35\x26\ +\x58\x63\xc3\xee\x8f\xe4\x90\x38\xcf\x97\x1d\x07\x58\x50\x94\xe2\ +\xcf\xb7\xaf\xfd\x0a\xd6\x55\x55\xfc\x25\xe4\x87\x5d\xc2\x63\x08\ +\x78\x2b\x8e\x10\x1a\x6d\x06\x78\x4d\xaa\x02\xd2\xd8\x60\xbd\x61\ +\x0d\xde\x53\x53\x81\x5f\x20\x6d\xeb\x60\x34\xdc\x90\xf5\xb5\xa5\ +\xa3\xd3\xde\xad\xa4\x7d\x3d\x1e\x36\x25\xa9\x1a\x66\x36\x05\xdf\ +\x34\xab\xeb\xdf\x4c\x10\xe4\x05\x77\x4e\x99\xae\xe9\xa6\x8b\xd9\ +\x7f\x3a\x15\x81\x95\x61\x45\x06\x13\x95\xeb\xc0\xa5\xa1\x5b\x0d\ +\x79\x34\x49\x24\x27\x46\xcf\xbd\x8f\x16\xe2\x55\xa2\x16\xb2\x44\ +\xcf\xbb\xee\x41\xbd\x61\x2b\x24\xa1\xd2\x99\xd2\xee\xb9\x31\x09\ +\x68\x08\x38\x39\x14\xdb\xc2\x62\xfb\x83\x56\x5a\x8b\x9a\x4a\xcc\ +\x8d\xda\x28\xb4\x96\xbd\x84\x12\x3f\xc2\x8f\x8c\xd0\x47\x86\xa1\ +\x6f\xcc\xf1\x86\x40\x0f\xad\xea\x80\x89\x38\x97\x28\xbe\x37\x9e\ +\x19\x07\xc3\xc2\x76\x57\x94\xc7\xb3\xed\x96\xe1\x3a\x2e\x0a\x5f\ +\x57\x68\xec\xa2\x21\x51\xd0\x46\xce\xb9\x3a\x88\xb3\x11\x53\x22\ +\x2d\x8f\xf4\xde\xdf\x4f\x21\x1a\xe3\xc6\x8f\x96\xd9\x2a\x89\xee\ +\xcd\xd5\xa5\x44\x49\xe2\xaf\xd2\xd7\x3c\x4a\x66\x46\xd0\x17\x67\ +\xfe\x6a\x15\xa5\xf9\xcc\x68\x0f\x7a\x79\x90\x02\x6b\x7a\x94\x1d\ +\x6b\x6a\xf0\x85\x35\xec\x27\x25\x63\xa5\xc6\xa8\x47\x29\x61\x22\ +\x2e\x6a\x7c\xa5\x72\xbc\xcb\xb6\x9d\x06\x9a\x91\xec\x1a\xd2\xf4\ +\x6a\x89\x2e\x57\x83\x21\x07\x9a\x8c\x18\x00\x52\x95\x0e\x20\x6d\ +\x5a\x33\x34\xba\xc1\xfd\x3a\xa0\x27\xa6\xd8\xb6\xa6\x37\x19\x04\ +\x2e\xc7\x00\x92\x3b\x54\x71\xdc\x5a\xbe\xf1\x5e\x33\x0e\x37\x89\ +\xd7\xd7\x7b\x5a\x1f\x05\xd2\x93\xb5\x97\x7b\xf4\xda\xa3\xfd\x95\ +\x5a\x07\xf3\x7b\xd0\xe1\x84\xee\xd4\x58\x7a\xb3\x82\x44\xac\x5c\ +\x22\x5a\xac\x35\x95\x7c\xaa\xb6\x9f\x42\x43\x30\xcb\x78\xe7\x4c\ +\xc3\xf4\x3e\x2a\x2a\xbf\x99\x79\xf9\x07\x7f\x57\x23\x69\x52\x3f\ +\xcf\xbb\x4e\x17\xb6\x49\xfd\x68\x40\x5c\x53\x02\x34\xdc\xf6\xfd\ +\x38\x58\x94\xbe\x9a\x1c\xee\x60\x64\x14\x1c\x7e\x07\x7f\x05\x44\ +\x8a\x0f\x5a\x3c\x87\xdd\xe3\xd6\x7d\xfb\x17\x7e\x18\x8e\x15\xb0\ +\xe5\x4a\x92\xd5\x6a\x3a\xe9\x40\xc2\x61\x3a\xb9\x80\xf3\x7b\xf8\ +\x12\x7a\xb5\x1f\xc5\x2f\xf0\xa2\xa9\xd1\x78\x30\x1b\xc0\x49\x3e\ +\x19\x57\xeb\x60\xef\x46\x91\xcd\x48\x9f\x75\x93\xd0\xee\x6b\x0c\ +\x32\x53\x70\x27\xe0\xe6\xfc\x51\x7b\x71\x80\x69\x02\x68\xca\x62\ +\x7b\xd4\x7a\x8a\xfd\x10\x8c\x17\x30\x4a\xa9\x74\xa8\x9d\x1b\x85\ +\x4b\xaa\x11\xe4\xa5\x4b\x90\x14\xbe\xd8\x5f\x97\x51\x08\x74\x6e\ +\x36\xbb\x1d\x82\x43\x2c\x2d\xe4\x02\xee\xc9\x09\xeb\xa3\xa4\xa6\ +\x68\xb6\x95\xfe\x73\x29\xcb\xac\x93\xb2\xcc\xee\xa4\x24\x10\xf3\ +\x93\x49\x89\x52\xa8\x88\xa9\x4d\x94\xce\xc5\xcc\x26\xfb\xff\x5c\ +\x4c\x12\x77\x75\x49\xe2\xb9\x94\xe5\x27\x93\x02\x75\x31\x52\x1e\ +\x55\x25\xfd\x64\x52\xa0\xb9\x92\xd8\xd4\x66\x76\xf5\x41\xcc\x67\ +\xbb\xfa\x20\x66\x99\x99\x01\xf0\x40\xcc\xfc\x4f\xd4\x3f\x88\x59\ +\x9b\x3f\xb4\x9b\xa7\xbf\x01\x1e\x88\x0a\xce\ \x00\x00\x08\xd6\ \x3c\ \x73\x76\x67\x3e\x0a\x20\x20\x3c\x64\x65\x66\x73\x3e\x0a\x20\x20\ @@ -53402,92 +53441,92 @@ qt_resource_struct = "\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x38\x00\x00\x00\x21\ \x00\x00\x00\x38\x00\x02\x00\x00\x00\x05\x00\x00\x00\x1c\ \x00\x00\x00\x1a\x00\x02\x00\x00\x00\x17\x00\x00\x00\x05\ -\x00\x00\x01\xb4\x00\x01\x00\x00\x00\x01\x00\x04\x04\x86\ -\x00\x00\x03\x00\x00\x01\x00\x00\x00\x01\x00\x08\x8b\x49\ -\x00\x00\x02\xde\x00\x01\x00\x00\x00\x01\x00\x08\x4e\x5b\ -\x00\x00\x02\x68\x00\x01\x00\x00\x00\x01\x00\x06\x51\xa0\ -\x00\x00\x03\x3e\x00\x01\x00\x00\x00\x01\x00\x09\x06\x5d\ -\x00\x00\x01\x06\x00\x01\x00\x00\x00\x01\x00\x01\xad\x4d\ -\x00\x00\x01\x7c\x00\x01\x00\x00\x00\x01\x00\x02\xef\xc8\ -\x00\x00\x02\x4c\x00\x01\x00\x00\x00\x01\x00\x06\x14\x8d\ -\x00\x00\x02\x8a\x00\x00\x00\x00\x00\x01\x00\x06\x8d\x86\ -\x00\x00\x03\x5a\x00\x00\x00\x00\x00\x01\x00\x09\x43\x86\ -\x00\x00\x01\xd6\x00\x01\x00\x00\x00\x01\x00\x04\x42\x50\ -\x00\x00\x00\xea\x00\x00\x00\x00\x00\x01\x00\x00\xde\x04\ -\x00\x00\x01\x60\x00\x01\x00\x00\x00\x01\x00\x02\xb3\x61\ -\x00\x00\x02\x30\x00\x01\x00\x00\x00\x01\x00\x05\xd6\xb0\ -\x00\x00\x02\xc2\x00\x00\x00\x00\x00\x01\x00\x07\x9a\x58\ -\x00\x00\x03\x22\x00\x01\x00\x00\x00\x01\x00\x08\xc9\x30\ -\x00\x00\x02\xa6\x00\x01\x00\x00\x00\x01\x00\x07\x5c\xd3\ -\x00\x00\x00\xce\x00\x00\x00\x00\x00\x01\x00\x00\x0f\x03\ -\x00\x00\x01\x22\x00\x01\x00\x00\x00\x01\x00\x01\xe9\xa3\ -\x00\x00\x01\x98\x00\x00\x00\x00\x00\x01\x00\x03\x2f\x13\ -\x00\x00\x02\x14\x00\x00\x00\x00\x00\x01\x00\x05\x0b\x55\ -\x00\x00\x01\x3e\x00\x00\x00\x00\x00\x01\x00\x02\x28\xa2\ -\x00\x00\x01\xf2\x00\x00\x00\x00\x00\x01\x00\x04\x80\xc0\ +\x00\x00\x01\xb4\x00\x01\x00\x00\x00\x01\x00\x04\x07\x01\ +\x00\x00\x03\x00\x00\x01\x00\x00\x00\x01\x00\x08\x8d\xc4\ +\x00\x00\x02\xde\x00\x01\x00\x00\x00\x01\x00\x08\x50\xd6\ +\x00\x00\x02\x68\x00\x01\x00\x00\x00\x01\x00\x06\x54\x1b\ +\x00\x00\x03\x3e\x00\x01\x00\x00\x00\x01\x00\x09\x08\xd8\ +\x00\x00\x01\x06\x00\x01\x00\x00\x00\x01\x00\x01\xaf\xc8\ +\x00\x00\x01\x7c\x00\x01\x00\x00\x00\x01\x00\x02\xf2\x43\ +\x00\x00\x02\x4c\x00\x01\x00\x00\x00\x01\x00\x06\x17\x08\ +\x00\x00\x02\x8a\x00\x00\x00\x00\x00\x01\x00\x06\x90\x01\ +\x00\x00\x03\x5a\x00\x00\x00\x00\x00\x01\x00\x09\x46\x01\ +\x00\x00\x01\xd6\x00\x01\x00\x00\x00\x01\x00\x04\x44\xcb\ +\x00\x00\x00\xea\x00\x00\x00\x00\x00\x01\x00\x00\xe0\x7f\ +\x00\x00\x01\x60\x00\x01\x00\x00\x00\x01\x00\x02\xb5\xdc\ +\x00\x00\x02\x30\x00\x01\x00\x00\x00\x01\x00\x05\xd9\x2b\ +\x00\x00\x02\xc2\x00\x00\x00\x00\x00\x01\x00\x07\x9c\xd3\ +\x00\x00\x03\x22\x00\x01\x00\x00\x00\x01\x00\x08\xcb\xab\ +\x00\x00\x02\xa6\x00\x01\x00\x00\x00\x01\x00\x07\x5f\x4e\ +\x00\x00\x00\xce\x00\x00\x00\x00\x00\x01\x00\x00\x11\x7e\ +\x00\x00\x01\x22\x00\x01\x00\x00\x00\x01\x00\x01\xec\x1e\ +\x00\x00\x01\x98\x00\x00\x00\x00\x00\x01\x00\x03\x31\x8e\ +\x00\x00\x02\x14\x00\x00\x00\x00\x00\x01\x00\x05\x0d\xd0\ +\x00\x00\x01\x3e\x00\x00\x00\x00\x00\x01\x00\x02\x2b\x1d\ +\x00\x00\x01\xf2\x00\x00\x00\x00\x00\x01\x00\x04\x83\x3b\ \x00\x00\x00\x4e\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x01\x00\x00\x06\x29\ +\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x01\x00\x00\x08\xa4\ \x00\x00\x00\x64\x00\x00\x00\x00\x00\x01\x00\x00\x01\x64\ -\x00\x00\x00\x96\x00\x00\x00\x00\x00\x01\x00\x00\x04\xc4\ +\x00\x00\x00\x96\x00\x01\x00\x00\x00\x01\x00\x00\x04\xc4\ \x00\x00\x00\x7c\x00\x00\x00\x00\x00\x01\x00\x00\x03\x12\ -\x00\x00\x06\xce\x00\x01\x00\x00\x00\x01\x00\x0a\xf8\xb6\ -\x00\x00\x04\x7c\x00\x00\x00\x00\x00\x01\x00\x0a\x55\x9f\ -\x00\x00\x09\x34\x00\x01\x00\x00\x00\x01\x00\x0b\xcf\xac\ -\x00\x00\x0b\xc4\x00\x01\x00\x00\x00\x01\x00\x0c\xab\xb7\ -\x00\x00\x05\x86\x00\x01\x00\x00\x00\x01\x00\x0a\x95\x4a\ -\x00\x00\x07\x16\x00\x00\x00\x00\x00\x01\x00\x0b\x16\x00\ -\x00\x00\x08\x2a\x00\x01\x00\x00\x00\x01\x00\x0b\x7e\xae\ -\x00\x00\x0b\x26\x00\x01\x00\x00\x00\x01\x00\x0c\x82\x74\ -\x00\x00\x07\x8a\x00\x00\x00\x00\x00\x01\x00\x0b\x3f\xcf\ -\x00\x00\x09\xce\x00\x01\x00\x00\x00\x01\x00\x0c\x10\x4d\ -\x00\x00\x0c\x14\x00\x01\x00\x00\x00\x01\x00\x0c\xc7\xdb\ -\x00\x00\x04\xc2\x00\x01\x00\x00\x00\x01\x00\x0a\x6e\xc1\ -\x00\x00\x08\xdc\x00\x00\x00\x00\x00\x01\x00\x0b\xad\x52\ -\x00\x00\x08\x50\x00\x01\x00\x00\x00\x01\x00\x0b\x84\x72\ -\x00\x00\x06\xf0\x00\x00\x00\x00\x00\x01\x00\x0b\x03\x6a\ -\x00\x00\x04\xe6\x00\x01\x00\x00\x00\x01\x00\x0a\x74\x40\ -\x00\x00\x07\x5e\x00\x01\x00\x00\x00\x01\x00\x0b\x2e\xc5\ -\x00\x00\x04\x9e\x00\x01\x00\x00\x00\x01\x00\x0a\x64\x55\ -\x00\x00\x0b\x4e\x00\x00\x00\x00\x00\x01\x00\x0c\x8d\xe3\ -\x00\x00\x03\xfc\x00\x01\x00\x00\x00\x01\x00\x0a\x30\x0d\ -\x00\x00\x05\xd6\x00\x01\x00\x00\x00\x01\x00\x0a\xb0\x69\ -\x00\x00\x0a\xde\x00\x01\x00\x00\x00\x01\x00\x0c\x6b\x45\ -\x00\x00\x0b\x00\x00\x01\x00\x00\x00\x01\x00\x0c\x78\xe0\ -\x00\x00\x05\xb4\x00\x00\x00\x00\x00\x01\x00\x0a\x9e\x50\ -\x00\x00\x03\xca\x00\x01\x00\x00\x00\x01\x00\x0a\x28\x54\ -\x00\x00\x08\xba\x00\x01\x00\x00\x00\x01\x00\x0b\xa5\xfe\ -\x00\x00\x0a\x28\x00\x00\x00\x00\x00\x01\x00\x0c\x20\x95\ -\x00\x00\x06\x2a\x00\x01\x00\x00\x00\x01\x00\x0a\xc1\xd9\ -\x00\x00\x0a\x4c\x00\x00\x00\x00\x00\x01\x00\x0c\x37\x48\ -\x00\x00\x07\xe4\x00\x00\x00\x00\x00\x01\x00\x0b\x57\x82\ -\x00\x00\x05\x38\x00\x01\x00\x00\x00\x01\x00\x0a\x84\x40\ -\x00\x00\x0b\xe4\x00\x00\x00\x00\x00\x01\x00\x0c\xb6\x65\ -\x00\x00\x06\x84\x00\x00\x00\x00\x00\x01\x00\x0a\xd9\x18\ -\x00\x00\x04\x28\x00\x00\x00\x00\x00\x01\x00\x0a\x38\x14\ -\x00\x00\x0c\x44\x00\x00\x00\x00\x00\x01\x00\x0c\xd3\xb4\ -\x00\x00\x0a\x94\x00\x00\x00\x00\x00\x01\x00\x0c\x54\xcf\ -\x00\x00\x04\x4c\x00\x01\x00\x00\x00\x01\x00\x0a\x4d\x34\ -\x00\x00\x0a\xbc\x00\x01\x00\x00\x00\x01\x00\x0c\x63\xf6\ -\x00\x00\x09\x56\x00\x01\x00\x00\x00\x01\x00\x0b\xd8\x55\ -\x00\x00\x0b\x74\x00\x01\x00\x00\x00\x01\x00\x0c\x96\x70\ -\x00\x00\x06\xac\x00\x01\x00\x00\x00\x01\x00\x0a\xeb\x57\ -\x00\x00\x07\xbc\x00\x01\x00\x00\x00\x01\x00\x0b\x4d\xd1\ -\x00\x00\x09\xac\x00\x00\x00\x00\x00\x01\x00\x0b\xfb\xbc\ -\x00\x00\x05\x5c\x00\x01\x00\x00\x00\x01\x00\x0a\x8b\x09\ -\x00\x00\x08\x0a\x00\x00\x00\x00\x00\x01\x00\x0b\x69\x3a\ -\x00\x00\x06\x0a\x00\x01\x00\x00\x00\x01\x00\x0a\xbc\x5a\ -\x00\x00\x09\xf8\x00\x01\x00\x00\x00\x01\x00\x0c\x16\xc2\ -\x00\x00\x08\x92\x00\x01\x00\x00\x00\x01\x00\x0b\x9a\x8c\ -\x00\x00\x09\x0c\x00\x01\x00\x00\x00\x01\x00\x0b\xbf\xd6\ -\x00\x00\x0b\x9a\x00\x01\x00\x00\x00\x01\x00\x0c\xa1\x35\ -\x00\x00\x0a\x70\x00\x01\x00\x00\x00\x01\x00\x0c\x4a\x1f\ -\x00\x00\x05\x08\x00\x01\x00\x00\x00\x01\x00\x0a\x7c\x1e\ -\x00\x00\x08\x72\x00\x00\x00\x00\x00\x01\x00\x0b\x8a\xba\ -\x00\x00\x06\x58\x00\x00\x00\x00\x00\x01\x00\x0a\xc9\xbe\ -\x00\x00\x07\x3e\x00\x01\x00\x00\x00\x01\x00\x0b\x25\x51\ -\x00\x00\x09\x7a\x00\x00\x00\x00\x00\x01\x00\x0b\xdf\xa6\ -\x00\x00\x03\x76\x00\x01\x00\x00\x00\x01\x00\x0a\x0d\xd7\ -\x00\x00\x03\xa2\x00\x01\x00\x00\x00\x01\x00\x0a\x17\x90\ +\x00\x00\x06\xce\x00\x01\x00\x00\x00\x01\x00\x0a\xfb\x31\ +\x00\x00\x04\x7c\x00\x00\x00\x00\x00\x01\x00\x0a\x58\x1a\ +\x00\x00\x09\x34\x00\x01\x00\x00\x00\x01\x00\x0b\xd2\x27\ +\x00\x00\x0b\xc4\x00\x01\x00\x00\x00\x01\x00\x0c\xae\x32\ +\x00\x00\x05\x86\x00\x01\x00\x00\x00\x01\x00\x0a\x97\xc5\ +\x00\x00\x07\x16\x00\x00\x00\x00\x00\x01\x00\x0b\x18\x7b\ +\x00\x00\x08\x2a\x00\x01\x00\x00\x00\x01\x00\x0b\x81\x29\ +\x00\x00\x0b\x26\x00\x01\x00\x00\x00\x01\x00\x0c\x84\xef\ +\x00\x00\x07\x8a\x00\x00\x00\x00\x00\x01\x00\x0b\x42\x4a\ +\x00\x00\x09\xce\x00\x01\x00\x00\x00\x01\x00\x0c\x12\xc8\ +\x00\x00\x0c\x14\x00\x01\x00\x00\x00\x01\x00\x0c\xca\x56\ +\x00\x00\x04\xc2\x00\x01\x00\x00\x00\x01\x00\x0a\x71\x3c\ +\x00\x00\x08\xdc\x00\x00\x00\x00\x00\x01\x00\x0b\xaf\xcd\ +\x00\x00\x08\x50\x00\x01\x00\x00\x00\x01\x00\x0b\x86\xed\ +\x00\x00\x06\xf0\x00\x00\x00\x00\x00\x01\x00\x0b\x05\xe5\ +\x00\x00\x04\xe6\x00\x01\x00\x00\x00\x01\x00\x0a\x76\xbb\ +\x00\x00\x07\x5e\x00\x01\x00\x00\x00\x01\x00\x0b\x31\x40\ +\x00\x00\x04\x9e\x00\x01\x00\x00\x00\x01\x00\x0a\x66\xd0\ +\x00\x00\x0b\x4e\x00\x00\x00\x00\x00\x01\x00\x0c\x90\x5e\ +\x00\x00\x03\xfc\x00\x01\x00\x00\x00\x01\x00\x0a\x32\x88\ +\x00\x00\x05\xd6\x00\x01\x00\x00\x00\x01\x00\x0a\xb2\xe4\ +\x00\x00\x0a\xde\x00\x01\x00\x00\x00\x01\x00\x0c\x6d\xc0\ +\x00\x00\x0b\x00\x00\x01\x00\x00\x00\x01\x00\x0c\x7b\x5b\ +\x00\x00\x05\xb4\x00\x00\x00\x00\x00\x01\x00\x0a\xa0\xcb\ +\x00\x00\x03\xca\x00\x01\x00\x00\x00\x01\x00\x0a\x2a\xcf\ +\x00\x00\x08\xba\x00\x01\x00\x00\x00\x01\x00\x0b\xa8\x79\ +\x00\x00\x0a\x28\x00\x00\x00\x00\x00\x01\x00\x0c\x23\x10\ +\x00\x00\x06\x2a\x00\x01\x00\x00\x00\x01\x00\x0a\xc4\x54\ +\x00\x00\x0a\x4c\x00\x00\x00\x00\x00\x01\x00\x0c\x39\xc3\ +\x00\x00\x07\xe4\x00\x00\x00\x00\x00\x01\x00\x0b\x59\xfd\ +\x00\x00\x05\x38\x00\x01\x00\x00\x00\x01\x00\x0a\x86\xbb\ +\x00\x00\x0b\xe4\x00\x00\x00\x00\x00\x01\x00\x0c\xb8\xe0\ +\x00\x00\x06\x84\x00\x00\x00\x00\x00\x01\x00\x0a\xdb\x93\ +\x00\x00\x04\x28\x00\x00\x00\x00\x00\x01\x00\x0a\x3a\x8f\ +\x00\x00\x0c\x44\x00\x00\x00\x00\x00\x01\x00\x0c\xd6\x2f\ +\x00\x00\x0a\x94\x00\x00\x00\x00\x00\x01\x00\x0c\x57\x4a\ +\x00\x00\x04\x4c\x00\x01\x00\x00\x00\x01\x00\x0a\x4f\xaf\ +\x00\x00\x0a\xbc\x00\x01\x00\x00\x00\x01\x00\x0c\x66\x71\ +\x00\x00\x09\x56\x00\x01\x00\x00\x00\x01\x00\x0b\xda\xd0\ +\x00\x00\x0b\x74\x00\x01\x00\x00\x00\x01\x00\x0c\x98\xeb\ +\x00\x00\x06\xac\x00\x01\x00\x00\x00\x01\x00\x0a\xed\xd2\ +\x00\x00\x07\xbc\x00\x01\x00\x00\x00\x01\x00\x0b\x50\x4c\ +\x00\x00\x09\xac\x00\x00\x00\x00\x00\x01\x00\x0b\xfe\x37\ +\x00\x00\x05\x5c\x00\x01\x00\x00\x00\x01\x00\x0a\x8d\x84\ +\x00\x00\x08\x0a\x00\x00\x00\x00\x00\x01\x00\x0b\x6b\xb5\ +\x00\x00\x06\x0a\x00\x01\x00\x00\x00\x01\x00\x0a\xbe\xd5\ +\x00\x00\x09\xf8\x00\x01\x00\x00\x00\x01\x00\x0c\x19\x3d\ +\x00\x00\x08\x92\x00\x01\x00\x00\x00\x01\x00\x0b\x9d\x07\ +\x00\x00\x09\x0c\x00\x01\x00\x00\x00\x01\x00\x0b\xc2\x51\ +\x00\x00\x0b\x9a\x00\x01\x00\x00\x00\x01\x00\x0c\xa3\xb0\ +\x00\x00\x0a\x70\x00\x01\x00\x00\x00\x01\x00\x0c\x4c\x9a\ +\x00\x00\x05\x08\x00\x01\x00\x00\x00\x01\x00\x0a\x7e\x99\ +\x00\x00\x08\x72\x00\x00\x00\x00\x00\x01\x00\x0b\x8d\x35\ +\x00\x00\x06\x58\x00\x00\x00\x00\x00\x01\x00\x0a\xcc\x39\ +\x00\x00\x07\x3e\x00\x01\x00\x00\x00\x01\x00\x0b\x27\xcc\ +\x00\x00\x09\x7a\x00\x00\x00\x00\x00\x01\x00\x0b\xe2\x21\ +\x00\x00\x03\x76\x00\x01\x00\x00\x00\x01\x00\x0a\x10\x52\ +\x00\x00\x03\xa2\x00\x01\x00\x00\x00\x01\x00\x0a\x1a\x0b\ " def qInitResources(): diff --git a/src/Mod/Draft/Resources/patterns/simple.svg b/src/Mod/Draft/Resources/patterns/simple.svg index ef756426d..07b0da6af 100644 --- a/src/Mod/Draft/Resources/patterns/simple.svg +++ b/src/Mod/Draft/Resources/patterns/simple.svg @@ -1,5 +1,62 @@ - - + + + + + + image/svg+xml + + + + + + + + + - \ No newline at end of file + + + + + + + + From b9fb862c661169b81a3b4e95e003b6882cbd21da Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 6 Jul 2013 15:02:52 +0200 Subject: [PATCH 146/160] + Reduce redundant code in mesh classes --- src/Mod/Mesh/App/Mesh.cpp | 35 ++---------- src/Mod/Mesh/App/Mesh.h | 9 +++- src/Mod/Mesh/App/MeshPyImp.cpp | 32 ++++++++++- src/Mod/Mesh/Gui/MeshSelection.cpp | 7 ++- src/Mod/Mesh/Gui/ViewProvider.cpp | 85 ++++++++---------------------- src/Mod/Mesh/Gui/ViewProvider.h | 10 ++-- 6 files changed, 77 insertions(+), 101 deletions(-) diff --git a/src/Mod/Mesh/App/Mesh.cpp b/src/Mod/Mesh/App/Mesh.cpp index fb5084b64..11fd04fd2 100644 --- a/src/Mod/Mesh/App/Mesh.cpp +++ b/src/Mod/Mesh/App/Mesh.cpp @@ -832,23 +832,9 @@ void MeshObject::crossSections(const std::vector& planes, st } } -void MeshObject::cut(const std::vector& polygon, MeshObject::CutType type) +void MeshObject::cut(const Base::Polygon2D& polygon2d, + const Base::ViewProjMethod& proj, MeshObject::CutType type) { - MeshCore::FlatTriangulator tria; - tria.SetPolygon(polygon); - // this gives us the inverse matrix - Base::Matrix4D inv = tria.GetTransformToFitPlane(); - // compute the matrix for the coordinate transformation - Base::Matrix4D mat = inv; - mat.inverseOrthogonal(); - - std::vector poly = tria.ProjectToFitPlane(); - - Base::ViewProjMatrix proj(mat); - Base::Polygon2D polygon2d; - for (std::vector::const_iterator it = poly.begin(); it != poly.end(); ++it) - polygon2d.Add(Base::Vector2D(it->x, it->y)); - MeshCore::MeshAlgorithm meshAlg(this->_kernel); std::vector check; @@ -868,22 +854,9 @@ void MeshObject::cut(const std::vector& polygon, MeshObject::Cut this->deleteFacets(check); } -void MeshObject::trim(const std::vector& polygon, MeshObject::CutType type) +void MeshObject::trim(const Base::Polygon2D& polygon2d, + const Base::ViewProjMethod& proj, MeshObject::CutType type) { - MeshCore::FlatTriangulator tria; - tria.SetPolygon(polygon); - // this gives us the inverse matrix - Base::Matrix4D inv = tria.GetTransformToFitPlane(); - // compute the matrix for the coordinate transformation - Base::Matrix4D mat = inv; - mat.inverseOrthogonal(); - - std::vector poly = tria.ProjectToFitPlane(); - - Base::ViewProjMatrix proj(mat); - Base::Polygon2D polygon2d; - for (std::vector::const_iterator it = poly.begin(); it != poly.end(); ++it) - polygon2d.Add(Base::Vector2D(it->x, it->y)); MeshCore::MeshTrimming trim(this->_kernel, &proj, polygon2d); std::vector check; std::vector triangle; diff --git a/src/Mod/Mesh/App/Mesh.h b/src/Mod/Mesh/App/Mesh.h index a88a06ec3..18a883d2c 100644 --- a/src/Mod/Mesh/App/Mesh.h +++ b/src/Mod/Mesh/App/Mesh.h @@ -49,6 +49,11 @@ namespace Py { class List; } +namespace Base { + class Polygon2D; + class ViewProjMethod; +} + namespace MeshCore { class AbstractPolygonTriangulator; } @@ -200,8 +205,8 @@ public: Base::Vector3d getPointNormal(unsigned long) const; void crossSections(const std::vector&, std::vector §ions, float fMinEps = 1.0e-2f, bool bConnectPolygons = false) const; - void cut(const std::vector& polygon, CutType); - void trim(const std::vector& polygon, CutType); + void cut(const Base::Polygon2D& polygon, const Base::ViewProjMethod& proj, CutType); + void trim(const Base::Polygon2D& polygon, const Base::ViewProjMethod& proj, CutType); //@} /** @name Selection */ diff --git a/src/Mod/Mesh/App/MeshPyImp.cpp b/src/Mod/Mesh/App/MeshPyImp.cpp index c25c6322b..158ef0d43 100644 --- a/src/Mod/Mesh/App/MeshPyImp.cpp +++ b/src/Mod/Mesh/App/MeshPyImp.cpp @@ -1295,7 +1295,21 @@ PyObject* MeshPy::cut(PyObject *args) polygon.push_back(Base::convertTo(pnt)); } - getMeshObjectPtr()->cut(polygon, MeshObject::CutType(mode)); + MeshCore::FlatTriangulator tria; + tria.SetPolygon(polygon); + // this gives us the inverse matrix + Base::Matrix4D inv = tria.GetTransformToFitPlane(); + // compute the matrix for the coordinate transformation + Base::Matrix4D mat = inv; + mat.inverseOrthogonal(); + + polygon = tria.ProjectToFitPlane(); + + Base::ViewProjMatrix proj(mat); + Base::Polygon2D polygon2d; + for (std::vector::const_iterator it = polygon.begin(); it != polygon.end(); ++it) + polygon2d.Add(Base::Vector2D(it->x, it->y)); + getMeshObjectPtr()->cut(polygon2d, proj, MeshObject::CutType(mode)); Py_Return; } @@ -1315,7 +1329,21 @@ PyObject* MeshPy::trim(PyObject *args) polygon.push_back(Base::convertTo(pnt)); } - getMeshObjectPtr()->trim(polygon, MeshObject::CutType(mode)); + MeshCore::FlatTriangulator tria; + tria.SetPolygon(polygon); + // this gives us the inverse matrix + Base::Matrix4D inv = tria.GetTransformToFitPlane(); + // compute the matrix for the coordinate transformation + Base::Matrix4D mat = inv; + mat.inverseOrthogonal(); + + polygon = tria.ProjectToFitPlane(); + + Base::ViewProjMatrix proj(mat); + Base::Polygon2D polygon2d; + for (std::vector::const_iterator it = polygon.begin(); it != polygon.end(); ++it) + polygon2d.Add(Base::Vector2D(it->x, it->y)); + getMeshObjectPtr()->trim(polygon2d, proj, MeshObject::CutType(mode)); Py_Return; } diff --git a/src/Mod/Mesh/Gui/MeshSelection.cpp b/src/Mod/Mesh/Gui/MeshSelection.cpp index a724f96ce..f04272801 100644 --- a/src/Mod/Mesh/Gui/MeshSelection.cpp +++ b/src/Mod/Mesh/Gui/MeshSelection.cpp @@ -29,6 +29,7 @@ # include # include # include +# include #endif #include "MeshSelection.h" @@ -42,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -372,7 +374,10 @@ void MeshSelection::selectGLCallback(void * ud, SoEventCallback * n) const MeshCore::MeshKernel& kernel = mesh.getKernel(); // simply get all triangles under the polygon - vp->getFacetsFromPolygon(polygon, *view, true, faces); + SoCamera* cam = view->getCamera(); + SbViewVolume vv = cam->getViewVolume(); + Gui::ViewVolumeProjection proj(vv); + vp->getFacetsFromPolygon(polygon, proj, true, faces); if (self->onlyVisibleTriangles) { const SbVec2s& sz = view->getViewportRegion().getWindowSize(); short width,height; sz.getValue(width,height); diff --git a/src/Mod/Mesh/Gui/ViewProvider.cpp b/src/Mod/Mesh/Gui/ViewProvider.cpp index 5bd84aaa6..21c5da129 100644 --- a/src/Mod/Mesh/Gui/ViewProvider.cpp +++ b/src/Mod/Mesh/Gui/ViewProvider.cpp @@ -674,10 +674,13 @@ void ViewProviderMesh::clipMeshCallback(void * ud, SoEventCallback * n) if (!views.empty()) { Gui::Application::Instance->activeDocument()->openCommand("Cut"); for (std::vector::iterator it = views.begin(); it != views.end(); ++it) { - ViewProviderMesh* that = static_cast(*it); - if (that->getEditingMode() > -1) { - that->finishEditing(); - that->cutMesh(clPoly, *view, clip_inner); + ViewProviderMesh* self = static_cast(*it); + if (self->getEditingMode() > -1) { + self->finishEditing(); + SoCamera* cam = view->getCamera(); + SbViewVolume vv = cam->getViewVolume(); + Gui::ViewVolumeProjection proj(vv); + self->cutMesh(clPoly, proj, clip_inner); } } @@ -709,10 +712,13 @@ void ViewProviderMesh::trimMeshCallback(void * ud, SoEventCallback * n) if (!views.empty()) { Gui::Application::Instance->activeDocument()->openCommand("Cut"); for (std::vector::iterator it = views.begin(); it != views.end(); ++it) { - ViewProviderMesh* that = static_cast(*it); - if (that->getEditingMode() > -1) { - that->finishEditing(); - that->trimMesh(clPoly, *view, clip_inner); + ViewProviderMesh* self = static_cast(*it); + if (self->getEditingMode() > -1) { + self->finishEditing(); + SoCamera* cam = view->getCamera(); + SbViewVolume vv = cam->getViewVolume(); + Gui::ViewVolumeProjection proj(vv); + self->trimMesh(clPoly, proj, clip_inner); } } @@ -889,15 +895,12 @@ void ViewProviderMesh::selectGLCallback(void * ud, SoEventCallback * n) } void ViewProviderMesh::getFacetsFromPolygon(const std::vector& picked, - Gui::View3DInventorViewer &Viewer, + const Base::ViewProjMethod& proj, SbBool inner, std::vector& indices) const { #if 1 bool ok = true; - SoCamera* cam = Viewer.getCamera(); - SbViewVolume vv = cam->getViewVolume(); - Gui::ViewVolumeProjection proj(vv); Base::Polygon2D polygon; for (std::vector::const_iterator it = picked.begin(); it != picked.end(); ++it) polygon.Add(Base::Vector2D((*it)[0],(*it)[1])); @@ -1115,69 +1118,27 @@ std::vector ViewProviderMesh::getVisibleFacets(const SbViewportRe } void ViewProviderMesh::cutMesh(const std::vector& picked, - Gui::View3DInventorViewer &Viewer, SbBool inner) + const Base::ViewProjMethod& proj, SbBool inner) { // Get the facet indices inside the tool mesh std::vector indices; - getFacetsFromPolygon(picked, Viewer, inner, indices); + getFacetsFromPolygon(picked, proj, inner, indices); removeFacets(indices); } void ViewProviderMesh::trimMesh(const std::vector& polygon, - Gui::View3DInventorViewer& viewer, SbBool inner) + const Base::ViewProjMethod& proj, SbBool inner) { - // get the drawing plane - SbViewVolume vol = viewer.getCamera()->getViewVolume(); - SbPlane drawPlane = vol.getPlane(viewer.getCamera()->focalDistance.getValue()); - - std::vector indices; Mesh::MeshObject* mesh = static_cast(pcObject)->Mesh.startEditing(); - MeshCore::MeshFacetGrid meshGrid(mesh->getKernel()); - MeshCore::MeshAlgorithm meshAlg(mesh->getKernel()); -#if 0 - for (std::vector::const_iterator it = polygon.begin(); it != polygon.end(); ++it) { - // the following element - std::vector::const_iterator nt = it + 1; - if (nt == polygon.end()) - break; - else if (*it == *nt) - continue; // two adjacent vertices are equal - - SbVec3f p1,p2; - SbLine l1, l2; - vol.projectPointToLine(*it, l1); - drawPlane.intersect(l1, p1); - vol.projectPointToLine(*nt, l2); - drawPlane.intersect(l2, p2); - - SbPlane plane(l1.getPosition(), l2.getPosition(), - l1.getPosition()+l1.getDirection()); - const SbVec3f& n = plane.getNormal(); - float d = plane.getDistanceFromOrigin(); - meshAlg.GetFacetsFromPlane(meshGrid, - Base::Vector3f(n[0],n[1],n[2]), d, - Base::Vector3f(p1[0],p1[1],p1[2]), - Base::Vector3f(p2[0],p2[1],p2[2]), indices); - } -#endif - - Gui::ViewVolumeProjection proj(vol); Base::Polygon2D polygon2d; for (std::vector::const_iterator it = polygon.begin(); it != polygon.end(); ++it) polygon2d.Add(Base::Vector2D((*it)[0],(*it)[1])); - MeshCore::MeshTrimming trim(mesh->getKernel(), &proj, polygon2d); - std::vector check; - std::vector triangle; - trim.SetInnerOrOuter(inner ? MeshCore::MeshTrimming::INNER : MeshCore::MeshTrimming::OUTER); - trim.CheckFacets(meshGrid, check); - trim.TrimFacets(check, triangle); - mesh->deleteFacets(check); - if (!triangle.empty()) { - mesh->getKernel().AddFacets(triangle); - } - //Remove the facets from the mesh and open a transaction object for the undo/redo stuff - //mesh->deleteFacets(indices); + + Mesh::MeshObject::CutType type = inner ? + Mesh::MeshObject::INNER : + Mesh::MeshObject::OUTER; + mesh->trim(polygon2d, proj, type); static_cast(pcObject)->Mesh.finishEditing(); pcObject->purgeTouched(); } diff --git a/src/Mod/Mesh/Gui/ViewProvider.h b/src/Mod/Mesh/Gui/ViewProvider.h index 29b98065a..79648b1b9 100644 --- a/src/Mod/Mesh/Gui/ViewProvider.h +++ b/src/Mod/Mesh/Gui/ViewProvider.h @@ -52,6 +52,10 @@ namespace App { class Color; } +namespace Base { + class ViewProjMethod; +} + namespace Gui { class View3DInventorViewer; class SoFCSelection; @@ -139,7 +143,7 @@ public: void clearSelection(); void deleteSelection(); void getFacetsFromPolygon(const std::vector& picked, - Gui::View3DInventorViewer &Viewer, SbBool inner, + const Base::ViewProjMethod& proj, SbBool inner, std::vector& indices) const; std::vector getFacetsOfRegion(const SbViewportRegion&, const SbViewportRegion&, SoCamera*) const; std::vector getVisibleFacetsAfterZoom(const SbBox2s&, const SbViewportRegion&, SoCamera*) const; @@ -156,8 +160,8 @@ protected: void onChanged(const App::Property* prop); virtual void showOpenEdges(bool); void setOpenEdgeColorFrom(const App::Color& col); - virtual void cutMesh(const std::vector& picked, Gui::View3DInventorViewer &Viewer, SbBool inner); - virtual void trimMesh(const std::vector& picked, Gui::View3DInventorViewer &Viewer, SbBool inner); + virtual void cutMesh(const std::vector& picked, const Base::ViewProjMethod& proj, SbBool inner); + virtual void trimMesh(const std::vector& picked, const Base::ViewProjMethod& proj, SbBool inner); virtual void splitMesh(const MeshCore::MeshKernel& toolMesh, const Base::Vector3f& normal, SbBool inner); virtual void segmentMesh(const MeshCore::MeshKernel& toolMesh, const Base::Vector3f& normal, SbBool inner); virtual void faceInfo(unsigned long facet); From 4afa0138cc9cee048a1cb3acaf9ff2ad50d6605e Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 6 Jul 2013 15:03:28 +0200 Subject: [PATCH 147/160] 0001162: Cut mesh with plane --- src/Mod/Mesh/Gui/Command.cpp | 89 ++++++++++++++++++++++++++++++++++ src/Mod/Mesh/Gui/Workbench.cpp | 2 +- 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/Mod/Mesh/Gui/Command.cpp b/src/Mod/Mesh/Gui/Command.cpp index 2e71e4ed9..4c32b1e07 100644 --- a/src/Mod/Mesh/Gui/Command.cpp +++ b/src/Mod/Mesh/Gui/Command.cpp @@ -800,6 +800,94 @@ bool CmdMeshPolyTrim::isActive(void) //-------------------------------------------------------------------------------------- +DEF_STD_CMD_A(CmdMeshTrimByPlane); + +CmdMeshTrimByPlane::CmdMeshTrimByPlane() + : Command("Mesh_TrimByPlane") +{ + sAppModule = "Mesh"; + sGroup = QT_TR_NOOP("Mesh"); + sMenuText = QT_TR_NOOP("Trim mesh with a plane"); + sToolTipText = QT_TR_NOOP("Trims a mesh with a plane"); + sStatusTip = QT_TR_NOOP("Trims a mesh with a plane"); +} + +void CmdMeshTrimByPlane::activated(int iMsg) +{ + Base::Type partType = Base::Type::fromName("Part::Plane"); + std::vector plane = getSelection().getObjectsOfType(partType); + if (plane.empty()) { + QMessageBox::warning(Gui::getMainWindow(), + qApp->translate("Mesh_TrimByPlane", "Select plane"), + qApp->translate("Mesh_TrimByPlane", "Please select a plane at which you trim the mesh.")); + return; + } + + Base::Placement plm = static_cast(plane.front())->Placement.getValue(); + Base::Vector3d normal(0,0,1); + plm.getRotation().multVec(normal, normal); + Base::Vector3d view; + if (normal == Base::Vector3d(0,0,1)) { + view.Set(0,1,0); + } + else { + Base::Vector3d dir(0,0,1); + view = normal % dir; + } + + Base::Vector3d base = plm.getPosition(); + Base::Vector3d up = normal % view; + + Base::Rotation rot(Base::Vector3d(0,0,1), view); + Base::Matrix4D mat; + rot.getValue(mat); + Base::ViewProjMatrix proj(mat); + + openCommand("Trim with plane"); + std::vector docObj = Gui::Selection().getObjectsOfType(Mesh::Feature::getClassTypeId()); + for (std::vector::iterator it = docObj.begin(); it != docObj.end(); ++it) { + Mesh::MeshObject* mesh = static_cast(*it)->Mesh.startEditing(); + Base::BoundBox3d bbox = mesh->getBoundBox(); + double len = bbox.CalcDiagonalLength(); + // project center of bbox onto plane and use this as base point + Base::Vector3d cnt = bbox.CalcCenter(); + double dist = (cnt-base)*normal; + base = cnt - normal * dist; + + Base::Vector3d p1 = base + up * len; + Base::Vector3d p2 = base - up * len; + Base::Vector3d p3 = p2 + normal * len; + Base::Vector3d p4 = p1 + normal * len; + p1 = mat * p1; + p2 = mat * p2; + p3 = mat * p3; + p4 = mat * p4; + + Base::Polygon2D polygon2d; + polygon2d.Add(Base::Vector2D(p1.x, p1.y)); + polygon2d.Add(Base::Vector2D(p2.x, p2.y)); + polygon2d.Add(Base::Vector2D(p3.x, p3.y)); + polygon2d.Add(Base::Vector2D(p4.x, p4.y)); + + Mesh::MeshObject::CutType type = Mesh::MeshObject::INNER; + mesh->trim(polygon2d, proj, type); + static_cast(*it)->Mesh.finishEditing(); + (*it)->purgeTouched(); + } + commitCommand(); +} + +bool CmdMeshTrimByPlane::isActive(void) +{ + // Check for the selected mesh feature (all Mesh types) + if (getSelection().countObjectsOfType(Mesh::Feature::getClassTypeId()) != 1) + return false; + + return true; +} + +//-------------------------------------------------------------------------------------- + DEF_STD_CMD_A(CmdMeshPolySplit); CmdMeshPolySplit::CmdMeshPolySplit() @@ -1437,6 +1525,7 @@ void CreateMeshCommands(void) rcCmdMgr.addCommand(new CmdMeshPolyCut()); rcCmdMgr.addCommand(new CmdMeshPolySplit()); rcCmdMgr.addCommand(new CmdMeshPolyTrim()); + rcCmdMgr.addCommand(new CmdMeshTrimByPlane()); rcCmdMgr.addCommand(new CmdMeshToolMesh()); rcCmdMgr.addCommand(new CmdMeshTransform()); rcCmdMgr.addCommand(new CmdMeshEvaluation()); diff --git a/src/Mod/Mesh/Gui/Workbench.cpp b/src/Mod/Mesh/Gui/Workbench.cpp index 25b9bd656..b5005b98d 100644 --- a/src/Mod/Mesh/Gui/Workbench.cpp +++ b/src/Mod/Mesh/Gui/Workbench.cpp @@ -190,7 +190,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Mesh_FillupHoles" << "Mesh_FillInteractiveHole" << "Mesh_RemoveComponents" << "Mesh_RemoveCompByHand" << "Mesh_AddFacet" << "Mesh_Smoothing" << "Separator" << "Mesh_BuildRegularSolid" << boolean << "Separator" << "Mesh_PolySelect" << "Mesh_PolyCut" - << "Mesh_PolySplit" << "Mesh_PolySegm" << "Mesh_PolyTrim" << "Mesh_Segmentation" + << "Mesh_PolySplit" << "Mesh_PolySegm" << "Mesh_PolyTrim" << "Mesh_TrimByPlane" << "Mesh_Segmentation" << "Mesh_VertexCurvature"; return root; } From efa27db67a6e5291249dcafc3a974f9ea63a0f01 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 6 Jul 2013 15:49:20 +0200 Subject: [PATCH 148/160] 0001161: Merged Project object being imported changes size when moved --- src/Gui/MergeDocuments.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Gui/MergeDocuments.cpp b/src/Gui/MergeDocuments.cpp index 9b53d960c..fe1cbbd98 100644 --- a/src/Gui/MergeDocuments.cpp +++ b/src/Gui/MergeDocuments.cpp @@ -69,7 +69,7 @@ protected: if (!propertyStack.empty()) { // replace the stored object name with the real one - if (LocalName == "Link" || (LocalName == "String" && propertyStack.top().first == "Label")) { + if (LocalName == "Link" || LocalName == "LinkSub" || (LocalName == "String" && propertyStack.top().first == "Label")) { for (std::map::iterator it = AttrMap.begin(); it != AttrMap.end(); ++it) { std::map::const_iterator jt = nameMap.find(it->second); if (jt != nameMap.end()) From 267c8ad046d45c63a323eac32e00c3beeaddf0fd Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 6 Jul 2013 17:21:35 +0200 Subject: [PATCH 149/160] 0001023: Crash when quitting after using Windows > Tile --- src/Gui/MDIView.cpp | 8 ++++++-- src/Gui/View3DInventor.cpp | 6 ++++++ src/Gui/View3DInventor.h | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Gui/MDIView.cpp b/src/Gui/MDIView.cpp index 895d4ec4e..80646a14d 100644 --- a/src/Gui/MDIView.cpp +++ b/src/Gui/MDIView.cpp @@ -76,13 +76,17 @@ void MDIView::deleteSelf() { // When using QMdiArea make sure to remove the QMdiSubWindow // this view is associated with. + // + // #0001023: Crash when quitting after using Windows > Tile + // Use deleteLater() instead of delete operator. #if !defined (NO_USE_QT_MDI_AREA) QWidget* parent = this->parentWidget(); if (qobject_cast(parent)) - delete parent; + parent->deleteLater(); else #endif - delete this; + this->deleteLater(); + _pcDocument = 0; } void MDIView::setOverrideCursor(const QCursor& c) diff --git a/src/Gui/View3DInventor.cpp b/src/Gui/View3DInventor.cpp index 9528ef143..3fca6cf0e 100644 --- a/src/Gui/View3DInventor.cpp +++ b/src/Gui/View3DInventor.cpp @@ -179,6 +179,12 @@ View3DInventor::~View3DInventor() delete _viewer; } +void View3DInventor::deleteSelf() +{ + _viewer->setDocument(0); + MDIView::deleteSelf(); +} + PyObject *View3DInventor::getPyObject(void) { if (!_viewerPy) diff --git a/src/Gui/View3DInventor.h b/src/Gui/View3DInventor.h index 94cd990e8..f955c0cc6 100644 --- a/src/Gui/View3DInventor.h +++ b/src/Gui/View3DInventor.h @@ -73,6 +73,7 @@ public: /// Mesage handler virtual bool onMsg(const char* pMsg, const char** ppReturn); virtual bool onHasMsg(const char* pMsg) const; + virtual void deleteSelf(); /// Observer message from the ParameterGrp virtual void OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp::MessageType Reason); /// get called when the document is updated From efd0274d47edba85a55ac3df263b1f535fc4cd57 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 6 Jul 2013 17:48:30 +0200 Subject: [PATCH 150/160] 0001104: Toolbar Customizer Move Buttons enabled but inactive --- src/Gui/DlgToolbarsImp.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Gui/DlgToolbarsImp.cpp b/src/Gui/DlgToolbarsImp.cpp index 4b51f06f2..31827df5e 100644 --- a/src/Gui/DlgToolbarsImp.cpp +++ b/src/Gui/DlgToolbarsImp.cpp @@ -288,7 +288,11 @@ void DlgCustomToolbars::on_moveActionRightButton_clicked() QTreeWidgetItem* item = commandTreeWidget->currentItem(); if (item) { QTreeWidgetItem* current = toolbarTreeWidget->currentItem(); - if (current && !current->parent() && toolbarTreeWidget->isItemSelected(current)) { + if (!current) + current = toolbarTreeWidget->topLevelItem(0); + else if (current->parent()) + current = current->parent(); + if (current && !current->parent()) { QTreeWidgetItem* copy = new QTreeWidgetItem(current); copy->setText(0, item->text(1)); copy->setIcon(0, item->icon(0)); From 9ba82ae058b1e0ba15b25259baa14cbf2ce12197 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sat, 6 Jul 2013 13:30:26 -0300 Subject: [PATCH 151/160] Arch: Small fix in windows --- src/Mod/Arch/ArchWindow.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py index 5d6436020..55dc0c094 100644 --- a/src/Mod/Arch/ArchWindow.py +++ b/src/Mod/Arch/ArchWindow.py @@ -467,6 +467,8 @@ class _ArchWindowTaskPanel: t = WindowPartTypes[0] else: t = str(getattr(self,"field"+str(i+1)).text()) + if t in WindowPartTypes: + t = t + "_" # avoiding part names similar to types if t == "": if not(i in [1,5]): ok = False From 28b001f26c341623cb94fdf27bfcbb9e4529f2f2 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sat, 6 Jul 2013 16:33:34 -0300 Subject: [PATCH 152/160] Draft: Further work on SVG hatch patterns --- src/Mod/Draft/Draft.py | 12 +- src/Mod/Draft/Draft_rc.py | 790 +++++++++++------- src/Mod/Draft/Resources/patterns/concrete.svg | 196 ++++- src/Mod/Draft/Resources/patterns/cross.svg | 132 ++- src/Mod/Draft/Resources/patterns/line.svg | 82 +- src/Mod/Draft/Resources/patterns/square.svg | 102 ++- 6 files changed, 986 insertions(+), 328 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 713027aa8..9f9379d50 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -409,7 +409,17 @@ def select(objs=None): def loadSvgPatterns(): "loads the default Draft SVG patterns and custom patters if available" import importSVG - FreeCAD.svgpatterns = importSVG.getContents(Draft_rc.qt_resource_data,'pattern',True) + from PyQt4 import QtCore + FreeCAD.svgpatterns = {} + # getting default patterns + patfiles = QtCore.QDir(":/patterns").entryList() + for fn in patfiles: + f = QtCore.QFile(":/patterns/"+str(fn)) + f.open(QtCore.QIODevice.ReadOnly) + p = importSVG.getContents(str(f.readAll()),'pattern',True) + if p: + FreeCAD.svgpatterns.update(p) + # looking for user patterns altpat = getParam("patternFile") if os.path.isdir(altpat): for f in os.listdir(altpat): diff --git a/src/Mod/Draft/Draft_rc.py b/src/Mod/Draft/Draft_rc.py index b14e8bfac..7375cb072 100644 --- a/src/Mod/Draft/Draft_rc.py +++ b/src/Mod/Draft/Draft_rc.py @@ -2,7 +2,7 @@ # Resource object code # -# Created: Fri Jul 5 22:03:19 2013 +# Created: Sat Jul 6 16:32:11 2013 # by: The Resource Compiler for PyQt (Qt v4.8.4) # # WARNING! All changes made in this file will be lost! @@ -10,35 +10,113 @@ from PyQt4 import QtCore qt_resource_data = "\ -\x00\x00\x01\x60\ +\x00\x00\x0a\xed\ \x3c\ -\x73\x76\x67\x3e\x0a\x20\x20\x3c\x64\x65\x66\x73\x3e\x0a\x20\x20\ -\x20\x20\x3c\x70\x61\x74\x74\x65\x72\x6e\x0a\x20\x20\x20\x20\x20\ -\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\x65\x22\x0a\x20\x20\x20\x20\ -\x20\x20\x20\x70\x61\x74\x74\x65\x72\x6e\x55\x6e\x69\x74\x73\x3d\ -\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\x4f\x6e\x55\x73\x65\x22\ -\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x3d\x22\x30\x22\x0a\x20\x20\ -\x20\x20\x20\x20\x20\x79\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\ -\x20\x20\x77\x69\x64\x74\x68\x3d\x22\x2e\x31\x22\x0a\x20\x20\x20\ -\x20\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x2e\x31\x22\x3e\ -\x0a\x20\x20\x20\x20\x20\x20\x3c\x67\x0a\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\x6c\x6c\x3a\x6e\ -\x6f\x6e\x65\x3b\x20\x73\x74\x72\x6f\x6b\x65\x3a\x23\x30\x30\x30\ -\x30\x30\x30\x3b\x20\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\ -\x68\x3a\x2e\x30\x30\x35\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x69\x64\x3d\x22\x67\x33\x33\x38\x39\x22\x3e\x0a\x20\x20\x20\ -\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x4d\x30\x2c\x30\x2e\x30\x35\ -\x20\x6c\x2e\x31\x32\x2c\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\x33\x33\x39\x31\ -\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x2f\x67\x3e\x0a\ -\x20\x20\x20\x20\x3c\x2f\x70\x61\x74\x74\x65\x72\x6e\x3e\x0a\x20\ -\x20\x3c\x2f\x64\x65\x66\x73\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\ -\x00\x00\x01\xaa\ -\x3c\ -\x73\x76\x67\x3e\x0a\x20\x20\x3c\x64\x65\x66\x73\x3e\x0a\x20\x20\ -\x20\x20\x3c\x70\x61\x74\x74\x65\x72\x6e\x0a\x20\x20\x20\x20\x20\ -\x20\x20\x69\x64\x3d\x22\x63\x72\x6f\x73\x73\x22\x0a\x20\x20\x20\ +\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\ +\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\ +\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\ +\x6e\x6f\x22\x3f\x3e\x0a\x3c\x73\x76\x67\x0a\x20\x20\x20\x78\x6d\ +\x6c\x6e\x73\x3a\x64\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\ +\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\x63\x2f\x65\x6c\x65\x6d\x65\ +\x6e\x74\x73\x2f\x31\x2e\x31\x2f\x22\x0a\x20\x20\x20\x78\x6d\x6c\ +\x6e\x73\x3a\x63\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\ +\x65\x61\x74\x69\x76\x65\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x6f\x72\ +\x67\x2f\x6e\x73\x23\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\ +\x72\x64\x66\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\ +\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\x30\x32\x2f\x32\ +\x32\x2d\x72\x64\x66\x2d\x73\x79\x6e\x74\x61\x78\x2d\x6e\x73\x23\ +\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x73\x76\x67\x3d\x22\ +\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\ +\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\x78\ +\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\ +\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\ +\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x73\x6f\x64\x69\x70\ +\x6f\x64\x69\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x73\x6f\x64\x69\ +\x70\x6f\x64\x69\x2e\x73\x6f\x75\x72\x63\x65\x66\x6f\x72\x67\x65\ +\x2e\x6e\x65\x74\x2f\x44\x54\x44\x2f\x73\x6f\x64\x69\x70\x6f\x64\ +\x69\x2d\x30\x2e\x64\x74\x64\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\ +\x73\x3a\x69\x6e\x6b\x73\x63\x61\x70\x65\x3d\x22\x68\x74\x74\x70\ +\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\ +\x6f\x72\x67\x2f\x6e\x61\x6d\x65\x73\x70\x61\x63\x65\x73\x2f\x69\ +\x6e\x6b\x73\x63\x61\x70\x65\x22\x0a\x20\x20\x20\x69\x64\x3d\x22\ +\x73\x76\x67\x33\x34\x34\x38\x22\x0a\x20\x20\x20\x76\x65\x72\x73\ +\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x0a\x20\x20\x20\x69\x6e\x6b\ +\x73\x63\x61\x70\x65\x3a\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x30\ +\x2e\x34\x38\x2e\x33\x2e\x31\x20\x72\x39\x38\x38\x36\x22\x0a\x20\ +\x20\x20\x77\x69\x64\x74\x68\x3d\x22\x36\x34\x22\x0a\x20\x20\x20\ +\x68\x65\x69\x67\x68\x74\x3d\x22\x36\x34\x22\x0a\x20\x20\x20\x73\ +\x6f\x64\x69\x70\x6f\x64\x69\x3a\x64\x6f\x63\x6e\x61\x6d\x65\x3d\ +\x22\x6c\x69\x6e\x65\x2e\x73\x76\x67\x22\x3e\x0a\x20\x20\x3c\x6d\ +\x65\x74\x61\x64\x61\x74\x61\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\ +\x22\x6d\x65\x74\x61\x64\x61\x74\x61\x33\x34\x35\x37\x22\x3e\x0a\ +\x20\x20\x20\x20\x3c\x72\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\x20\ +\x20\x20\x20\x20\x3c\x63\x63\x3a\x57\x6f\x72\x6b\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x72\x64\x66\x3a\x61\x62\x6f\x75\x74\x3d\ +\x22\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\ +\x66\x6f\x72\x6d\x61\x74\x3e\x69\x6d\x61\x67\x65\x2f\x73\x76\x67\ +\x2b\x78\x6d\x6c\x3c\x2f\x64\x63\x3a\x66\x6f\x72\x6d\x61\x74\x3e\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x74\x79\x70\ +\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\x66\ +\x3a\x72\x65\x73\x6f\x75\x72\x63\x65\x3d\x22\x68\x74\x74\x70\x3a\ +\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\x63\x2f\x64\x63\ +\x6d\x69\x74\x79\x70\x65\x2f\x53\x74\x69\x6c\x6c\x49\x6d\x61\x67\ +\x65\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x2f\x63\x63\ +\x3a\x57\x6f\x72\x6b\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x72\x64\x66\ +\x3a\x52\x44\x46\x3e\x0a\x20\x20\x3c\x2f\x6d\x65\x74\x61\x64\x61\ +\x74\x61\x3e\x0a\x20\x20\x3c\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\ +\x6e\x61\x6d\x65\x64\x76\x69\x65\x77\x0a\x20\x20\x20\x20\x20\x70\ +\x61\x67\x65\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x66\x66\x66\x66\x66\ +\x66\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x63\x6f\ +\x6c\x6f\x72\x3d\x22\x23\x36\x36\x36\x36\x36\x36\x22\x0a\x20\x20\ +\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x6f\x70\x61\x63\x69\x74\x79\ +\x3d\x22\x31\x22\x0a\x20\x20\x20\x20\x20\x6f\x62\x6a\x65\x63\x74\ +\x74\x6f\x6c\x65\x72\x61\x6e\x63\x65\x3d\x22\x31\x30\x22\x0a\x20\ +\x20\x20\x20\x20\x67\x72\x69\x64\x74\x6f\x6c\x65\x72\x61\x6e\x63\ +\x65\x3d\x22\x31\x30\x22\x0a\x20\x20\x20\x20\x20\x67\x75\x69\x64\ +\x65\x74\x6f\x6c\x65\x72\x61\x6e\x63\x65\x3d\x22\x31\x30\x22\x0a\ +\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\ +\x67\x65\x6f\x70\x61\x63\x69\x74\x79\x3d\x22\x30\x22\x0a\x20\x20\ +\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\ +\x73\x68\x61\x64\x6f\x77\x3d\x22\x32\x22\x0a\x20\x20\x20\x20\x20\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\ +\x77\x69\x64\x74\x68\x3d\x22\x31\x39\x32\x30\x22\x0a\x20\x20\x20\ +\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\ +\x77\x2d\x68\x65\x69\x67\x68\x74\x3d\x22\x31\x30\x35\x37\x22\x0a\ +\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6e\x61\x6d\x65\x64\x76\x69\ +\x65\x77\x33\x34\x35\x35\x22\x0a\x20\x20\x20\x20\x20\x73\x68\x6f\ +\x77\x67\x72\x69\x64\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\x20\x20\ +\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x7a\x6f\x6f\x6d\x3d\ +\x22\x33\x2e\x35\x38\x38\x31\x31\x38\x33\x22\x0a\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x78\x3d\x22\x35\x30\ +\x2e\x39\x31\x39\x32\x36\x31\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x63\x79\x3d\x22\x33\x32\x2e\x33\x39\ +\x33\x31\x34\x38\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x78\x3d\x22\x30\x22\ +\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\ +\x69\x6e\x64\x6f\x77\x2d\x79\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\ +\x2d\x6d\x61\x78\x69\x6d\x69\x7a\x65\x64\x3d\x22\x31\x22\x0a\x20\ +\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x75\x72\ +\x72\x65\x6e\x74\x2d\x6c\x61\x79\x65\x72\x3d\x22\x73\x76\x67\x33\ +\x34\x34\x38\x22\x3e\x0a\x20\x20\x20\x20\x3c\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3a\x67\x72\x69\x64\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x74\x79\x70\x65\x3d\x22\x78\x79\x67\x72\x69\x64\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x67\x72\x69\x64\x33\x34\x35\ +\x39\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x65\x6d\x70\x73\x70\x61\ +\x63\x69\x6e\x67\x3d\x22\x35\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x76\x69\x73\x69\x62\x6c\x65\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x65\x6e\x61\x62\x6c\x65\x64\x3d\x22\x74\ +\x72\x75\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x73\x6e\x61\x70\ +\x76\x69\x73\x69\x62\x6c\x65\x67\x72\x69\x64\x6c\x69\x6e\x65\x73\ +\x6f\x6e\x6c\x79\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x73\x70\x61\x63\x69\x6e\x67\x78\x3d\x22\x38\x70\x78\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x73\x70\x61\x63\x69\x6e\x67\ +\x79\x3d\x22\x38\x70\x78\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x2f\x73\ +\x6f\x64\x69\x70\x6f\x64\x69\x3a\x6e\x61\x6d\x65\x64\x76\x69\x65\ +\x77\x3e\x0a\x20\x20\x3c\x64\x65\x66\x73\x0a\x20\x20\x20\x20\x20\ +\x69\x64\x3d\x22\x64\x65\x66\x73\x33\x34\x35\x30\x22\x3e\x0a\x20\ +\x20\x20\x20\x3c\x70\x61\x74\x74\x65\x72\x6e\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\x65\x22\x0a\x20\x20\x20\ \x20\x20\x20\x20\x70\x61\x74\x74\x65\x72\x6e\x55\x6e\x69\x74\x73\ \x3d\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\x4f\x6e\x55\x73\x65\ \x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x3d\x22\x30\x22\x0a\x20\ @@ -50,48 +128,198 @@ qt_resource_data = "\ \x6e\x6f\x6e\x65\x3b\x20\x73\x74\x72\x6f\x6b\x65\x3a\x23\x30\x30\ \x30\x30\x30\x30\x3b\x20\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\ \x74\x68\x3a\x2e\x30\x30\x35\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x69\x64\x3d\x22\x67\x33\x33\x38\x32\x22\x3e\x0a\x20\x20\ +\x20\x20\x69\x64\x3d\x22\x67\x33\x33\x38\x39\x22\x3e\x0a\x20\x20\ \x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x4d\x30\x2c\x30\x20\x6c\ -\x2e\x31\x32\x2c\x2e\x31\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\x33\x33\x38\x34\ -\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\ -\x74\x68\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x64\x3d\ -\x22\x4d\x2e\x31\x32\x2c\x30\x20\x6c\x2d\x2e\x31\x32\x2c\x2e\x31\ -\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\ -\x3d\x22\x70\x61\x74\x68\x33\x33\x38\x36\x22\x20\x2f\x3e\x0a\x20\ -\x20\x20\x20\x20\x20\x3c\x2f\x67\x3e\x0a\x20\x20\x20\x20\x3c\x2f\ -\x70\x61\x74\x74\x65\x72\x6e\x3e\x0a\x20\x20\x3c\x2f\x64\x65\x66\ -\x73\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\ -\x00\x00\x01\xae\ -\x3c\ -\x73\x76\x67\x3e\x0a\x20\x20\x3c\x64\x65\x66\x73\x3e\x20\x20\x20\ -\x20\x0a\x20\x20\x20\x20\x3c\x70\x61\x74\x74\x65\x72\x6e\x0a\x20\ -\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x71\x75\x61\x72\x65\ -\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x70\x61\x74\x74\x65\x72\x6e\ -\x55\x6e\x69\x74\x73\x3d\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\ -\x4f\x6e\x55\x73\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x3d\ -\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x79\x3d\x22\x30\x22\ -\x0a\x20\x20\x20\x20\x20\x20\x20\x77\x69\x64\x74\x68\x3d\x22\x2e\ -\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x68\x65\x69\x67\x68\x74\ -\x3d\x22\x2e\x31\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x67\x0a\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\ -\x66\x69\x6c\x6c\x3a\x6e\x6f\x6e\x65\x3b\x20\x73\x74\x72\x6f\x6b\ -\x65\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\x20\x73\x74\x72\x6f\x6b\ -\x65\x2d\x77\x69\x64\x74\x68\x3a\x2e\x30\x30\x35\x22\x0a\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x67\x33\x33\x39\x34\ -\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\ -\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x4d\ -\x30\x2c\x30\x2e\x30\x35\x20\x6c\x2e\x31\x32\x2c\x30\x22\x0a\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\ -\x74\x68\x33\x33\x39\x36\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\ -\x20\x20\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x64\x3d\x22\x4d\x30\x2e\x30\x35\x2c\x30\x20\x6c\ -\x30\x2c\x2e\x31\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\x33\x33\x39\x38\x22\x20\ -\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x2f\x67\x3e\x0a\x20\x20\ -\x20\x20\x3c\x2f\x70\x61\x74\x74\x65\x72\x6e\x3e\x0a\x20\x20\x3c\ -\x2f\x64\x65\x66\x73\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\ +\x20\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x4d\x30\x2c\x30\x2e\x30\ +\x35\x20\x6c\x2e\x31\x32\x2c\x30\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\x33\x33\x39\ +\x31\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x2f\x67\x3e\ +\x0a\x20\x20\x20\x20\x3c\x2f\x70\x61\x74\x74\x65\x72\x6e\x3e\x0a\ +\x20\x20\x3c\x2f\x64\x65\x66\x73\x3e\x0a\x20\x20\x3c\x70\x61\x74\ +\x68\x0a\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\ +\x6c\x6c\x3a\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x23\ +\x30\x30\x30\x30\x30\x30\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\ +\x64\x74\x68\x3a\x31\x70\x78\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\ +\x69\x6e\x65\x63\x61\x70\x3a\x62\x75\x74\x74\x3b\x73\x74\x72\x6f\ +\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\x3a\x6d\x69\x74\x65\ +\x72\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\ +\x3a\x31\x22\x0a\x20\x20\x20\x20\x20\x64\x3d\x22\x6d\x20\x30\x2c\ +\x35\x36\x20\x36\x34\x2c\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x64\ +\x3d\x22\x70\x61\x74\x68\x33\x34\x36\x31\x22\x0a\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6e\x6e\x65\x63\ +\x74\x6f\x72\x2d\x63\x75\x72\x76\x61\x74\x75\x72\x65\x3d\x22\x30\ +\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\ +\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\x6c\x6c\x3a\x6e\x6f\ +\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x23\x30\x30\x30\x30\x30\ +\x30\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x31\ +\x70\x78\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\ +\x70\x3a\x62\x75\x74\x74\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\ +\x6e\x65\x6a\x6f\x69\x6e\x3a\x6d\x69\x74\x65\x72\x3b\x73\x74\x72\ +\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x22\x0a\x20\ +\x20\x20\x20\x20\x64\x3d\x22\x6d\x20\x30\x2c\x34\x30\x20\x36\x34\ +\x2c\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\ +\x68\x33\x34\x36\x33\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\ +\x63\x61\x70\x65\x3a\x63\x6f\x6e\x6e\x65\x63\x74\x6f\x72\x2d\x63\ +\x75\x72\x76\x61\x74\x75\x72\x65\x3d\x22\x30\x22\x20\x2f\x3e\x0a\ +\x20\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\x20\x20\x73\x74\x79\ +\x6c\x65\x3d\x22\x66\x69\x6c\x6c\x3a\x6e\x6f\x6e\x65\x3b\x73\x74\ +\x72\x6f\x6b\x65\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\x73\x74\x72\ +\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x31\x70\x78\x3b\x73\x74\ +\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3a\x62\x75\x74\ +\x74\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\ +\x6e\x3a\x6d\x69\x74\x65\x72\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6f\ +\x70\x61\x63\x69\x74\x79\x3a\x31\x22\x0a\x20\x20\x20\x20\x20\x64\ +\x3d\x22\x6d\x20\x30\x2c\x32\x34\x20\x36\x34\x2c\x30\x22\x0a\x20\ +\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\x33\x34\x36\x35\ +\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ +\x63\x6f\x6e\x6e\x65\x63\x74\x6f\x72\x2d\x63\x75\x72\x76\x61\x74\ +\x75\x72\x65\x3d\x22\x30\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x70\x61\ +\x74\x68\x0a\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\ +\x69\x6c\x6c\x3a\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x3a\ +\x23\x30\x30\x30\x30\x30\x30\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\ +\x69\x64\x74\x68\x3a\x31\x70\x78\x3b\x73\x74\x72\x6f\x6b\x65\x2d\ +\x6c\x69\x6e\x65\x63\x61\x70\x3a\x62\x75\x74\x74\x3b\x73\x74\x72\ +\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\x3a\x6d\x69\x74\ +\x65\x72\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\ +\x79\x3a\x31\x22\x0a\x20\x20\x20\x20\x20\x64\x3d\x22\x4d\x20\x30\ +\x2c\x38\x20\x36\x34\x2c\x38\x22\x0a\x20\x20\x20\x20\x20\x69\x64\ +\x3d\x22\x70\x61\x74\x68\x33\x34\x36\x37\x22\x0a\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6e\x6e\x65\x63\ +\x74\x6f\x72\x2d\x63\x75\x72\x76\x61\x74\x75\x72\x65\x3d\x22\x30\ +\x22\x20\x2f\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\ +\x00\x00\x04\x2e\ +\x00\ +\x00\x13\x35\x78\x9c\xd5\x58\xcb\x6e\xe3\x36\x14\xdd\xe7\x2b\x04\ +\x66\xd9\x58\x6f\x2b\x92\xc6\xf2\x6c\x82\x01\xba\x28\x0a\x74\x26\ +\xe8\x9a\x96\x68\x5b\x13\x89\x14\x48\xfa\x35\x5f\xdf\x4b\x8a\x7a\ +\xd8\xd2\xa0\xed\x6a\x6c\x01\x01\xc2\x73\x0f\x2f\x79\xee\x4b\x4a\ +\x56\x9f\xcf\x75\x65\x1d\x09\x17\x25\xa3\x19\xf2\x6c\x17\x59\x84\ +\xe6\xac\x28\xe9\x2e\x43\xef\xdf\xbe\x2c\x62\x64\x09\x89\x69\x81\ +\x2b\x46\x49\x86\x28\x43\x9f\xd7\x4f\x2b\x71\xdc\x3d\x59\x96\x05\ +\x9b\xa9\x48\x8b\x3c\x43\x7b\x29\x9b\xd4\x71\x9a\x03\xaf\x6c\xc6\ +\x77\x4e\x91\x3b\xa4\x22\x35\xa1\x52\x38\x9e\xed\x39\x68\xa0\xe7\ +\x03\x3d\xe7\x04\xcb\xf2\x48\x72\x56\xd7\x8c\x0a\xbd\x93\x8a\xe7\ +\x11\x99\x17\xdb\x9e\x7d\x3a\x9d\xec\x53\xa0\x49\x5e\x92\x24\x8e\ +\xeb\x3b\xbe\xbf\x00\xc6\x42\x5c\xa8\xc4\xe7\xc5\xf5\x56\xb8\xe3\ +\xdc\x56\xdf\x75\x5d\x07\x6c\x03\xf3\xbf\xb1\x52\x01\x51\x69\xe0\ +\xa7\xa7\x77\x80\x2d\xd8\x81\xe7\x64\x0b\xfb\x88\x4d\x89\x74\xde\ +\xbe\xbd\xf5\xc6\x85\x6b\x17\xb2\x18\xb9\x29\xe9\x87\xc8\x71\x43\ +\xae\x4e\xed\xc0\x36\x02\xb8\x26\xa2\xc1\x39\x11\x4e\x87\xeb\xfd\ +\x65\x91\x21\xb8\x52\xb0\x0c\x7d\xbd\x1e\xa5\xcd\x6b\x09\x86\x9d\ +\xf6\x16\xd7\x0e\x63\x3b\xb0\x3d\x8b\x27\x71\x1c\x69\xd2\xa9\x2c\ +\xe4\x3e\x43\x51\xa8\x57\x7b\x52\xee\xf6\xb2\x5f\x76\xb7\x4e\x0b\ +\x96\xab\x6b\x64\x28\xe7\x4c\x08\x5b\x45\x62\x0d\x84\x55\x4d\x24\ +\x2e\xb0\xc4\x8a\xdc\xde\xa8\x43\x82\xe5\xd2\xd7\x1c\x60\x41\x4e\ +\xd2\xbf\xde\xbe\xb4\x2b\x58\xe7\x79\xfa\x37\xe3\x1f\x66\x09\x8f\ +\x22\xe0\x0d\x3b\xc0\xc9\x68\xdd\xc3\xab\x22\x4f\x21\x8a\x35\x96\ +\xeb\xb2\xc6\x3b\xa2\x12\xf0\x1b\x44\x6d\xe5\x0c\x86\x2b\xb2\xbc\ +\x34\x64\x70\xda\xba\xe5\xa4\x4d\xc7\x6c\x4d\x16\x79\x5d\xaa\x4d\ +\xce\x57\x59\x56\xd5\xef\xea\x10\x64\x39\xfd\x3d\x1d\x73\x51\x23\ +\xc3\x19\xe9\x58\x39\x9d\x50\xbd\xea\x03\xa5\xa2\x54\x1c\x4b\x72\ +\x6a\x7d\x34\xe0\x31\x67\x15\xe3\x19\x7a\xde\xea\x07\xb5\x86\x0d\ +\xe3\x05\xe1\x9d\x29\xd2\xcf\x95\x89\x41\xc6\xe1\x6e\x90\x4d\x03\ +\xb3\xcd\x77\x92\x4b\xc9\x2a\xc2\x31\x55\x7a\x3c\xd7\x58\x76\x1c\ +\x72\x38\x87\x1f\xca\x82\xcc\x19\xfa\xc2\x50\xd7\xeb\x0f\x9a\xb5\ +\x8a\x3d\x2e\xd8\x29\x43\xfe\xad\xf1\x54\x52\x30\x2c\x4c\xf9\x78\ +\x89\x3f\xd9\x6e\x18\x5d\x49\x79\xee\xf2\x15\x0d\x75\xd2\x07\x0a\ +\x0a\xa5\xdb\x2a\xf6\xec\xa4\xc4\x64\x48\xf2\x03\xb9\xf5\xf7\x83\ +\xb1\x3a\x43\x4b\xdb\x7d\x0d\x83\x68\xb9\xbc\x35\xe7\xe7\x0c\x41\ +\x77\x25\x61\xb8\x7c\x85\x71\x30\x31\x83\xc2\xc0\xb7\xfd\x20\xf0\ +\xe3\x89\xd1\x5c\xf5\x3c\x13\x04\x63\x9a\x8b\x8f\x31\xd5\xf8\x5c\ +\xd6\xe5\x0f\x52\x0c\xb9\x1a\x4e\x3d\x70\x0e\x43\x6f\x51\xe1\x0b\ +\xe1\x43\xbb\x9a\x82\xea\x69\x4a\x74\x57\xb8\xaa\x1e\x33\x74\xbe\ +\x28\x0c\x75\xa0\x8a\x89\x02\x82\x28\xf2\x7b\x90\xd4\x8d\x9a\x0b\ +\x7a\x36\x2f\x7b\xf4\x58\x8a\x72\x53\x91\xab\x18\x02\x97\x62\x00\ +\x8b\x1b\x54\x50\xdc\x18\xbe\xf2\x5e\x95\x14\xba\x85\x56\x97\x5b\ +\x5a\x7b\x0a\x84\x27\x6e\xce\xb7\xe8\xa5\x45\xdb\xb6\x59\x39\xd3\ +\x4e\xd0\x78\x41\xb6\x62\x48\xbe\x5a\x41\x20\xc2\x2e\x10\x0d\x96\ +\x92\x70\x3a\x56\xab\x07\x4d\x7f\x96\x21\xbc\xd3\x52\xc2\x7c\x3e\ +\x08\xc2\xbf\xaa\x89\xf8\x27\x7d\x17\xc3\x35\x47\xe9\xb3\xac\xcb\ +\x78\x61\xaa\xd4\xf6\x7a\xa4\xab\x4a\x80\xfa\x76\xdf\x0d\xb3\x43\ +\xc8\x8b\x0a\xe1\x16\xa6\x42\x4a\xe1\x4d\xf7\x09\x10\xce\x3e\x48\ +\xfa\xec\xea\xa7\x5b\xb7\xf5\x9f\xda\xae\x3b\x24\xc0\x64\x2b\x08\ +\x62\x7f\x3c\xcc\x40\xc2\x7e\x3c\x9c\x80\xf3\x87\xfb\xe2\x5a\x95\ +\xed\xf9\x2f\xf0\x83\xc6\x46\xe5\x41\x6d\x00\x27\xe1\x68\x22\xfd\ +\xc4\x8d\xf2\x00\x8e\x16\xff\xe2\x29\xba\x9a\x6d\xbb\x6e\xaa\x99\ +\xd8\xb6\xe9\x53\x99\xd1\xbf\x0d\xe7\x4c\x62\x71\x13\x8a\xab\x48\ +\x78\xcd\xb9\x03\x54\x35\x41\x75\xa7\x9b\x83\x94\x63\xec\x3b\x2b\ +\x69\x0a\x73\x97\xf0\x0e\x35\x23\x28\xed\xd2\xa3\x34\x59\x51\x08\ +\x9a\xdc\x17\xf3\x26\x1a\x84\xf8\x49\x12\x4f\xda\x8c\x51\x38\x4b\ +\x32\xbe\x80\x86\x3b\x62\x79\xe0\x44\xa5\xdf\xd4\xe4\x2f\x97\x12\ +\xc6\x5a\x4a\x18\xdf\x48\x09\xe0\xcc\x07\x93\xe2\x45\x90\x11\x95\ +\x1b\x2f\x9a\x8a\x99\xbc\x24\xee\x5c\x4c\xe0\xeb\xbc\x04\xfe\x54\ +\x4a\xf8\x60\x52\x20\x2f\x4a\xca\x5c\x56\xa2\x07\x93\x02\xc5\x15\ +\xf8\x2a\x37\x93\xd6\x07\x31\x8f\xd6\xfa\x20\x26\x8c\xd5\x00\x98\ +\x11\x33\xfd\x1e\xbb\x73\x31\xea\x75\x05\x82\xa6\x52\xa2\x38\x78\ +\x30\x29\xba\x5f\x74\x72\xa6\x5a\xa6\x9f\x96\xf7\xad\x45\x8f\x31\ +\xdd\x35\x53\x2d\xaf\x0f\xa6\x45\xbf\x2a\x67\x5f\x2f\xd1\xf4\xb3\ +\xfd\xce\xb5\xa8\x71\x3c\xdf\xfa\x51\x32\xfd\x4b\xe1\xde\xb5\xfc\ +\x6c\x26\x47\xc9\xa3\xf5\xbe\xfa\x12\x6b\x3f\x64\xa6\x5a\xfe\x4f\ +\xef\xaf\xd4\x3f\x24\xd6\x4f\xff\x00\x3d\xa0\xd3\x03\ +\x00\x00\x03\xd9\ +\x00\ +\x00\x0e\x64\x78\x9c\xd5\x56\xc9\x8e\xdb\x38\x10\xbd\xf7\x57\x08\ +\xec\xe3\xd8\x12\xb5\x58\x92\x15\xcb\xb9\x34\x02\xcc\x21\x18\x60\ +\x92\x46\xce\xb4\x44\xdb\x4a\x4b\xa4\x86\xa4\xbc\xe4\xeb\xa7\xa8\ +\x85\x92\x37\x60\xe6\x16\x0b\x68\xa0\xf9\xea\xb1\x8a\xaf\xb6\xee\ +\xd5\xe7\x53\x55\x5a\x07\x2a\x64\xc1\x59\x8a\x5c\x1b\x23\x8b\xb2\ +\x8c\xe7\x05\xdb\xa5\xe8\xfd\xfb\x97\x79\x8c\x2c\xa9\x08\xcb\x49\ +\xc9\x19\x4d\x11\xe3\xe8\xf3\xfa\x65\x25\x0f\xbb\x17\xcb\xb2\xe0\ +\x32\x93\x49\x9e\xa5\x68\xaf\x54\x9d\x38\x4e\xdd\x88\xd2\xe6\x62\ +\xe7\xe4\x99\x43\x4b\x5a\x51\xa6\xa4\xe3\xda\xae\x83\x46\x7a\x36\ +\xd2\x33\x41\x89\x2a\x0e\x34\xe3\x55\xc5\x99\x6c\x6f\x32\xf9\x3a\ +\x21\x8b\x7c\x6b\xd8\xc7\xe3\xd1\x3e\xfa\x2d\xc9\x5d\x2e\x97\x0e\ +\xf6\x1c\xcf\x9b\x03\x63\x2e\xcf\x4c\x91\xd3\xfc\xf2\x2a\xbc\xf1\ +\xde\x55\x0f\x63\xec\x80\x6d\x64\xfe\x37\x56\x22\x21\x2b\x35\xfc\ +\x18\xfa\x00\xd8\x92\x37\x22\xa3\x5b\xb8\x47\x6d\x46\x95\xf3\xf6\ +\xfd\xcd\x18\xe7\xd8\xce\x55\x3e\x71\x53\xb0\x0f\x99\x91\x9a\x5e\ +\x44\x1d\xc0\x2e\x03\xa4\xa2\xb2\x26\x19\x95\xce\x80\xb7\xf7\x8b\ +\x3c\x45\xf0\x24\x3f\x8a\x83\xf6\x3c\x29\x9b\xdb\x11\x7a\x76\x62\ +\x2c\xd8\x0e\x62\xdb\xb7\x5d\x4b\x2c\xe3\x38\x6c\x49\xc7\x22\x57\ +\xfb\x14\x85\x9d\x8f\x3d\x2d\x76\x7b\x65\x8e\xc3\xab\x93\x9c\x67\ +\xfa\x19\x10\xf0\x9f\x86\x08\x6a\xeb\x54\xac\x81\xb1\xaa\xa8\x22\ +\x39\x51\x44\xb3\xbb\x27\x0d\x88\x1f\x2d\x83\x96\x03\x2c\x28\x4a\ +\xf2\xf7\xdb\x97\xee\x04\xe7\x2c\x4b\x7e\x70\xf1\xd1\x1f\xe1\xd3\ +\x04\xb2\xe1\x0d\x84\x46\x6b\x03\xaf\xf2\x2c\x81\x34\x56\x44\xad\ +\x8b\x8a\xec\xa8\xae\xc0\x1f\x90\xb6\x95\x33\x1a\x2e\xc8\xea\x5c\ +\xd3\xd1\x69\xe7\x56\xd0\xae\x1e\x77\x9b\x32\xcf\xaa\x42\x5f\x72\ +\xbe\xa9\xa2\x2c\xff\xd4\x41\x90\xe5\x98\x77\x3a\xfd\x43\x7b\x19\ +\xce\x44\xc7\xca\x19\x84\xb6\x27\x93\x29\x9d\xa6\xfc\x50\xd0\x63\ +\xe7\xa3\x06\x8f\x19\x2f\xb9\x48\xd1\xeb\xb6\xfd\x50\x67\xd8\x70\ +\x91\x53\x31\x98\xc2\xf6\xbb\x30\x71\x28\x39\xbc\x0d\xca\xd9\xc3\ +\x7c\xf3\x93\x66\x4a\xf1\x92\x0a\xc2\xb4\x1e\x17\xf7\x96\x9d\x80\ +\x22\xde\xc3\x9b\x22\xa7\xf7\x0c\xa6\x33\xf4\xf3\x4c\xa0\xbb\x56\ +\xb9\x27\x39\x3f\xa6\xc8\xbb\x36\x1e\x0b\x06\x86\x79\xdf\x3f\xee\ +\xd2\xbb\xb9\xde\x33\x86\x9e\x72\xf1\x22\x42\x63\x9f\x98\x44\x41\ +\xa3\x0c\xce\xe5\x9e\x1f\xb5\x98\x14\x29\xd1\xd0\x6b\x7f\xbf\x38\ +\xaf\x52\x14\xd9\x5e\x80\xa3\xc8\x0f\xae\xcd\xd9\x29\x45\x7e\x68\ +\x87\x9e\x1f\x45\xf1\x8d\x11\xf4\xf9\xbe\xed\x2f\x22\xdf\x7d\x24\ +\xe5\x74\x27\x05\xbd\xe9\x5e\x76\x7a\x53\x45\x4e\x45\x55\xfc\xa2\ +\xf9\x58\xa9\x31\x6a\x23\x04\xec\xbc\x79\x49\xce\x54\x8c\xd3\xda\ +\xb7\x93\xa1\x69\xc9\x43\xdb\xea\x6e\x4c\xd1\xe9\xac\x31\x34\x80\ +\x3a\x23\x1a\x80\x54\x85\x06\xa4\x55\xad\xd7\x42\xbb\x9a\x17\x06\ +\x3d\x14\xb2\xd8\x94\xf4\x22\x83\xc0\x65\x04\xc0\xfc\x0a\x95\x8c\ +\xd4\x3d\x5f\x7b\x2f\x0b\x06\xb3\xc2\xca\xf3\x35\xad\x8b\x02\xe9\ +\x89\xeb\xd3\x35\x7a\xee\xd0\x6e\x68\x56\xce\xed\x1c\xb4\x78\x4e\ +\xb7\x72\x2c\xbd\x3e\x41\x22\xc2\x21\x11\x35\x51\x8a\x0a\x36\x55\ +\xdb\xed\x19\x13\xac\x67\xbc\xb3\x42\xc1\x7e\x6e\x24\x15\xdf\xf4\ +\x46\xfc\x8b\xbd\xcb\x91\x34\xa9\x9f\x65\x9d\xa7\x87\xbe\x49\x6d\ +\xd7\x20\x43\x53\x02\x64\xa6\x7d\x37\xae\x0e\xa9\xce\x3a\x87\x5b\ +\x58\x0a\x09\x83\xbf\x74\x9f\x00\x11\xfc\x83\x26\xaf\xb8\xfd\x86\ +\x73\xd7\xfe\x89\x8d\xf1\x58\x81\xbe\x5c\xbe\x6f\xf6\xdf\x20\x72\ +\x3f\xdd\x4d\xc0\xf9\x8a\x67\xd8\xc6\x0b\xab\xb4\x5d\x6f\x86\xd1\ +\xd4\xaa\x5d\xe8\x1b\xe0\x25\x9c\x6c\xa4\x47\x7e\xc0\xcb\x0c\x5b\ +\x25\x9e\xd9\xa6\xbb\x6f\xfc\xc4\x17\x9b\x6d\x37\xec\xb4\x3e\xb5\ +\x5d\xf9\x74\x65\xda\xdf\xc6\x28\x37\xa9\xb8\xca\xc4\x45\x22\xdc\ +\xfa\x34\x00\xba\x9b\xa0\xbb\x93\x4d\xa3\xd4\x14\xfb\xc9\x0b\x96\ +\xc0\xd6\xa5\x62\x40\xfb\x05\x94\x0c\xd5\xd1\x7f\x44\x2c\x3c\x5b\ +\x84\x56\x18\x98\xb4\x18\x21\x41\x78\x3b\x66\x9c\x41\x2c\xc5\xc5\ +\x1c\x06\xee\x40\x54\x23\xa8\xae\x7e\xdf\x93\xbf\x81\x94\x00\x3f\ +\x90\xe2\x3f\x9d\x14\x2f\x78\x20\x65\xf1\x54\x52\xbe\x82\x94\x58\ +\x2b\x89\x6f\x95\x44\x4f\xa6\x24\x86\xd1\x8f\x67\x61\x70\xad\x24\ +\x76\x9f\x6d\x52\x3c\xe8\x2c\x28\xcc\x3d\x29\xcf\x36\x29\x01\x7e\ +\x28\xe5\xb9\x26\xa5\xb2\x16\xe1\x43\x29\xff\x67\x54\x56\xfa\xdf\ +\xf7\xf5\xcb\xbf\xca\xa1\x4f\xfa\ \x00\x00\x03\xdc\ \x00\ \x00\x0d\x76\x78\x9c\xd5\x56\x4d\x8f\xe3\x36\x0c\xbd\xcf\xaf\x30\ @@ -156,150 +384,114 @@ qt_resource_data = "\ \x55\x25\xfd\x64\x52\xa0\xb9\x92\xd8\xd4\x66\x76\xf5\x41\xcc\x67\ \xbb\xfa\x20\x66\x99\x99\x01\xf0\x40\xcc\xfc\x4f\xd4\x3f\x88\x59\ \x9b\x3f\xb4\x9b\xa7\xbf\x01\x1e\x88\x0a\xce\ -\x00\x00\x08\xd6\ -\x3c\ -\x73\x76\x67\x3e\x0a\x20\x20\x3c\x64\x65\x66\x73\x3e\x0a\x20\x20\ -\x20\x20\x3c\x70\x61\x74\x74\x65\x72\x6e\x0a\x20\x20\x20\x20\x20\ -\x20\x20\x69\x64\x3d\x22\x63\x6f\x6e\x63\x72\x65\x74\x65\x22\x0a\ -\x20\x20\x20\x20\x20\x20\x20\x70\x61\x74\x74\x65\x72\x6e\x55\x6e\ -\x69\x74\x73\x3d\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\x4f\x6e\ -\x55\x73\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x3d\x22\x30\ -\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x79\x3d\x22\x30\x22\x0a\x20\ -\x20\x20\x20\x20\x20\x20\x77\x69\x64\x74\x68\x3d\x22\x2e\x35\x22\ -\x0a\x20\x20\x20\x20\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\ -\x2e\x35\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x67\x0a\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\ -\x6c\x6c\x3a\x6e\x6f\x6e\x65\x3b\x20\x73\x74\x72\x6f\x6b\x65\x3a\ -\x23\x30\x30\x30\x30\x30\x30\x3b\x20\x73\x74\x72\x6f\x6b\x65\x2d\ -\x77\x69\x64\x74\x68\x3a\x2e\x35\x22\x0a\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x73\x63\ -\x61\x6c\x65\x28\x2e\x30\x31\x29\x22\x0a\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x69\x64\x3d\x22\x67\x33\x34\x30\x31\x22\x3e\x0a\x20\ -\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\ -\x6d\x20\x35\x2e\x33\x35\x37\x31\x34\x32\x38\x2c\x33\x2e\x35\x32\ -\x32\x38\x39\x34\x36\x20\x61\x20\x31\x2e\x33\x33\x39\x32\x38\x35\ -\x37\x2c\x31\x2e\x33\x33\x39\x32\x38\x35\x37\x20\x30\x20\x31\x20\ -\x31\x20\x2d\x32\x2e\x36\x37\x38\x35\x37\x31\x35\x2c\x30\x20\x31\ -\x2e\x33\x33\x39\x32\x38\x35\x37\x2c\x31\x2e\x33\x33\x39\x32\x38\ -\x35\x37\x20\x30\x20\x31\x20\x31\x20\x32\x2e\x36\x37\x38\x35\x37\ -\x31\x35\x2c\x30\x20\x7a\x22\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\ -\x20\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x20\x31\x34\x2e\ -\x31\x30\x37\x31\x34\x33\x2c\x36\x2e\x38\x32\x36\x34\x36\x36\x31\ -\x20\x61\x20\x33\x2e\x32\x31\x34\x32\x38\x35\x36\x2c\x33\x2e\x32\ -\x31\x34\x32\x38\x35\x36\x20\x30\x20\x31\x20\x31\x20\x2d\x36\x2e\ -\x34\x32\x38\x35\x37\x31\x31\x2c\x30\x20\x33\x2e\x32\x31\x34\x32\ -\x38\x35\x36\x2c\x33\x2e\x32\x31\x34\x32\x38\x35\x36\x20\x30\x20\ -\x31\x20\x31\x20\x36\x2e\x34\x32\x38\x35\x37\x31\x31\x2c\x30\x20\ -\x7a\x22\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\ -\x74\x68\x20\x64\x3d\x22\x6d\x20\x31\x34\x2e\x38\x32\x31\x34\x32\ -\x38\x2c\x33\x30\x2e\x39\x33\x33\x36\x30\x39\x20\x61\x20\x30\x2e\ -\x37\x31\x34\x32\x38\x35\x37\x33\x2c\x30\x2e\x37\x31\x34\x32\x38\ -\x35\x37\x33\x20\x30\x20\x31\x20\x31\x20\x2d\x31\x2e\x34\x32\x38\ -\x35\x37\x31\x2c\x30\x20\x30\x2e\x37\x31\x34\x32\x38\x35\x37\x33\ -\x2c\x30\x2e\x37\x31\x34\x32\x38\x35\x37\x33\x20\x30\x20\x31\x20\ -\x31\x20\x31\x2e\x34\x32\x38\x35\x37\x31\x2c\x30\x20\x7a\x22\x2f\ -\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x20\ -\x64\x3d\x22\x6d\x20\x32\x38\x2e\x35\x37\x31\x34\x32\x38\x2c\x31\ -\x36\x2e\x32\x30\x31\x34\x36\x36\x20\x61\x20\x32\x2e\x32\x33\x32\ -\x31\x34\x32\x39\x2c\x32\x2e\x32\x33\x32\x31\x34\x32\x39\x20\x30\ -\x20\x31\x20\x31\x20\x2d\x34\x2e\x34\x36\x34\x32\x38\x36\x2c\x30\ -\x20\x32\x2e\x32\x33\x32\x31\x34\x32\x39\x2c\x32\x2e\x32\x33\x32\ -\x31\x34\x32\x39\x20\x30\x20\x31\x20\x31\x20\x34\x2e\x34\x36\x34\ -\x32\x38\x36\x2c\x30\x20\x7a\x22\x2f\x3e\x0a\x20\x20\x20\x20\x20\ -\x20\x20\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x20\x36\x2e\ -\x32\x35\x30\x30\x30\x30\x32\x2c\x32\x30\x2e\x30\x38\x35\x33\x39\ -\x34\x20\x61\x20\x30\x2e\x34\x39\x31\x30\x37\x31\x34\x33\x2c\x30\ -\x2e\x34\x39\x31\x30\x37\x31\x34\x33\x20\x30\x20\x31\x20\x31\x20\ -\x2d\x30\x2e\x39\x38\x32\x31\x34\x32\x39\x2c\x30\x20\x30\x2e\x34\ -\x39\x31\x30\x37\x31\x34\x33\x2c\x30\x2e\x34\x39\x31\x30\x37\x31\ -\x34\x33\x20\x30\x20\x31\x20\x31\x20\x30\x2e\x39\x38\x32\x31\x34\ -\x32\x39\x2c\x30\x20\x7a\x22\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\ -\x20\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x20\x33\x34\x2e\ -\x37\x33\x32\x31\x34\x34\x2c\x32\x37\x2e\x35\x32\x37\x37\x32\x35\ -\x20\x61\x20\x30\x2e\x32\x36\x37\x38\x35\x37\x31\x33\x2c\x30\x2e\ -\x34\x33\x33\x34\x30\x31\x39\x37\x20\x30\x20\x31\x20\x31\x20\x2d\ -\x30\x2e\x35\x33\x35\x37\x31\x34\x2c\x30\x20\x30\x2e\x32\x36\x37\ -\x38\x35\x37\x31\x33\x2c\x30\x2e\x34\x33\x33\x34\x30\x31\x39\x37\ -\x20\x30\x20\x31\x20\x31\x20\x30\x2e\x35\x33\x35\x37\x31\x34\x2c\ -\x30\x20\x7a\x22\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\ -\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x20\x34\x30\x2e\x31\x37\x38\ -\x35\x37\x32\x2c\x39\x2e\x33\x37\x31\x31\x30\x38\x31\x20\x61\x20\ -\x30\x2e\x31\x33\x33\x39\x32\x38\x35\x37\x2c\x30\x2e\x32\x32\x33\ -\x32\x31\x34\x32\x38\x20\x30\x20\x31\x20\x31\x20\x2d\x30\x2e\x32\ -\x36\x37\x38\x35\x37\x2c\x30\x20\x30\x2e\x31\x33\x33\x39\x32\x38\ -\x35\x37\x2c\x30\x2e\x32\x32\x33\x32\x31\x34\x32\x38\x20\x30\x20\ -\x31\x20\x31\x20\x30\x2e\x32\x36\x37\x38\x35\x37\x2c\x30\x20\x7a\ -\x22\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\ -\x68\x20\x64\x3d\x22\x6d\x20\x34\x30\x2e\x39\x38\x32\x31\x34\x34\ -\x2c\x33\x38\x2e\x37\x34\x36\x31\x30\x39\x20\x61\x20\x30\x2e\x32\ -\x32\x33\x32\x31\x34\x32\x38\x2c\x30\x2e\x32\x32\x33\x32\x31\x34\ -\x32\x38\x20\x30\x20\x31\x20\x31\x20\x2d\x30\x2e\x34\x34\x36\x34\ -\x32\x38\x2c\x30\x20\x30\x2e\x32\x32\x33\x32\x31\x34\x32\x38\x2c\ -\x30\x2e\x32\x32\x33\x32\x31\x34\x32\x38\x20\x30\x20\x31\x20\x31\ -\x20\x30\x2e\x34\x34\x36\x34\x32\x38\x2c\x30\x20\x7a\x22\x2f\x3e\ -\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x20\x64\ -\x3d\x22\x6d\x20\x33\x31\x2e\x31\x36\x30\x37\x31\x35\x2c\x34\x30\ -\x2e\x35\x37\x36\x34\x36\x36\x20\x61\x20\x33\x2e\x39\x32\x38\x35\ -\x37\x31\x35\x2c\x33\x2e\x39\x32\x38\x35\x37\x31\x35\x20\x30\x20\ -\x31\x20\x31\x20\x2d\x37\x2e\x38\x35\x37\x31\x34\x33\x2c\x30\x20\ -\x33\x2e\x39\x32\x38\x35\x37\x31\x35\x2c\x33\x2e\x39\x32\x38\x35\ -\x37\x31\x35\x20\x30\x20\x31\x20\x31\x20\x37\x2e\x38\x35\x37\x31\ -\x34\x33\x2c\x30\x20\x7a\x22\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\ -\x20\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x20\x32\x32\x2e\ -\x32\x33\x32\x31\x34\x33\x2c\x33\x38\x2e\x32\x35\x35\x30\x33\x35\ -\x20\x61\x20\x31\x2e\x36\x30\x37\x31\x34\x32\x38\x2c\x31\x2e\x36\ -\x30\x37\x31\x34\x32\x38\x20\x30\x20\x31\x20\x31\x20\x2d\x33\x2e\ -\x32\x31\x34\x32\x38\x36\x2c\x30\x20\x31\x2e\x36\x30\x37\x31\x34\ -\x32\x38\x2c\x31\x2e\x36\x30\x37\x31\x34\x32\x38\x20\x30\x20\x31\ -\x20\x31\x20\x33\x2e\x32\x31\x34\x32\x38\x36\x2c\x30\x20\x7a\x22\ -\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\ -\x20\x64\x3d\x22\x6d\x20\x34\x31\x2e\x39\x36\x34\x32\x38\x37\x2c\ -\x31\x31\x2e\x36\x34\x37\x38\x39\x35\x20\x61\x20\x30\x2e\x38\x39\ -\x32\x38\x35\x37\x31\x33\x2c\x30\x2e\x38\x39\x32\x38\x35\x37\x31\ -\x33\x20\x30\x20\x31\x20\x31\x20\x2d\x31\x2e\x37\x38\x35\x37\x31\ -\x34\x2c\x30\x20\x30\x2e\x38\x39\x32\x38\x35\x37\x31\x33\x2c\x30\ -\x2e\x38\x39\x32\x38\x35\x37\x31\x33\x20\x30\x20\x31\x20\x31\x20\ -\x31\x2e\x37\x38\x35\x37\x31\x34\x2c\x30\x20\x7a\x22\x2f\x3e\x0a\ -\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\ -\x22\x6d\x20\x33\x36\x2e\x30\x37\x31\x34\x33\x2c\x32\x35\x2e\x37\ -\x35\x35\x30\x33\x37\x20\x61\x20\x30\x2e\x33\x35\x37\x31\x34\x32\ -\x38\x37\x2c\x30\x2e\x33\x35\x37\x31\x34\x32\x38\x37\x20\x30\x20\ -\x31\x20\x31\x20\x2d\x30\x2e\x37\x31\x34\x32\x38\x36\x2c\x30\x20\ -\x30\x2e\x33\x35\x37\x31\x34\x32\x38\x37\x2c\x30\x2e\x33\x35\x37\ -\x31\x34\x32\x38\x37\x20\x30\x20\x31\x20\x31\x20\x30\x2e\x37\x31\ -\x34\x32\x38\x36\x2c\x30\x20\x7a\x22\x2f\x3e\x0a\x20\x20\x20\x20\ -\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x20\x36\ -\x2e\x32\x35\x2c\x34\x32\x2e\x39\x38\x37\x31\x37\x39\x20\x61\x20\ -\x30\x2e\x36\x32\x35\x2c\x30\x2e\x36\x32\x35\x20\x30\x20\x31\x20\ -\x31\x20\x2d\x31\x2e\x32\x35\x2c\x30\x20\x30\x2e\x36\x32\x35\x2c\ -\x30\x2e\x36\x32\x35\x20\x30\x20\x31\x20\x31\x20\x31\x2e\x32\x35\ -\x2c\x30\x20\x7a\x22\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ -\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x20\x31\x37\x2e\x33\x32\ -\x31\x34\x32\x38\x2c\x31\x39\x2e\x39\x35\x31\x34\x36\x36\x20\x61\ -\x20\x31\x2e\x33\x33\x39\x32\x38\x35\x37\x2c\x31\x2e\x33\x33\x39\ -\x32\x38\x35\x37\x20\x30\x20\x31\x20\x31\x20\x2d\x32\x2e\x36\x37\ -\x38\x35\x37\x31\x2c\x30\x20\x31\x2e\x33\x33\x39\x32\x38\x35\x37\ -\x2c\x31\x2e\x33\x33\x39\x32\x38\x35\x37\x20\x30\x20\x31\x20\x31\ -\x20\x32\x2e\x36\x37\x38\x35\x37\x31\x2c\x30\x20\x7a\x22\x2f\x3e\ -\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x20\x64\ -\x3d\x22\x6d\x20\x31\x31\x2e\x39\x36\x34\x32\x38\x36\x2c\x31\x38\ -\x2e\x31\x36\x35\x37\x35\x32\x20\x61\x20\x30\x2e\x34\x34\x36\x34\ -\x32\x38\x35\x37\x2c\x30\x2e\x34\x34\x36\x34\x32\x38\x35\x37\x20\ -\x30\x20\x31\x20\x31\x20\x2d\x30\x2e\x38\x39\x32\x38\x35\x37\x2c\ -\x30\x20\x30\x2e\x34\x34\x36\x34\x32\x38\x35\x37\x2c\x30\x2e\x34\ -\x34\x36\x34\x32\x38\x35\x37\x20\x30\x20\x31\x20\x31\x20\x30\x2e\ -\x38\x39\x32\x38\x35\x37\x2c\x30\x20\x7a\x22\x2f\x3e\x0a\x20\x20\ -\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\ -\x20\x31\x36\x2e\x36\x30\x37\x31\x34\x33\x2c\x37\x2e\x38\x39\x37\ -\x38\x39\x34\x39\x20\x61\x20\x30\x2e\x35\x33\x35\x37\x31\x34\x32\ -\x37\x2c\x30\x2e\x35\x33\x35\x37\x31\x34\x32\x37\x20\x30\x20\x31\ -\x20\x31\x20\x2d\x31\x2e\x30\x37\x31\x34\x32\x39\x2c\x30\x20\x30\ -\x2e\x35\x33\x35\x37\x31\x34\x32\x37\x2c\x30\x2e\x35\x33\x35\x37\ -\x31\x34\x32\x37\x20\x30\x20\x31\x20\x31\x20\x31\x2e\x30\x37\x31\ -\x34\x32\x39\x2c\x30\x20\x7a\x22\x2f\x3e\x0a\x20\x20\x20\x20\x20\ -\x20\x3c\x2f\x67\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x70\x61\x74\x74\ -\x65\x72\x6e\x3e\x0a\x20\x20\x3c\x2f\x64\x65\x66\x73\x3e\x0a\x3c\ -\x2f\x73\x76\x67\x3e\ +\x00\x00\x06\x9d\ +\x00\ +\x00\x1d\xe0\x78\x9c\xbd\x59\x5d\xaf\x9b\x38\x10\x7d\xef\xaf\x40\ +\xf4\xa5\xab\x25\xc6\x5f\x80\xc9\x26\xb7\x2f\xd5\x4a\xfb\xb4\xd2\ +\xb6\xd5\x3e\x73\xc1\x37\x61\x9b\x40\x04\xe4\x26\xe9\xaf\xdf\xb1\ +\xc1\x40\x08\x64\x91\xb2\x4a\xaa\x56\xf6\xf8\x80\x8f\x67\xe6\x0c\ +\x63\x75\xf5\xf9\xbc\xdf\x59\xef\xb2\x28\xd3\x3c\x5b\xdb\x04\x61\ +\xdb\x92\x59\x9c\x27\x69\xb6\x59\xdb\xdf\xbf\xfd\xbe\x10\xb6\x55\ +\x56\x51\x96\x44\xbb\x3c\x93\x6b\x3b\xcb\xed\xcf\x2f\x1f\x56\xe5\ +\xfb\xe6\x83\x65\x59\xf0\x70\x56\x2e\x93\x78\x6d\x6f\xab\xea\xb0\ +\x74\xdd\xc3\xb1\xd8\xa1\xbc\xd8\xb8\x49\xec\xca\x9d\xdc\xcb\xac\ +\x2a\x5d\x82\x88\x6b\x77\xf0\xb8\x83\xc7\x85\x8c\xaa\xf4\x5d\xc6\ +\xf9\x7e\x9f\x67\xa5\x7e\x32\x2b\x3f\xf6\xc0\x45\xf2\xd6\xa2\x4f\ +\xa7\x13\x3a\x31\x0d\x22\x61\x18\xba\x98\xba\x94\x2e\x00\xb1\x28\ +\x2f\x59\x15\x9d\x17\xd7\x8f\x02\xc7\xb1\x47\x29\xc6\xd8\x85\xb5\ +\x0e\x39\x0f\xb5\x2c\xc1\x2b\x07\xf8\xdb\xc2\x8d\x01\x95\xf9\xb1\ +\x88\xe5\x1b\x3c\x27\x51\x26\x2b\xf7\xcb\xb7\x2f\xed\xe2\x02\xa3\ +\xa4\x4a\x7a\xaf\x49\xb3\x1f\x65\x1c\x1d\xe4\xd5\xae\xc6\x58\x7b\ +\x20\xda\xcb\xf2\x10\xc5\xb2\x74\x8d\x5d\x3f\x9f\x26\x6b\x1b\x28\ +\x31\x21\xb0\x9e\xf7\xc2\x46\x6a\x40\x83\x5e\xb6\x2b\x18\x71\x81\ +\x18\x22\x56\x11\x0a\xe1\x6b\xd0\x29\x4d\xaa\xed\xda\xf6\xb9\x9e\ +\x6d\x65\xba\xd9\x56\xed\xd4\xb0\x5e\x26\x79\xac\x68\xac\xed\x38\ +\xcf\x20\x4a\x95\x44\xca\x19\x2f\x80\x59\xed\x65\x15\x25\x51\x15\ +\x29\x7c\x4d\xca\x58\x58\x48\xb1\xc6\x00\x0a\xc2\xb2\xfc\xeb\xcb\ +\xef\xf5\x0c\xe6\x71\xbc\xfc\x3b\x2f\x7e\x34\x53\xf8\x29\x40\xf4\ +\x9a\x1f\x61\x73\xfb\xa5\x35\xaf\x92\x78\x09\x8e\xdc\x47\xd5\x4b\ +\xba\x8f\x36\x52\xc5\xe0\x57\x70\xdc\xca\xed\x16\xae\xc0\xd5\xe5\ +\x20\xbb\x97\xd6\xaf\x2d\x64\x1d\x91\xd1\xb4\x4c\xe2\x7d\xaa\x1e\ +\x72\xbf\x56\xe9\x6e\xf7\x87\xda\xc4\xb6\xdc\x96\xa7\xdb\x10\x6d\ +\x8e\xe1\xf6\xce\xb1\x72\xcd\x41\xf5\xac\xf5\x95\x72\x54\xf2\x9e\ +\xca\x53\xfd\x8e\x03\xbc\x31\xce\x77\x79\xb1\xb6\x3f\xbe\xe9\x9f\ +\x5d\x2f\xbc\xe6\x45\x22\x0b\xb3\xe4\xeb\xdf\xd5\x52\x0e\x41\x07\ +\x6e\x10\xd0\xc6\x9c\xbf\xfe\x23\xe3\xaa\xca\x77\xb2\x88\x32\x75\ +\x1e\x82\x9b\x95\x4d\x01\x61\x1c\xb3\x1f\xd3\x44\x8e\x2d\xb4\xb9\ +\xa1\xe8\xb5\x1b\x8d\xae\x96\xdb\x28\xc9\x4f\x6b\x9b\x0e\x17\x4f\ +\x69\x06\x0b\x8b\x26\x83\x88\x8a\xf6\x38\xc2\x64\x15\xc1\x5e\x60\ +\x77\x79\xd2\x3a\x8a\x85\x44\x34\xf6\x72\x9b\x9f\xd4\x61\xd6\x76\ +\x55\x1c\xe5\xf0\x7d\x65\x16\x1d\x16\x59\x9e\x48\x10\xe9\x5b\xb4\ +\x2b\x6f\x00\x3f\xf3\x7c\xbf\xb6\x3d\x84\x03\xce\x7c\xcf\x1b\x2e\ +\xc7\x67\x58\x04\x05\x10\xcc\x04\xbf\x59\x04\x07\xf8\x08\x33\xee\ +\x13\x41\x26\x4e\x72\x1e\xf1\x51\xb3\x34\xe6\xbe\x66\x69\x1f\x9d\ +\xd3\x7d\xfa\x53\x26\x5d\x28\xbb\x5d\x8f\x45\x01\x65\x71\xb1\x8b\ +\x2e\xb2\xe8\x04\xdd\xe4\x5b\x0b\x53\x3e\x31\x79\xad\xd2\x75\x6d\ +\x9f\x2f\xca\x66\x1b\xa3\x72\x99\x32\x80\xe8\x68\x6b\x94\xfb\x83\ +\xaa\x1c\xba\x7a\x7b\xad\xf5\x3d\x2d\xd3\xd7\x9d\xbc\x72\x31\x60\ +\xb3\x08\x8c\xc9\xc0\xaa\x3c\xde\xe0\xd5\xdb\x77\x69\x06\x62\xca\ +\x76\x97\x21\xac\xde\x05\xdc\x23\x0e\xe7\xa1\xf5\x52\x5b\x6b\x55\ +\xad\xdc\x5b\xa1\x68\x7b\x22\xdf\xca\x2e\x37\xd4\x0c\x1c\x41\x8d\ +\x23\x0e\x51\x55\xc9\x22\xeb\x9f\xd6\x94\xa2\x76\xbb\x06\xf3\x3d\ +\x4b\x2b\xc8\x8f\x63\x29\x8b\xaf\xaa\x6c\xfe\x99\x7d\x2f\x3b\x50\ +\x2f\x82\x96\x75\xe9\x4f\x9a\x3c\x46\x9d\xa3\x4c\xde\x82\xa9\x2d\ +\x08\x9b\xae\xba\x94\xd5\x45\x79\xf1\x0d\xea\xc6\x32\x83\xcf\xe1\ +\x6f\x60\x29\xf2\x1f\x72\xf9\x11\xeb\x9f\x99\xd7\x0a\x59\xf6\x5e\ +\x0c\x31\x04\x41\x96\xaa\x80\x41\xc8\xe3\x68\x27\x3f\x21\x4c\x7e\ +\xe9\xad\xeb\x70\x32\x8e\x49\xbf\x18\xc2\x01\xb7\xfd\xe2\xa6\x6a\ +\xad\xe5\x21\xe6\x05\x84\x53\xe1\x30\xe4\x51\x2a\x42\xee\x5b\x91\ +\x45\x10\x83\x4c\x10\x5e\xe0\xb4\x23\x0b\x5b\x04\xfe\x2c\x28\xf2\ +\x03\x98\x12\xcf\xc1\x77\x60\x7d\xd4\x4f\xbb\xbf\xab\xa2\xa6\x98\ +\x30\xf5\x09\xe9\x4a\xe5\x14\x3f\xc2\x11\xc1\x40\x90\x39\x3e\x12\ +\xd4\xe7\xbe\x4f\x80\x1f\x43\x54\x71\xf6\x7c\xa7\x1d\x19\x7e\x3e\ +\x52\xd3\x80\x10\xd8\x79\x1a\xd6\x47\x4d\xf2\x13\xf3\xf8\x09\x5a\ +\xfb\x0f\xa3\x90\x31\x1f\x87\xc0\x0f\x23\xed\x53\x2f\x60\x4e\x37\ +\x34\x0c\x49\xb3\x37\x6c\x7d\x0f\xd7\x83\x4d\x31\x0c\xf1\x0c\x86\ +\x54\xa0\x26\xc2\xc4\x47\x14\x13\x70\x21\x30\xa4\x88\x32\xc5\x3b\ +\x74\xda\x91\xe1\xc7\x11\xf7\x01\xee\xc3\xc6\xd3\xa8\x1e\x68\x92\ +\x1d\x9d\xc1\x0e\x28\x79\x2a\xdb\xa9\x43\x31\xc2\xc2\x63\x21\xd7\ +\xfe\xe3\x61\x13\xf6\x6e\x68\xf8\x81\x9f\x45\x4d\x0a\xdf\x05\xf6\ +\x71\x93\x1c\xf9\x0c\x8e\x8c\xa3\x40\x1d\x9e\x3b\x34\x00\x91\x04\ +\x01\xf5\x34\x47\x5a\xe7\xb8\xde\x9a\x29\xb5\x85\x41\xc7\xd1\xd3\ +\xba\xd2\x14\xa7\x71\x3d\xd8\x24\xc3\x39\x2a\xe1\x18\x11\xb5\x07\ +\x75\x42\xc4\x20\xab\xb1\x20\x9a\x21\x31\xfa\x04\x12\x75\xfc\x44\ +\xc7\xb0\xa6\xa5\x19\x4e\xe3\x7a\xb0\x49\x86\x73\x74\xc2\x9b\x68\ +\x70\x87\x09\x14\xc0\x47\xb2\xd1\x89\xd9\x6e\x94\x21\xd7\x39\x56\ +\xfb\x70\x12\xd7\x83\x4d\x30\x0c\xf1\x1c\x9d\x30\x68\x7c\x7d\xac\ +\x4a\x16\x70\xf5\x02\xbf\xd6\x09\x43\xda\x31\x60\x6d\x47\x86\x5f\ +\x80\xd4\x54\x65\xde\x1d\x54\x0f\x34\xc9\x6e\x8e\x4e\x68\x23\x40\ +\xa6\xfc\x47\x3d\x0f\x33\x4f\xd7\x69\xc5\x58\x6b\xdb\x8c\x0c\xbb\ +\xa6\xe2\xf9\xba\x4c\x4f\xa1\x7a\xa0\x49\x76\x73\x14\xc2\x09\x0a\ +\x55\x0c\xe0\x43\x00\x5b\xf0\x40\x84\xb5\x42\x44\xed\x0c\x95\xf9\ +\x66\xd8\x55\x41\x2d\x8a\x5a\x21\xd3\xb8\x1e\x6c\x92\xe1\x1c\x85\ +\x30\xe8\xcd\x74\x1c\xa8\x87\x02\xe5\xbe\x40\x13\x6c\x3e\x7e\x2a\ +\xf1\xcd\xb0\x4b\xbf\xc0\xf8\xe6\x1e\xae\x07\x9b\x24\x38\x47\x20\ +\xaa\x10\x3a\x9c\x82\x4a\x02\x12\xd4\xda\xf0\xc1\xa2\xff\xed\x7c\ +\xa6\x2c\x23\x2b\xcd\xc2\x14\x01\x32\x27\xff\x49\x80\x1a\x89\x91\ +\x10\x85\x5e\xf3\x9d\x98\xd1\x09\xcc\x6a\x04\xee\xb1\x9b\x93\xff\ +\xa4\xc9\x30\xdf\x21\x02\x74\xea\x05\x1e\xad\xbf\x13\x5a\xfb\xba\ +\x72\x99\x61\x17\x40\xd1\x14\xb5\xbb\xb8\x1e\x6c\x92\xe1\x1c\x0d\ +\xc0\xd7\xd5\xaf\x53\x0c\x34\x1f\x82\x04\x78\x1d\xc5\xba\xc2\x53\ +\xb5\xb3\x19\x76\xf1\xd4\x6a\xac\x3f\x64\xd3\xb8\x1e\x6c\x92\xa1\ +\x7f\x75\xed\xdc\x98\x0b\x67\xd3\xd4\xd6\xad\xb3\xea\x8a\xf5\x68\ +\xd3\x75\xca\x1b\x8e\x43\xd3\xf1\xf7\xba\x4a\xb8\x19\x17\xe9\xf9\ +\x13\xf4\x20\x1e\x87\x0b\x05\x75\x30\xfc\x59\x74\x53\x70\x2e\x5c\ +\x83\x38\x55\x7d\x19\x08\x0a\x8a\x25\x0f\x4c\x03\x7a\xd3\xd8\x0e\ +\xfa\xda\xab\xb6\x16\xb7\xdd\xf1\x95\x57\xcd\xc9\x80\x1d\x6f\x8f\ +\xfc\xfc\x86\xb5\xbb\x67\xe5\x59\x06\x97\xe7\xbc\x58\xc0\x8d\xeb\ +\x3d\xaa\x8e\x85\x54\xcd\xbf\xf1\xf9\x14\x77\xff\x9a\xfb\x53\x9b\ +\xd9\x47\xb9\x8b\x1b\xee\xcf\x6c\x74\x1f\x63\x4f\x30\xbe\x66\x7f\ +\xb7\x09\x66\xa6\xbb\x65\xd3\x2d\xf0\x0d\x66\xb4\x01\x7e\x94\x35\ +\xbd\x66\xfd\x1f\xcd\xb1\xd7\xf5\xbc\xde\xdd\xe6\x78\x04\x38\xde\ +\x1c\x3f\xca\x7f\xa0\xd5\x27\x37\xce\x8f\xb2\x1f\xa8\xf5\xc9\x4d\ +\xf5\xa3\xec\xc5\x0d\xfb\x67\x36\xdc\x0f\xb2\x27\x03\xbd\x3e\xb1\ +\x19\x7f\x94\xf9\x40\xb3\x77\x1b\x75\x66\x3a\x70\x36\xdd\xa6\xdf\ +\x60\x46\x9b\xf4\x47\x59\x0f\x94\xfa\xe4\x06\xfe\x51\xf6\x03\xa5\ +\xde\x6b\xee\x99\x69\xd9\xd9\x74\x63\x7f\x83\x19\x6d\xea\x1f\x25\ +\x2d\x6e\x8b\xfb\xff\xd7\xf0\x3f\x48\x8e\x0e\xf4\xf7\xc4\xcb\xc0\ +\xa3\xcc\x07\xfa\x7b\xf2\x45\xe1\x51\xf6\x03\x1d\xde\xbf\x44\x78\ +\xed\xdd\xc0\xbb\x73\x85\xb8\x45\x8d\x5e\x20\xe6\x31\xd7\x77\x89\ +\x95\xfa\x8f\xb3\x97\x0f\xff\x02\x89\x44\xf7\x33\ \x00\x00\xce\xfd\ \x3c\ \xb8\x64\x18\xca\xef\x9c\x95\xcd\x21\x1c\xbf\x60\xa1\xbd\xdd\x42\ @@ -53441,92 +53633,92 @@ qt_resource_struct = "\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x38\x00\x00\x00\x21\ \x00\x00\x00\x38\x00\x02\x00\x00\x00\x05\x00\x00\x00\x1c\ \x00\x00\x00\x1a\x00\x02\x00\x00\x00\x17\x00\x00\x00\x05\ -\x00\x00\x01\xb4\x00\x01\x00\x00\x00\x01\x00\x04\x07\x01\ -\x00\x00\x03\x00\x00\x01\x00\x00\x00\x01\x00\x08\x8d\xc4\ -\x00\x00\x02\xde\x00\x01\x00\x00\x00\x01\x00\x08\x50\xd6\ -\x00\x00\x02\x68\x00\x01\x00\x00\x00\x01\x00\x06\x54\x1b\ -\x00\x00\x03\x3e\x00\x01\x00\x00\x00\x01\x00\x09\x08\xd8\ -\x00\x00\x01\x06\x00\x01\x00\x00\x00\x01\x00\x01\xaf\xc8\ -\x00\x00\x01\x7c\x00\x01\x00\x00\x00\x01\x00\x02\xf2\x43\ -\x00\x00\x02\x4c\x00\x01\x00\x00\x00\x01\x00\x06\x17\x08\ -\x00\x00\x02\x8a\x00\x00\x00\x00\x00\x01\x00\x06\x90\x01\ -\x00\x00\x03\x5a\x00\x00\x00\x00\x00\x01\x00\x09\x46\x01\ -\x00\x00\x01\xd6\x00\x01\x00\x00\x00\x01\x00\x04\x44\xcb\ -\x00\x00\x00\xea\x00\x00\x00\x00\x00\x01\x00\x00\xe0\x7f\ -\x00\x00\x01\x60\x00\x01\x00\x00\x00\x01\x00\x02\xb5\xdc\ -\x00\x00\x02\x30\x00\x01\x00\x00\x00\x01\x00\x05\xd9\x2b\ -\x00\x00\x02\xc2\x00\x00\x00\x00\x00\x01\x00\x07\x9c\xd3\ -\x00\x00\x03\x22\x00\x01\x00\x00\x00\x01\x00\x08\xcb\xab\ -\x00\x00\x02\xa6\x00\x01\x00\x00\x00\x01\x00\x07\x5f\x4e\ -\x00\x00\x00\xce\x00\x00\x00\x00\x00\x01\x00\x00\x11\x7e\ -\x00\x00\x01\x22\x00\x01\x00\x00\x00\x01\x00\x01\xec\x1e\ -\x00\x00\x01\x98\x00\x00\x00\x00\x00\x01\x00\x03\x31\x8e\ -\x00\x00\x02\x14\x00\x00\x00\x00\x00\x01\x00\x05\x0d\xd0\ -\x00\x00\x01\x3e\x00\x00\x00\x00\x00\x01\x00\x02\x2b\x1d\ -\x00\x00\x01\xf2\x00\x00\x00\x00\x00\x01\x00\x04\x83\x3b\ +\x00\x00\x01\xb4\x00\x01\x00\x00\x00\x01\x00\x04\x13\x04\ +\x00\x00\x03\x00\x00\x01\x00\x00\x00\x01\x00\x08\x99\xc7\ +\x00\x00\x02\xde\x00\x01\x00\x00\x00\x01\x00\x08\x5c\xd9\ +\x00\x00\x02\x68\x00\x01\x00\x00\x00\x01\x00\x06\x60\x1e\ +\x00\x00\x03\x3e\x00\x01\x00\x00\x00\x01\x00\x09\x14\xdb\ +\x00\x00\x01\x06\x00\x01\x00\x00\x00\x01\x00\x01\xbb\xcb\ +\x00\x00\x01\x7c\x00\x01\x00\x00\x00\x01\x00\x02\xfe\x46\ +\x00\x00\x02\x4c\x00\x01\x00\x00\x00\x01\x00\x06\x23\x0b\ +\x00\x00\x02\x8a\x00\x00\x00\x00\x00\x01\x00\x06\x9c\x04\ +\x00\x00\x03\x5a\x00\x00\x00\x00\x00\x01\x00\x09\x52\x04\ +\x00\x00\x01\xd6\x00\x01\x00\x00\x00\x01\x00\x04\x50\xce\ +\x00\x00\x00\xea\x00\x00\x00\x00\x00\x01\x00\x00\xec\x82\ +\x00\x00\x01\x60\x00\x01\x00\x00\x00\x01\x00\x02\xc1\xdf\ +\x00\x00\x02\x30\x00\x01\x00\x00\x00\x01\x00\x05\xe5\x2e\ +\x00\x00\x02\xc2\x00\x00\x00\x00\x00\x01\x00\x07\xa8\xd6\ +\x00\x00\x03\x22\x00\x01\x00\x00\x00\x01\x00\x08\xd7\xae\ +\x00\x00\x02\xa6\x00\x01\x00\x00\x00\x01\x00\x07\x6b\x51\ +\x00\x00\x00\xce\x00\x00\x00\x00\x00\x01\x00\x00\x1d\x81\ +\x00\x00\x01\x22\x00\x01\x00\x00\x00\x01\x00\x01\xf8\x21\ +\x00\x00\x01\x98\x00\x00\x00\x00\x00\x01\x00\x03\x3d\x91\ +\x00\x00\x02\x14\x00\x00\x00\x00\x00\x01\x00\x05\x19\xd3\ +\x00\x00\x01\x3e\x00\x00\x00\x00\x00\x01\x00\x02\x37\x20\ +\x00\x00\x01\xf2\x00\x00\x00\x00\x00\x01\x00\x04\x8f\x3e\ \x00\x00\x00\x4e\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x01\x00\x00\x08\xa4\ -\x00\x00\x00\x64\x00\x00\x00\x00\x00\x01\x00\x00\x01\x64\ -\x00\x00\x00\x96\x00\x01\x00\x00\x00\x01\x00\x00\x04\xc4\ -\x00\x00\x00\x7c\x00\x00\x00\x00\x00\x01\x00\x00\x03\x12\ -\x00\x00\x06\xce\x00\x01\x00\x00\x00\x01\x00\x0a\xfb\x31\ -\x00\x00\x04\x7c\x00\x00\x00\x00\x00\x01\x00\x0a\x58\x1a\ -\x00\x00\x09\x34\x00\x01\x00\x00\x00\x01\x00\x0b\xd2\x27\ -\x00\x00\x0b\xc4\x00\x01\x00\x00\x00\x01\x00\x0c\xae\x32\ -\x00\x00\x05\x86\x00\x01\x00\x00\x00\x01\x00\x0a\x97\xc5\ -\x00\x00\x07\x16\x00\x00\x00\x00\x00\x01\x00\x0b\x18\x7b\ -\x00\x00\x08\x2a\x00\x01\x00\x00\x00\x01\x00\x0b\x81\x29\ -\x00\x00\x0b\x26\x00\x01\x00\x00\x00\x01\x00\x0c\x84\xef\ -\x00\x00\x07\x8a\x00\x00\x00\x00\x00\x01\x00\x0b\x42\x4a\ -\x00\x00\x09\xce\x00\x01\x00\x00\x00\x01\x00\x0c\x12\xc8\ -\x00\x00\x0c\x14\x00\x01\x00\x00\x00\x01\x00\x0c\xca\x56\ -\x00\x00\x04\xc2\x00\x01\x00\x00\x00\x01\x00\x0a\x71\x3c\ -\x00\x00\x08\xdc\x00\x00\x00\x00\x00\x01\x00\x0b\xaf\xcd\ -\x00\x00\x08\x50\x00\x01\x00\x00\x00\x01\x00\x0b\x86\xed\ -\x00\x00\x06\xf0\x00\x00\x00\x00\x00\x01\x00\x0b\x05\xe5\ -\x00\x00\x04\xe6\x00\x01\x00\x00\x00\x01\x00\x0a\x76\xbb\ -\x00\x00\x07\x5e\x00\x01\x00\x00\x00\x01\x00\x0b\x31\x40\ -\x00\x00\x04\x9e\x00\x01\x00\x00\x00\x01\x00\x0a\x66\xd0\ -\x00\x00\x0b\x4e\x00\x00\x00\x00\x00\x01\x00\x0c\x90\x5e\ -\x00\x00\x03\xfc\x00\x01\x00\x00\x00\x01\x00\x0a\x32\x88\ -\x00\x00\x05\xd6\x00\x01\x00\x00\x00\x01\x00\x0a\xb2\xe4\ -\x00\x00\x0a\xde\x00\x01\x00\x00\x00\x01\x00\x0c\x6d\xc0\ -\x00\x00\x0b\x00\x00\x01\x00\x00\x00\x01\x00\x0c\x7b\x5b\ -\x00\x00\x05\xb4\x00\x00\x00\x00\x00\x01\x00\x0a\xa0\xcb\ -\x00\x00\x03\xca\x00\x01\x00\x00\x00\x01\x00\x0a\x2a\xcf\ -\x00\x00\x08\xba\x00\x01\x00\x00\x00\x01\x00\x0b\xa8\x79\ -\x00\x00\x0a\x28\x00\x00\x00\x00\x00\x01\x00\x0c\x23\x10\ -\x00\x00\x06\x2a\x00\x01\x00\x00\x00\x01\x00\x0a\xc4\x54\ -\x00\x00\x0a\x4c\x00\x00\x00\x00\x00\x01\x00\x0c\x39\xc3\ -\x00\x00\x07\xe4\x00\x00\x00\x00\x00\x01\x00\x0b\x59\xfd\ -\x00\x00\x05\x38\x00\x01\x00\x00\x00\x01\x00\x0a\x86\xbb\ -\x00\x00\x0b\xe4\x00\x00\x00\x00\x00\x01\x00\x0c\xb8\xe0\ -\x00\x00\x06\x84\x00\x00\x00\x00\x00\x01\x00\x0a\xdb\x93\ -\x00\x00\x04\x28\x00\x00\x00\x00\x00\x01\x00\x0a\x3a\x8f\ -\x00\x00\x0c\x44\x00\x00\x00\x00\x00\x01\x00\x0c\xd6\x2f\ -\x00\x00\x0a\x94\x00\x00\x00\x00\x00\x01\x00\x0c\x57\x4a\ -\x00\x00\x04\x4c\x00\x01\x00\x00\x00\x01\x00\x0a\x4f\xaf\ -\x00\x00\x0a\xbc\x00\x01\x00\x00\x00\x01\x00\x0c\x66\x71\ -\x00\x00\x09\x56\x00\x01\x00\x00\x00\x01\x00\x0b\xda\xd0\ -\x00\x00\x0b\x74\x00\x01\x00\x00\x00\x01\x00\x0c\x98\xeb\ -\x00\x00\x06\xac\x00\x01\x00\x00\x00\x01\x00\x0a\xed\xd2\ -\x00\x00\x07\xbc\x00\x01\x00\x00\x00\x01\x00\x0b\x50\x4c\ -\x00\x00\x09\xac\x00\x00\x00\x00\x00\x01\x00\x0b\xfe\x37\ -\x00\x00\x05\x5c\x00\x01\x00\x00\x00\x01\x00\x0a\x8d\x84\ -\x00\x00\x08\x0a\x00\x00\x00\x00\x00\x01\x00\x0b\x6b\xb5\ -\x00\x00\x06\x0a\x00\x01\x00\x00\x00\x01\x00\x0a\xbe\xd5\ -\x00\x00\x09\xf8\x00\x01\x00\x00\x00\x01\x00\x0c\x19\x3d\ -\x00\x00\x08\x92\x00\x01\x00\x00\x00\x01\x00\x0b\x9d\x07\ -\x00\x00\x09\x0c\x00\x01\x00\x00\x00\x01\x00\x0b\xc2\x51\ -\x00\x00\x0b\x9a\x00\x01\x00\x00\x00\x01\x00\x0c\xa3\xb0\ -\x00\x00\x0a\x70\x00\x01\x00\x00\x00\x01\x00\x0c\x4c\x9a\ -\x00\x00\x05\x08\x00\x01\x00\x00\x00\x01\x00\x0a\x7e\x99\ -\x00\x00\x08\x72\x00\x00\x00\x00\x00\x01\x00\x0b\x8d\x35\ -\x00\x00\x06\x58\x00\x00\x00\x00\x00\x01\x00\x0a\xcc\x39\ -\x00\x00\x07\x3e\x00\x01\x00\x00\x00\x01\x00\x0b\x27\xcc\ -\x00\x00\x09\x7a\x00\x00\x00\x00\x00\x01\x00\x0b\xe2\x21\ -\x00\x00\x03\x76\x00\x01\x00\x00\x00\x01\x00\x0a\x10\x52\ -\x00\x00\x03\xa2\x00\x01\x00\x00\x00\x01\x00\x0a\x1a\x0b\ +\x00\x00\x00\xb0\x00\x01\x00\x00\x00\x01\x00\x00\x16\xe0\ +\x00\x00\x00\x64\x00\x01\x00\x00\x00\x01\x00\x00\x0a\xf1\ +\x00\x00\x00\x96\x00\x01\x00\x00\x00\x01\x00\x00\x13\x00\ +\x00\x00\x00\x7c\x00\x01\x00\x00\x00\x01\x00\x00\x0f\x23\ +\x00\x00\x06\xce\x00\x01\x00\x00\x00\x01\x00\x0b\x07\x34\ +\x00\x00\x04\x7c\x00\x00\x00\x00\x00\x01\x00\x0a\x64\x1d\ +\x00\x00\x09\x34\x00\x01\x00\x00\x00\x01\x00\x0b\xde\x2a\ +\x00\x00\x0b\xc4\x00\x01\x00\x00\x00\x01\x00\x0c\xba\x35\ +\x00\x00\x05\x86\x00\x01\x00\x00\x00\x01\x00\x0a\xa3\xc8\ +\x00\x00\x07\x16\x00\x00\x00\x00\x00\x01\x00\x0b\x24\x7e\ +\x00\x00\x08\x2a\x00\x01\x00\x00\x00\x01\x00\x0b\x8d\x2c\ +\x00\x00\x0b\x26\x00\x01\x00\x00\x00\x01\x00\x0c\x90\xf2\ +\x00\x00\x07\x8a\x00\x00\x00\x00\x00\x01\x00\x0b\x4e\x4d\ +\x00\x00\x09\xce\x00\x01\x00\x00\x00\x01\x00\x0c\x1e\xcb\ +\x00\x00\x0c\x14\x00\x01\x00\x00\x00\x01\x00\x0c\xd6\x59\ +\x00\x00\x04\xc2\x00\x01\x00\x00\x00\x01\x00\x0a\x7d\x3f\ +\x00\x00\x08\xdc\x00\x00\x00\x00\x00\x01\x00\x0b\xbb\xd0\ +\x00\x00\x08\x50\x00\x01\x00\x00\x00\x01\x00\x0b\x92\xf0\ +\x00\x00\x06\xf0\x00\x00\x00\x00\x00\x01\x00\x0b\x11\xe8\ +\x00\x00\x04\xe6\x00\x01\x00\x00\x00\x01\x00\x0a\x82\xbe\ +\x00\x00\x07\x5e\x00\x01\x00\x00\x00\x01\x00\x0b\x3d\x43\ +\x00\x00\x04\x9e\x00\x01\x00\x00\x00\x01\x00\x0a\x72\xd3\ +\x00\x00\x0b\x4e\x00\x00\x00\x00\x00\x01\x00\x0c\x9c\x61\ +\x00\x00\x03\xfc\x00\x01\x00\x00\x00\x01\x00\x0a\x3e\x8b\ +\x00\x00\x05\xd6\x00\x01\x00\x00\x00\x01\x00\x0a\xbe\xe7\ +\x00\x00\x0a\xde\x00\x01\x00\x00\x00\x01\x00\x0c\x79\xc3\ +\x00\x00\x0b\x00\x00\x01\x00\x00\x00\x01\x00\x0c\x87\x5e\ +\x00\x00\x05\xb4\x00\x00\x00\x00\x00\x01\x00\x0a\xac\xce\ +\x00\x00\x03\xca\x00\x01\x00\x00\x00\x01\x00\x0a\x36\xd2\ +\x00\x00\x08\xba\x00\x01\x00\x00\x00\x01\x00\x0b\xb4\x7c\ +\x00\x00\x0a\x28\x00\x00\x00\x00\x00\x01\x00\x0c\x2f\x13\ +\x00\x00\x06\x2a\x00\x01\x00\x00\x00\x01\x00\x0a\xd0\x57\ +\x00\x00\x0a\x4c\x00\x00\x00\x00\x00\x01\x00\x0c\x45\xc6\ +\x00\x00\x07\xe4\x00\x00\x00\x00\x00\x01\x00\x0b\x66\x00\ +\x00\x00\x05\x38\x00\x01\x00\x00\x00\x01\x00\x0a\x92\xbe\ +\x00\x00\x0b\xe4\x00\x00\x00\x00\x00\x01\x00\x0c\xc4\xe3\ +\x00\x00\x06\x84\x00\x00\x00\x00\x00\x01\x00\x0a\xe7\x96\ +\x00\x00\x04\x28\x00\x00\x00\x00\x00\x01\x00\x0a\x46\x92\ +\x00\x00\x0c\x44\x00\x00\x00\x00\x00\x01\x00\x0c\xe2\x32\ +\x00\x00\x0a\x94\x00\x00\x00\x00\x00\x01\x00\x0c\x63\x4d\ +\x00\x00\x04\x4c\x00\x01\x00\x00\x00\x01\x00\x0a\x5b\xb2\ +\x00\x00\x0a\xbc\x00\x01\x00\x00\x00\x01\x00\x0c\x72\x74\ +\x00\x00\x09\x56\x00\x01\x00\x00\x00\x01\x00\x0b\xe6\xd3\ +\x00\x00\x0b\x74\x00\x01\x00\x00\x00\x01\x00\x0c\xa4\xee\ +\x00\x00\x06\xac\x00\x01\x00\x00\x00\x01\x00\x0a\xf9\xd5\ +\x00\x00\x07\xbc\x00\x01\x00\x00\x00\x01\x00\x0b\x5c\x4f\ +\x00\x00\x09\xac\x00\x00\x00\x00\x00\x01\x00\x0c\x0a\x3a\ +\x00\x00\x05\x5c\x00\x01\x00\x00\x00\x01\x00\x0a\x99\x87\ +\x00\x00\x08\x0a\x00\x00\x00\x00\x00\x01\x00\x0b\x77\xb8\ +\x00\x00\x06\x0a\x00\x01\x00\x00\x00\x01\x00\x0a\xca\xd8\ +\x00\x00\x09\xf8\x00\x01\x00\x00\x00\x01\x00\x0c\x25\x40\ +\x00\x00\x08\x92\x00\x01\x00\x00\x00\x01\x00\x0b\xa9\x0a\ +\x00\x00\x09\x0c\x00\x01\x00\x00\x00\x01\x00\x0b\xce\x54\ +\x00\x00\x0b\x9a\x00\x01\x00\x00\x00\x01\x00\x0c\xaf\xb3\ +\x00\x00\x0a\x70\x00\x01\x00\x00\x00\x01\x00\x0c\x58\x9d\ +\x00\x00\x05\x08\x00\x01\x00\x00\x00\x01\x00\x0a\x8a\x9c\ +\x00\x00\x08\x72\x00\x00\x00\x00\x00\x01\x00\x0b\x99\x38\ +\x00\x00\x06\x58\x00\x00\x00\x00\x00\x01\x00\x0a\xd8\x3c\ +\x00\x00\x07\x3e\x00\x01\x00\x00\x00\x01\x00\x0b\x33\xcf\ +\x00\x00\x09\x7a\x00\x00\x00\x00\x00\x01\x00\x0b\xee\x24\ +\x00\x00\x03\x76\x00\x01\x00\x00\x00\x01\x00\x0a\x1c\x55\ +\x00\x00\x03\xa2\x00\x01\x00\x00\x00\x01\x00\x0a\x26\x0e\ " def qInitResources(): diff --git a/src/Mod/Draft/Resources/patterns/concrete.svg b/src/Mod/Draft/Resources/patterns/concrete.svg index 2aa5e9565..b919a036c 100644 --- a/src/Mod/Draft/Resources/patterns/concrete.svg +++ b/src/Mod/Draft/Resources/patterns/concrete.svg @@ -1,5 +1,62 @@ - - + + + + + + image/svg+xml + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - \ No newline at end of file + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Draft/Resources/patterns/cross.svg b/src/Mod/Draft/Resources/patterns/cross.svg index 0d4787b29..e77cf8d73 100644 --- a/src/Mod/Draft/Resources/patterns/cross.svg +++ b/src/Mod/Draft/Resources/patterns/cross.svg @@ -1,5 +1,61 @@ - - + + + + + + image/svg+xml + + + + + + + + - \ No newline at end of file + + + + + + + + + + + + + + + diff --git a/src/Mod/Draft/Resources/patterns/line.svg b/src/Mod/Draft/Resources/patterns/line.svg index 9314cd9e4..ecc47cf3d 100644 --- a/src/Mod/Draft/Resources/patterns/line.svg +++ b/src/Mod/Draft/Resources/patterns/line.svg @@ -1,5 +1,61 @@ - - + + + + + + image/svg+xml + + + + + + + + - \ No newline at end of file + + + + + diff --git a/src/Mod/Draft/Resources/patterns/square.svg b/src/Mod/Draft/Resources/patterns/square.svg index bc4961c62..8cd2b7ff6 100644 --- a/src/Mod/Draft/Resources/patterns/square.svg +++ b/src/Mod/Draft/Resources/patterns/square.svg @@ -1,5 +1,61 @@ - - + + + + + + image/svg+xml + + + + + + + + - \ No newline at end of file + + + + + + + + + From d4d4c8dc6251886d94eeebf14eb0b2a8f5adf5d5 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 6 Jul 2013 22:49:12 +0200 Subject: [PATCH 153/160] 0000596: Edge chain selection --- src/Mod/Part/Gui/DlgFilletEdges.cpp | 118 ++++++++++++++++++++++------ src/Mod/Part/Gui/DlgFilletEdges.h | 4 + src/Mod/Part/Gui/DlgFilletEdges.ui | 65 +++++++++------ 3 files changed, 140 insertions(+), 47 deletions(-) diff --git a/src/Mod/Part/Gui/DlgFilletEdges.cpp b/src/Mod/Part/Gui/DlgFilletEdges.cpp index f6c701ab8..46066a5f2 100644 --- a/src/Mod/Part/Gui/DlgFilletEdges.cpp +++ b/src/Mod/Part/Gui/DlgFilletEdges.cpp @@ -30,6 +30,7 @@ # include # include # include +# include # include # include # include @@ -133,14 +134,23 @@ bool FilletRadiusModel::setData (const QModelIndex & index, const QVariant & val // -------------------------------------------------------------- namespace PartGui { - class EdgeSelection : public Gui::SelectionFilterGate + class EdgeFaceSelection : public Gui::SelectionFilterGate { + bool allowEdge; App::DocumentObject*& object; public: - EdgeSelection(App::DocumentObject*& obj) - : Gui::SelectionFilterGate((Gui::SelectionFilter*)0), object(obj) + EdgeFaceSelection(App::DocumentObject*& obj) + : Gui::SelectionFilterGate((Gui::SelectionFilter*)0), allowEdge(true), object(obj) { } + void selectEdges() + { + allowEdge = true; + } + void selectFaces() + { + allowEdge = false; + } bool allow(App::Document*pDoc, App::DocumentObject*pObj, const char*sSubName) { if (pObj != this->object) @@ -148,16 +158,21 @@ namespace PartGui { if (!sSubName || sSubName[0] == '\0') return false; std::string element(sSubName); - return element.substr(0,4) == "Edge"; + if (allowEdge) + return element.substr(0,4) == "Edge"; + else + return element.substr(0,4) == "Face"; } }; class DlgFilletEdgesP { public: App::DocumentObject* object; - EdgeSelection* selection; + EdgeFaceSelection* selection; Part::FilletBase* fillet; std::vector edge_ids; + TopTools_IndexedMapOfShape all_edges; + TopTools_IndexedMapOfShape all_faces; typedef boost::signals::connection Connection; Connection connectApplicationDeletedObject; Connection connectApplicationDeletedDocument; @@ -172,7 +187,7 @@ DlgFilletEdges::DlgFilletEdges(Part::FilletBase* fillet, QWidget* parent, Qt::WF ui->setupUi(this); d->object = 0; - d->selection = new EdgeSelection(d->object); + d->selection = new EdgeFaceSelection(d->object); Gui::Selection().addSelectionGate(d->selection); d->fillet = fillet; @@ -225,27 +240,67 @@ void DlgFilletEdges::onSelectionChanged(const Gui::SelectionChanges& msg) std::string objname = d->object->getNameInDocument(); if (docname==msg.pDocName && objname==msg.pObjectName) { QString subelement = QString::fromAscii(msg.pSubName); - QAbstractItemModel* model = ui->treeView->model(); - for (int i=0; irowCount(); ++i) { - int id = model->data(model->index(i,0), Qt::UserRole).toInt(); + if (subelement.startsWith(QLatin1String("Edge"))) { + onSelectEdge(subelement, msg.Type); + } + else if (subelement.startsWith(QLatin1String("Face"))) { + d->selection->selectEdges(); + onSelectEdgesOfFace(subelement, msg.Type); + d->selection->selectFaces(); + } + } + } +} + +void DlgFilletEdges::onSelectEdge(const QString& subelement, int type) +{ + Gui::SelectionChanges::MsgType msgType = Gui::SelectionChanges::MsgType(type); + QAbstractItemModel* model = ui->treeView->model(); + for (int i=0; irowCount(); ++i) { + int id = model->data(model->index(i,0), Qt::UserRole).toInt(); + QString name = QString::fromAscii("Edge%1").arg(id); + if (name == subelement) { + // ok, check the selected sub-element + Qt::CheckState checkState = + (msgType == Gui::SelectionChanges::AddSelection + ? Qt::Checked : Qt::Unchecked); + QVariant value(static_cast(checkState)); + QModelIndex index = model->index(i,0); + model->setData(index, value, Qt::CheckStateRole); + // select the item + ui->treeView->selectionModel()->setCurrentIndex(index,QItemSelectionModel::NoUpdate); + QItemSelection selection(index, model->index(i,1)); + ui->treeView->selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect); + ui->treeView->update(); + break; + } + } +} + +void DlgFilletEdges::onSelectEdgesOfFace(const QString& subelement, int type) +{ + bool ok; + int index = subelement.mid(4).toInt(&ok); + if (ok) { + try { + const TopoDS_Shape& face = d->all_faces.FindKey(index); + TopTools_IndexedMapOfShape mapOfEdges; + TopExp::MapShapes(face, TopAbs_EDGE, mapOfEdges); + + for(int j = 1; j <= mapOfEdges.Extent(); ++j) { + TopoDS_Edge edge = TopoDS::Edge(mapOfEdges.FindKey(j)); + int id = d->all_edges.FindIndex(edge); QString name = QString::fromAscii("Edge%1").arg(id); - if (name == subelement) { - // ok, check the selected sub-element - Qt::CheckState checkState = - (msg.Type == Gui::SelectionChanges::AddSelection - ? Qt::Checked : Qt::Unchecked); - QVariant value(static_cast(checkState)); - QModelIndex index = model->index(i,0); - model->setData(index, value, Qt::CheckStateRole); - // select the item - ui->treeView->selectionModel()->setCurrentIndex(index,QItemSelectionModel::NoUpdate); - QItemSelection selection(index, model->index(i,1)); - ui->treeView->selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect); - ui->treeView->update(); - break; + onSelectEdge(name, type); + Gui::SelectionChanges::MsgType msgType = Gui::SelectionChanges::MsgType(type); + if (msgType == Gui::SelectionChanges::AddSelection) { + Gui::Selection().addSelection(d->object->getDocument()->getName(), + d->object->getNameInDocument(), (const char*)name.toAscii()); } } } + catch (Standard_Failure) { + } } } @@ -435,6 +490,13 @@ void DlgFilletEdges::on_shapeObject_activated(int index) if (part && part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { d->object = part; TopoDS_Shape myShape = static_cast(part)->Shape.getValue(); + + d->all_edges.Clear(); + TopExp::MapShapes(myShape, TopAbs_EDGE, d->all_edges); + + d->all_faces.Clear(); + TopExp::MapShapes(myShape, TopAbs_FACE, d->all_faces); + // build up map edge->face TopTools_IndexedDataMapOfShapeListOfShape edge2Face; TopExp::MapShapesAndAncestors(myShape, TopAbs_EDGE, TopAbs_FACE, edge2Face); @@ -481,6 +543,16 @@ void DlgFilletEdges::on_shapeObject_activated(int index) } } +void DlgFilletEdges::on_selectEdges_toggled(bool on) +{ + if (on) d->selection->selectEdges(); +} + +void DlgFilletEdges::on_selectFaces_toggled(bool on) +{ + if (on) d->selection->selectFaces(); +} + void DlgFilletEdges::on_selectAllButton_clicked() { QAbstractItemModel* model = ui->treeView->model(); diff --git a/src/Mod/Part/Gui/DlgFilletEdges.h b/src/Mod/Part/Gui/DlgFilletEdges.h index 4c36cd9c6..46df51366 100644 --- a/src/Mod/Part/Gui/DlgFilletEdges.h +++ b/src/Mod/Part/Gui/DlgFilletEdges.h @@ -90,9 +90,13 @@ private: void onSelectionChanged(const Gui::SelectionChanges& msg); void onDeleteObject(const App::DocumentObject&); void onDeleteDocument(const App::Document&); + void onSelectEdge(const QString& subelement, int type); + void onSelectEdgesOfFace(const QString& subelement, int type); private Q_SLOTS: void on_shapeObject_activated(int); + void on_selectEdges_toggled(bool); + void on_selectFaces_toggled(bool); void on_selectAllButton_clicked(); void on_selectNoneButton_clicked(); void on_filletType_activated(int); diff --git a/src/Mod/Part/Gui/DlgFilletEdges.ui b/src/Mod/Part/Gui/DlgFilletEdges.ui index 5d08a55d9..9f2e4606a 100644 --- a/src/Mod/Part/Gui/DlgFilletEdges.ui +++ b/src/Mod/Part/Gui/DlgFilletEdges.ui @@ -51,27 +51,7 @@ Fillet Parameter - - - - Qt::Horizontal - - - - 221 - 20 - - - - - - - - All - - - - + None @@ -85,7 +65,7 @@ - + @@ -99,10 +79,10 @@ - + - + 6 @@ -155,6 +135,43 @@ + + + + All + + + + + + + Select faces + + + + + + + Qt::Horizontal + + + + 221 + 20 + + + + + + + + Select edges + + + true + + + From 407f4d9e2f17eb0afd8efdecf395a1558efc0644 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sat, 6 Jul 2013 18:41:43 -0300 Subject: [PATCH 154/160] Draft: Added face mode to Draft rectangle tracker --- src/Mod/Draft/DraftTrackers.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Mod/Draft/DraftTrackers.py b/src/Mod/Draft/DraftTrackers.py index f672cad5b..960f281d2 100644 --- a/src/Mod/Draft/DraftTrackers.py +++ b/src/Mod/Draft/DraftTrackers.py @@ -157,13 +157,21 @@ class lineTracker(Tracker): class rectangleTracker(Tracker): "A Rectangle tracker, used by the rectangle tool" - def __init__(self,dotted=False,scolor=None,swidth=None): + def __init__(self,dotted=False,scolor=None,swidth=None,face=False): self.origin = Vector(0,0,0) line = coin.SoLineSet() line.numVertices.setValue(5) self.coords = coin.SoCoordinate3() # this is the coordinate self.coords.point.setValues(0,50,[[0,0,0],[2,0,0],[2,2,0],[0,2,0],[0,0,0]]) - Tracker.__init__(self,dotted,scolor,swidth,[self.coords,line]) + if face: + m1 = coin.SoMaterial() + m1.transparency.setValue(0.5) + m1.diffuseColor.setValue([0.5,0.5,1.0]) + f = coin.SoIndexedFaceSet() + f.coordIndex.setValues([0,1,2,3]) + Tracker.__init__(self,dotted,scolor,swidth,[self.coords,line,m1,f]) + else: + Tracker.__init__(self,dotted,scolor,swidth,[self.coords,line]) self.u = FreeCAD.DraftWorkingPlane.u self.v = FreeCAD.DraftWorkingPlane.v From e3b0c111be5d0da2a1563211599a4cf778b22cc5 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 7 Jul 2013 16:05:30 +0200 Subject: [PATCH 155/160] Fix crash when closing color panel --- src/Mod/Part/Gui/TaskFaceColors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Part/Gui/TaskFaceColors.cpp b/src/Mod/Part/Gui/TaskFaceColors.cpp index ef1c1804e..60570612f 100644 --- a/src/Mod/Part/Gui/TaskFaceColors.cpp +++ b/src/Mod/Part/Gui/TaskFaceColors.cpp @@ -103,7 +103,7 @@ public: Connection connectDelDoc; Connection connectDelObj; - Private(ViewProviderPartExt* vp) : ui(new Ui_TaskFaceColors()), vp(vp) + Private(ViewProviderPartExt* vp) : ui(new Ui_TaskFaceColors()), view(0), vp(vp) { obj = vp->getObject(); doc = Gui::Application::Instance->getDocument(obj->getDocument()); From 2b0757c3a6665cdc07bafd5434f66f75e2da01aa Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 7 Jul 2013 16:13:38 +0200 Subject: [PATCH 156/160] 0000735: Feature request for better Fillet/Chamfer --- src/Mod/Part/App/FeatureChamfer.cpp | 4 ++ src/Mod/Part/App/FeatureFillet.cpp | 4 ++ src/Mod/Part/Gui/DlgFilletEdges.cpp | 1 - src/Mod/Part/Gui/ViewProvider.cpp | 14 ++++ src/Mod/Part/Gui/ViewProvider.h | 7 ++ src/Mod/Part/Gui/ViewProviderBoolean.cpp | 14 ---- src/Mod/Part/Gui/ViewProviderMirror.cpp | 82 ++++++++++++++++++++++++ src/Mod/Part/Gui/ViewProviderMirror.h | 2 + 8 files changed, 113 insertions(+), 15 deletions(-) diff --git a/src/Mod/Part/App/FeatureChamfer.cpp b/src/Mod/Part/App/FeatureChamfer.cpp index 3c694f012..e857000b0 100644 --- a/src/Mod/Part/App/FeatureChamfer.cpp +++ b/src/Mod/Part/App/FeatureChamfer.cpp @@ -75,7 +75,11 @@ App::DocumentObjectExecReturn *Chamfer::execute(void) TopoDS_Shape shape = mkChamfer.Shape(); if (shape.IsNull()) return new App::DocumentObjectExecReturn("Resulting shape is null"); + ShapeHistory history = buildHistory(mkChamfer, TopAbs_FACE, shape, base->Shape.getValue()); this->Shape.setValue(shape); + PropertyShapeHistory prop; + prop.setContainer(this); + prop.setValue(history); return App::DocumentObject::StdReturn; } catch (Standard_Failure) { diff --git a/src/Mod/Part/App/FeatureFillet.cpp b/src/Mod/Part/App/FeatureFillet.cpp index 032bcde7d..550fcaf3e 100644 --- a/src/Mod/Part/App/FeatureFillet.cpp +++ b/src/Mod/Part/App/FeatureFillet.cpp @@ -74,7 +74,11 @@ App::DocumentObjectExecReturn *Fillet::execute(void) TopoDS_Shape shape = mkFillet.Shape(); if (shape.IsNull()) return new App::DocumentObjectExecReturn("Resulting shape is null"); + ShapeHistory history = buildHistory(mkFillet, TopAbs_FACE, shape, base->Shape.getValue()); this->Shape.setValue(shape); + PropertyShapeHistory prop; + prop.setContainer(this); + prop.setValue(history); return App::DocumentObject::StdReturn; } catch (Standard_Failure) { diff --git a/src/Mod/Part/Gui/DlgFilletEdges.cpp b/src/Mod/Part/Gui/DlgFilletEdges.cpp index 46066a5f2..f241f656b 100644 --- a/src/Mod/Part/Gui/DlgFilletEdges.cpp +++ b/src/Mod/Part/Gui/DlgFilletEdges.cpp @@ -703,7 +703,6 @@ bool DlgFilletEdges::accept() QByteArray to = name.toAscii(); QByteArray from = shape.toAscii(); - Gui::Command::copyVisual(to, "ShapeColor", from); Gui::Command::copyVisual(to, "LineColor", from); Gui::Command::copyVisual(to, "PointColor", from); return true; diff --git a/src/Mod/Part/Gui/ViewProvider.cpp b/src/Mod/Part/Gui/ViewProvider.cpp index 9bf99796a..ec2ffe269 100644 --- a/src/Mod/Part/Gui/ViewProvider.cpp +++ b/src/Mod/Part/Gui/ViewProvider.cpp @@ -120,6 +120,20 @@ bool ViewProviderPart::doubleClicked(void) return true; } +void ViewProviderPart::applyColor(const Part::ShapeHistory& hist, + const std::vector& colBase, + std::vector& colBool) +{ + std::map >::const_iterator jt; + // apply color from modified faces + for (jt = hist.shapeMap.begin(); jt != hist.shapeMap.end(); ++jt) { + std::vector::const_iterator kt; + for (kt = jt->second.begin(); kt != jt->second.end(); ++kt) { + colBool[*kt] = colBase[jt->first]; + } + } +} + #else PROPERTY_SOURCE(PartGui::ViewProviderPart, PartGui::ViewProviderPartBase) diff --git a/src/Mod/Part/Gui/ViewProvider.h b/src/Mod/Part/Gui/ViewProvider.h index 50b4b8642..4d9058fd3 100644 --- a/src/Mod/Part/Gui/ViewProvider.h +++ b/src/Mod/Part/Gui/ViewProvider.h @@ -50,6 +50,8 @@ class SoScale; // Set this to use the fast rendering of shapes #define FC_USE_FAST_SHAPE_RENDERING +namespace Part { struct ShapeHistory; } + namespace PartGui { class ViewProviderShapeBuilder : public Gui::ViewProviderBuilder @@ -157,6 +159,11 @@ public: /// destructor virtual ~ViewProviderPart(); virtual bool doubleClicked(void); + +protected: + void applyColor(const Part::ShapeHistory& hist, + const std::vector& colBase, + std::vector& colBool); }; #else class PartGuiExport ViewProviderPart : public ViewProviderPartBase diff --git a/src/Mod/Part/Gui/ViewProviderBoolean.cpp b/src/Mod/Part/Gui/ViewProviderBoolean.cpp index 74aadfad5..cd7c99088 100644 --- a/src/Mod/Part/Gui/ViewProviderBoolean.cpp +++ b/src/Mod/Part/Gui/ViewProviderBoolean.cpp @@ -77,20 +77,6 @@ QIcon ViewProviderBoolean::getIcon(void) const return ViewProviderPart::getIcon(); } -void applyColor(const Part::ShapeHistory& hist, - const std::vector& colBase, - std::vector& colBool) -{ - std::map >::const_iterator jt; - // apply color from modified faces - for (jt = hist.shapeMap.begin(); jt != hist.shapeMap.end(); ++jt) { - std::vector::const_iterator kt; - for (kt = jt->second.begin(); kt != jt->second.end(); ++kt) { - colBool[*kt] = colBase[jt->first]; - } - } -} - void ViewProviderBoolean::updateData(const App::Property* prop) { PartGui::ViewProviderPart::updateData(prop); diff --git a/src/Mod/Part/Gui/ViewProviderMirror.cpp b/src/Mod/Part/Gui/ViewProviderMirror.cpp index d7c8ea5d5..9be1540ab 100644 --- a/src/Mod/Part/Gui/ViewProviderMirror.cpp +++ b/src/Mod/Part/Gui/ViewProviderMirror.cpp @@ -28,6 +28,10 @@ # include # include # include +# include +# include +# include +# include # include # include # include @@ -225,6 +229,45 @@ ViewProviderFillet::~ViewProviderFillet() { } +void ViewProviderFillet::updateData(const App::Property* prop) +{ + PartGui::ViewProviderPart::updateData(prop); + if (prop->getTypeId() == Part::PropertyShapeHistory::getClassTypeId()) { + const std::vector& hist = static_cast + (prop)->getValues(); + if (hist.size() != 1) + return; + Part::Fillet* objFill = dynamic_cast(getObject()); + Part::Feature* objBase = dynamic_cast(objFill->Base.getValue()); + if (objBase) { + const TopoDS_Shape& baseShape = objBase->Shape.getValue(); + const TopoDS_Shape& fillShape = objFill->Shape.getValue(); + + TopTools_IndexedMapOfShape baseMap, fillMap; + TopExp::MapShapes(baseShape, TopAbs_FACE, baseMap); + TopExp::MapShapes(fillShape, TopAbs_FACE, fillMap); + + Gui::ViewProvider* vpBase = Gui::Application::Instance->getViewProvider(objBase); + std::vector colBase = static_cast(vpBase)->DiffuseColor.getValues(); + std::vector colFill; + colFill.resize(fillMap.Extent(), static_cast(vpBase)->ShapeColor.getValue()); + + bool setColor=false; + if (colBase.size() == baseMap.Extent()) { + applyColor(hist[0], colBase, colFill); + setColor = true; + } + else if (!colBase.empty() && colBase[0] != this->ShapeColor.getValue()) { + colBase.resize(baseMap.Extent(), colBase[0]); + applyColor(hist[0], colBase, colFill); + setColor = true; + } + if (setColor) + this->DiffuseColor.setValues(colFill); + } + } +} + void ViewProviderFillet::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) { QAction* act; @@ -289,6 +332,45 @@ ViewProviderChamfer::~ViewProviderChamfer() { } +void ViewProviderChamfer::updateData(const App::Property* prop) +{ + PartGui::ViewProviderPart::updateData(prop); + if (prop->getTypeId() == Part::PropertyShapeHistory::getClassTypeId()) { + const std::vector& hist = static_cast + (prop)->getValues(); + if (hist.size() != 1) + return; + Part::Chamfer* objCham = dynamic_cast(getObject()); + Part::Feature* objBase = dynamic_cast(objCham->Base.getValue()); + if (objBase) { + const TopoDS_Shape& baseShape = objBase->Shape.getValue(); + const TopoDS_Shape& chamShape = objCham->Shape.getValue(); + + TopTools_IndexedMapOfShape baseMap, chamMap; + TopExp::MapShapes(baseShape, TopAbs_FACE, baseMap); + TopExp::MapShapes(chamShape, TopAbs_FACE, chamMap); + + Gui::ViewProvider* vpBase = Gui::Application::Instance->getViewProvider(objBase); + std::vector colBase = static_cast(vpBase)->DiffuseColor.getValues(); + std::vector colCham; + colCham.resize(chamMap.Extent(), static_cast(vpBase)->ShapeColor.getValue()); + + bool setColor=false; + if (colBase.size() == baseMap.Extent()) { + applyColor(hist[0], colBase, colCham); + setColor = true; + } + else if (!colBase.empty() && colBase[0] != this->ShapeColor.getValue()) { + colBase.resize(baseMap.Extent(), colBase[0]); + applyColor(hist[0], colBase, colCham); + setColor = true; + } + if (setColor) + this->DiffuseColor.setValues(colCham); + } + } +} + void ViewProviderChamfer::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) { QAction* act; diff --git a/src/Mod/Part/Gui/ViewProviderMirror.h b/src/Mod/Part/Gui/ViewProviderMirror.h index ab0ec4c2d..802ffcc94 100644 --- a/src/Mod/Part/Gui/ViewProviderMirror.h +++ b/src/Mod/Part/Gui/ViewProviderMirror.h @@ -70,6 +70,7 @@ public: bool onDelete(const std::vector &); protected: + void updateData(const App::Property*); bool setEdit(int ModNum); void unsetEdit(int ModNum); //@} @@ -91,6 +92,7 @@ public: bool onDelete(const std::vector &); protected: + void updateData(const App::Property*); bool setEdit(int ModNum); void unsetEdit(int ModNum); //@} From 51383ada0702d756148f09fb88be52928efd1a00 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sun, 7 Jul 2013 11:29:26 -0300 Subject: [PATCH 157/160] 0001167: Arch fixtures system Arch objects can now have Fixtures, which is a mesh or part attached to them, but that doesn't modify the geometry of the base object. They are normally hidden, except when the new Display Mode "Detailed" is used. Fixtures can be added to any Arch object using the new Arch_Fixture command and removed with the standard Arch_Remove command. Fixtures are useful for small unimportant details like window latches or hinges, that should stay hidden most of the time. --- src/Mod/Arch/ArchCommands.py | 38 +++ src/Mod/Arch/ArchComponent.py | 41 ++- src/Mod/Arch/ArchWall.py | 7 +- src/Mod/Arch/ArchWindow.py | 2 +- src/Mod/Arch/Arch_rc.py | 152 +++++++++-- src/Mod/Arch/InitGui.py | 3 +- src/Mod/Arch/Resources/Arch.qrc | 1 + src/Mod/Arch/Resources/icons/Arch_Fixture.svg | 243 ++++++++++++++++++ 8 files changed, 455 insertions(+), 32 deletions(-) create mode 100644 src/Mod/Arch/Resources/icons/Arch_Fixture.svg diff --git a/src/Mod/Arch/ArchCommands.py b/src/Mod/Arch/ArchCommands.py index 96da0d2bd..8212772fa 100644 --- a/src/Mod/Arch/ArchCommands.py +++ b/src/Mod/Arch/ArchCommands.py @@ -525,6 +525,19 @@ def check(objectslist,includehidden=False): bad.append([o,str(translate("Arch","contains faces that are not part of any solid"))]) return bad + +def addFixture(fixture,baseobject): + '''addFixture(fixture,baseobject): adds the given object as a + fixture to the given base object''' + if hasattr(baseobject,"Fixtures"): + f = baseobject.Fixtures + f.append(fixture) + baseobject.Fixtures = f + if baseobject.ViewObject.DisplayMode != "Detailed": + fixture.ViewObject.hide() + else: + FreeCAD.Console.PrintMessage(str(translate("Arch","This object has no support for fixtures"))) + # command definitions ############################################### @@ -737,6 +750,30 @@ class _CommandCheck: FreeCADGui.Selection.addSelection(i[0]) +class _CommandFixture: + "the Arch Fixture command definition" + def GetResources(self): + return {'Pixmap' : 'Arch_Fixture', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_Fixture","Add fixture"), + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Fixture","Adds the selected components as fixtures to the active object")} + + def IsActive(self): + if len(FreeCADGui.Selection.getSelection()) > 1: + return True + else: + return False + + def Activated(self): + sel = FreeCADGui.Selection.getSelection() + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Grouping"))) + host = sel.pop() + for o in sel: + FreeCADGui.doCommand("import Arch") + FreeCADGui.doCommand("Arch.addFixture(FreeCAD.ActiveDocument."+o.Name+",FreeCAD.ActiveDocument."+host.Name+")") + FreeCAD.ActiveDocument.commitTransaction() + FreeCAD.ActiveDocument.recompute() + + FreeCADGui.addCommand('Arch_Add',_CommandAdd()) FreeCADGui.addCommand('Arch_Remove',_CommandRemove()) FreeCADGui.addCommand('Arch_SplitMesh',_CommandSplitMesh()) @@ -745,3 +782,4 @@ FreeCADGui.addCommand('Arch_SelectNonSolidMeshes',_CommandSelectNonSolidMeshes() FreeCADGui.addCommand('Arch_RemoveShape',_CommandRemoveShape()) FreeCADGui.addCommand('Arch_CloseHoles',_CommandCloseHoles()) FreeCADGui.addCommand('Arch_Check',_CommandCheck()) +FreeCADGui.addCommand('Arch_Fixture',_CommandFixture()) diff --git a/src/Mod/Arch/ArchComponent.py b/src/Mod/Arch/ArchComponent.py index aa5a30064..786f48914 100644 --- a/src/Mod/Arch/ArchComponent.py +++ b/src/Mod/Arch/ArchComponent.py @@ -74,6 +74,7 @@ def addToComponent(compobject,addobject,mod=None): addobject.ViewObject.hide() break + def removeFromComponent(compobject,subobject): '''removeFromComponent(compobject,subobject): subtracts subobject from the given component. If the subobject is already part of the @@ -81,7 +82,7 @@ def removeFromComponent(compobject,subobject): it is added as a subtraction.''' if compobject == subobject: return found = False - attribs = ["Additions","Subtractions","Objects","Components","Base","Axes"] + attribs = ["Additions","Subtractions","Objects","Components","Base","Axes","Fixtures"] for a in attribs: if hasattr(compobject,a): if a == "Base": @@ -113,7 +114,7 @@ class ComponentTaskPanel: # the categories are shown only if they are not empty. self.obj = None - self.attribs = ["Base","Additions","Subtractions","Objects","Components","Axes"] + self.attribs = ["Base","Additions","Subtractions","Objects","Components","Axes","Fixtures"] self.form = QtGui.QWidget() self.form.setObjectName("TaskPanel") self.grid = QtGui.QGridLayout(self.form) @@ -263,6 +264,8 @@ class Component: "Other shapes that are appended to this object") obj.addProperty("App::PropertyLinkList","Subtractions","Base", "Other shapes that are subtracted from this object") + obj.addProperty("App::PropertyLinkList","Fixtures","Base", + "Shapes or Meshes that are appended to this object without modifying its geometry") obj.Proxy = self self.Type = "Component" self.Subvolume = None @@ -275,7 +278,18 @@ class Component: def __setstate__(self,state): if state: self.Type = state - + + def onChanged(self,obj,prop): + if prop == "Placement": + # make fixtures move along with host + if hasattr(obj,"Fixtures"): + vo = obj.Shape.Placement.Base + vn = obj.Placement.Base + import DraftVecUtils + if not DraftVecUtils.equals(vo,vn): + delta = vn.sub(vo) + for o in obj.Fixtures: + o.Placement.move(delta) def getSubVolume(self,base,width,plac=None): "returns a subvolume from a base object" @@ -388,7 +402,6 @@ class Component: base = base.cut(o.Shape) return base - class ViewProviderComponent: "A default View Provider for Component objects" def __init__(self,vobj): @@ -406,11 +419,22 @@ class ViewProviderComponent: return def getDisplayModes(self,vobj): - modes=[] + modes=["Detailed"] return modes def setDisplayMode(self,mode): - return mode + if mode == "Detailed": + if hasattr(self,"Object"): + if hasattr(self.Object,"Fixtures"): + for f in self.Object.Fixtures: + f.ViewObject.show() + return "Flat Lines" + else: + if hasattr(self,"Object"): + if hasattr(self.Object,"Fixtures"): + for f in self.Object.Fixtures: + f.ViewObject.hide() + return mode def __getstate__(self): return None @@ -419,7 +443,10 @@ class ViewProviderComponent: return None def claimChildren(self): - return [self.Object.Base]+self.Object.Additions+self.Object.Subtractions + c = [self.Object.Base]+self.Object.Additions+self.Object.Subtractions + if hasattr(self.Object,"Fixtures"): + c.extend(self.Object.Fixtures) + return c def setEdit(self,vobj,mode): taskd = ComponentTaskPanel() diff --git a/src/Mod/Arch/ArchWall.py b/src/Mod/Arch/ArchWall.py index 9fd625b82..5f0ca5cb0 100644 --- a/src/Mod/Arch/ArchWall.py +++ b/src/Mod/Arch/ArchWall.py @@ -362,9 +362,8 @@ class _Wall(ArchComponent.Component): for o in obj.OutList: if (Draft.getType(o) == "Window") or Draft.isClone(o,"Window"): o.Placement.move(delta) + ArchComponent.Component.onChanged(self,obj,prop) - - def getDefaultValues(self,obj): "returns normal,width,height values from this wall" width = 1.0 @@ -508,14 +507,14 @@ class _ViewProviderWall(ArchComponent.ViewProviderComponent): return ":/icons/Arch_Wall_Tree.svg" def getDisplayModes(self,vobj): - return ["Flat 2D"] + return ArchComponent.ViewProviderComponent.getDisplayModes(self,vobj)+["Flat 2D"] def setDisplayMode(self,mode): self.Object.Proxy.createGeometry(self.Object) if mode == "Flat 2D": return "Flat Lines" else: - return mode + return ArchComponent.ViewProviderComponent.setDisplayMode(self,mode) def attach(self,vobj): self.Object = vobj.Object diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py index 55dc0c094..c3d72f30a 100644 --- a/src/Mod/Arch/ArchWindow.py +++ b/src/Mod/Arch/ArchWindow.py @@ -213,7 +213,7 @@ class _ViewProviderWindow(ArchComponent.ViewProviderComponent): if self.Object.Base: self.Object.Base.ViewObject.hide() FreeCADGui.Control.closeDialog() - return + return False def colorize(self,obj): "setting different part colors" diff --git a/src/Mod/Arch/Arch_rc.py b/src/Mod/Arch/Arch_rc.py index 870ae8d4f..37b7e01be 100644 --- a/src/Mod/Arch/Arch_rc.py +++ b/src/Mod/Arch/Arch_rc.py @@ -2,7 +2,7 @@ # Resource object code # -# Created: Wed Jul 3 13:10:05 2013 +# Created: Sun Jul 7 11:06:17 2013 # by: The Resource Compiler for PyQt (Qt v4.8.4) # # WARNING! All changes made in this file will be lost! @@ -30238,6 +30238,115 @@ qt_resource_data = "\ \xd2\x9d\x05\x58\x30\x1c\x10\x5c\xc1\xc0\xb9\x84\x28\x3a\x0e\x7c\ \x1e\x69\x22\x66\xf0\xbf\x6e\xdf\x34\x9b\xcb\xfa\xdb\x5d\xc5\xd7\ \x0f\x77\x73\x77\xf7\x79\xb8\xfb\x37\x54\x09\xba\x52\ +\x00\x00\x06\xab\ +\x00\ +\x00\x22\x6d\x78\x9c\xed\x58\xeb\x8f\xdb\x36\x12\xff\xbe\x7f\x85\ +\x4e\xf9\x92\x45\x4d\x8a\x0f\x49\x14\xb5\xf6\x16\xc5\x05\x29\x0a\ +\xb4\x28\x70\x4d\x70\x1f\x0f\xb2\x44\xdb\xca\xca\x92\x41\xc9\x6b\ +\x3b\x7f\x7d\x87\xb2\x5e\xde\xd5\x3e\x2f\x71\xda\xbb\x18\x58\xac\ +\x34\x0f\xce\x70\xe6\x37\x43\x6a\xa6\x3f\xee\xd7\x99\x75\xab\x74\ +\x99\x16\xf9\xcc\xa6\x98\xd8\x96\xca\xe3\x22\x49\xf3\xe5\xcc\xfe\ +\xf8\xe1\x3d\x0a\x6c\xab\xac\xa2\x3c\x89\xb2\x22\x57\x33\x3b\x2f\ +\xec\x1f\xaf\x2f\xa6\xff\x40\xc8\xfa\xa7\x56\x51\xa5\x12\x6b\x97\ +\x56\x2b\xeb\x97\xfc\xa6\x8c\xa3\x8d\xb2\xde\xae\xaa\x6a\x13\x3a\ +\xce\x6e\xb7\xc3\x69\x43\xc4\x85\x5e\x3a\x97\x16\x42\xd7\x17\x17\ +\xd3\xf2\x76\x79\x61\x59\x16\xd8\xcd\xcb\x30\x89\x67\x76\xa3\xb0\ +\xd9\xea\xac\x16\x4c\x62\x47\x65\x6a\xad\xf2\xaa\x74\x28\xa6\x8e\ +\xdd\x8b\xc7\xbd\x78\x6c\xac\xa7\xb7\x2a\x2e\xd6\xeb\x22\x2f\x6b\ +\xcd\xbc\x7c\x33\x10\xd6\xc9\xa2\x93\x36\xde\xec\x78\x2d\x44\xa5\ +\x94\x0e\x61\x0e\x63\x08\x24\x50\x79\xc8\xab\x68\x8f\x4e\x55\xc1\ +\xc7\x31\x55\x46\x08\x71\x80\xd7\x4b\x3e\x4f\x2a\xdc\x67\x10\x8a\ +\x07\x9d\xa9\xb9\x43\xeb\x10\xfe\x0d\xfc\x75\x0a\x2d\x01\x97\xc5\ +\x56\xc7\x6a\x01\x9a\x0a\xe7\xaa\x72\xde\x7d\x78\xd7\x31\x11\xc1\ +\x49\x95\x0c\x96\x69\xa3\x7f\x62\xf7\x24\x25\x79\xb4\x56\xe5\x26\ +\x8a\x55\xe9\xb4\xf4\x5a\x7f\x97\x26\xd5\x6a\x66\xfb\xee\x66\x5f\ +\xbf\xaf\x54\xba\x5c\x55\x03\x42\x9a\xcc\x6c\xd8\x21\x93\x81\x57\ +\xbf\x0f\x00\x44\x8f\x02\xcd\x72\x61\xc7\x21\xd8\x0d\xb0\x6b\x69\ +\x29\xb9\xac\x45\x5a\xbf\xc3\xa4\x88\x8d\x23\x33\xfb\x27\x1d\xaf\ +\xfe\xf3\x53\x92\x60\x13\xbc\x6b\x90\x99\x26\x6a\x51\x1a\xd9\xa3\ +\x45\xf3\x06\x26\x45\xcd\x03\x2e\x84\x4d\x45\xfa\x67\x1d\x25\x29\ +\x80\xe5\x28\x77\x94\x3c\xe5\x70\x21\x79\xa3\x03\x5a\x65\x55\x6c\ +\x5a\x59\xf0\xa2\x3a\x64\x60\xda\x10\x51\x5c\x64\x85\x0e\xdf\x40\ +\xfa\x16\x41\x74\x55\x93\x0a\x88\x4e\x5a\x1d\x42\x7a\x65\xf7\x3a\ +\xc5\x62\x51\x2a\x08\x07\x19\xd0\xea\x88\x80\x06\xd8\xf2\x6c\xcb\ +\x79\x89\x35\xdf\x5f\x2c\x9e\x61\x8d\x8e\x5b\x13\x9d\xb5\xa9\x73\ +\xba\xed\xc7\xa3\xd4\x26\x08\xdc\xc8\x54\x0c\xeb\x47\xd9\x2e\x3a\ +\x94\x9d\x91\x1a\x94\xe1\x4a\x2b\x28\xa2\x37\x23\xf1\x7c\x34\xdc\ +\xb2\x5f\x86\x82\xe7\x0c\x13\x2e\x02\xe2\x77\xd4\x03\x50\x3d\x17\ +\x13\x42\x5d\x3a\x90\x65\x40\x65\x38\x08\x98\xef\x06\xbd\x2c\x50\ +\x25\x66\xc2\xa5\x03\xe2\xb2\xb1\xf5\x31\x4f\x2b\x28\xc2\x6d\xa9\ +\xf4\x1f\x06\xc8\xbf\xe7\x1f\x4b\x75\x4f\xea\x83\x8e\xf2\x12\xaa\ +\x66\x3d\xb3\x2b\xf3\x98\x41\xdf\x7a\x8b\xd8\x04\xb1\xcb\x3e\x7a\ +\x5f\x27\x4e\x88\x3d\x11\x29\x14\x7c\xdb\x58\x3d\xb5\xff\xd1\x6a\ +\x82\x5d\x9d\xb1\x9e\x90\x7f\xde\x8a\x42\xe4\x95\x35\x35\x1e\xab\ +\xb3\xf6\x1e\x24\xcf\x1c\x2b\xff\xdb\xf4\x1f\x44\x9f\xaa\x2b\xf2\ +\x77\xe8\x41\x94\x10\x4c\x99\xc7\xe5\x04\x09\x4c\x29\x11\xf2\xe9\ +\x8e\x34\x8e\x32\x7a\x56\x94\xd1\x33\xa3\xcc\x7b\x1d\xca\x46\xf3\ +\xf6\x40\x8a\xc7\xe1\x30\x0a\x9d\xc7\x73\xca\xb1\x24\x3e\xf3\x26\ +\xc8\xc5\x2c\x80\xe4\x5e\xbe\x10\x31\x23\x09\x06\x9f\x5e\x53\x18\ +\x0f\xd5\xd8\x57\x3e\xf3\x1e\xdd\x89\x27\xbf\x64\x01\x05\x01\x16\ +\xbe\x2f\x64\x30\xf1\x09\x96\xd2\x17\x81\x7f\xf9\xb5\xea\xfe\x75\ +\x75\x29\xce\x5a\x97\x67\xbe\x7b\xc2\x3d\xe0\xff\xbd\x2e\x87\xf7\ +\xb7\x27\x2a\x53\xfc\xf7\x95\xf9\x40\xef\x3f\xef\x75\x8c\x9d\x19\ +\x64\xaf\xfc\xc4\xf9\x5f\x02\xd9\x0b\xda\x3f\xfb\x5a\x28\x23\xe7\ +\xbd\xf3\x8b\x33\xa3\x2c\xf8\x8e\x32\xf1\x6c\x94\x91\xe7\x82\x6c\ +\xea\x98\xa9\x4d\xfd\xd4\x0d\x7c\xcc\xb4\x27\xb9\x4d\xd5\xee\xa2\ +\x73\x66\x1e\x75\xde\x6d\xa2\xa5\xaa\x93\x0a\x96\x17\xf5\xaf\x61\ +\xcc\x0b\x9d\x28\xdd\xb2\xfc\xfa\x77\xc2\x6a\xf2\x7e\x1c\x63\x5e\ +\x9c\x7a\x67\x56\xed\xf8\x64\x9c\x5f\xae\xa2\xa4\xd8\xcd\x6c\x76\ +\x97\xf9\xb9\x28\x20\xfe\x1c\xf2\x29\x49\x20\xf8\x5d\x76\xbc\x9f\ +\xd9\x70\x7d\x17\x2c\x08\x3c\x1e\xdc\xe3\x82\x41\x97\x61\xe6\x4a\ +\x9f\x7a\xf7\x98\x5b\xad\x21\xa6\x28\x8b\x0e\x0a\x76\x55\xff\x6b\ +\x11\x5a\xae\x8a\xdd\x52\x9b\xe8\x54\x7a\xab\xee\x6a\x26\x45\xbc\ +\x35\x33\x52\xb4\x3d\x66\xba\x99\xcc\x0d\x24\x8c\x2e\x9a\xcf\x8b\ +\xfd\xf8\x02\xbb\x34\x87\xdd\xa2\x66\xd6\x47\x25\xbb\x17\x93\x46\ +\xa2\x9d\xfe\x51\xe2\x89\x07\x44\xf6\x7d\x21\xdf\x65\x1d\x1e\x66\ +\xad\xa3\x7d\xba\x4e\x3f\xab\xa4\xaf\xca\x4e\xa4\xcc\xa3\x0d\xca\ +\x8b\x44\x95\xe3\xde\x17\xf3\x4f\x00\xb6\x13\x89\x06\x70\x6b\x55\ +\x45\x49\x54\x45\x3d\xb8\x5a\x0a\x93\xb2\xed\x61\x53\x9d\x2c\xc2\ +\x7f\xbd\x7b\xdf\x35\x98\x38\x0e\xff\x5d\xe8\x9b\xbe\x37\x18\x81\ +\x68\x5e\x6c\x61\xe3\x5d\xdf\x33\x13\xc9\x38\x34\xd5\x18\x55\xd7\ +\xe9\x1a\x20\x63\xe6\xbc\x3f\xec\xd7\x19\xc0\xbc\x63\x9c\x08\x57\ +\x87\x8d\xea\x17\x3d\x2e\xab\xd5\x71\x8e\x3b\x3a\xfa\x4e\xe2\x75\ +\x6a\x94\x9c\x3f\xaa\x34\xcb\x7e\x31\x46\x06\x8d\xb0\x59\x34\xad\ +\x32\x75\x5d\xdb\x3c\x3e\xb6\xbb\x70\x9a\x6d\xb4\x7d\x6c\xb0\xcb\ +\xa9\xd3\x86\xa1\x7e\x5b\xf6\xe1\x39\x01\x5d\x17\xe0\x2c\x9a\xab\ +\x6c\x66\xff\x6a\x98\xd6\x3d\xee\x52\x17\xdb\xcd\x1a\x82\xdf\xa8\ +\xb7\x61\xdd\x44\xd5\xaa\x75\xb5\xe9\xd2\x0b\xd8\x46\xf8\x26\x08\ +\xe6\xa2\xee\xcf\xba\xb8\x51\xf5\xf9\xc0\x5d\xaf\x79\x3d\x62\x30\ +\x64\xed\xab\xe9\x37\x60\x25\x9c\x6f\xab\x6a\x48\xfb\x54\xa4\x79\ +\x08\x86\xf3\xa4\xa5\xf6\x9d\xbe\x3f\x77\xe0\x77\x65\x6c\x0e\x98\ +\xf5\xab\xde\x66\x2a\xcc\x8b\xfc\x33\x34\x8a\x56\x1f\x42\xad\x74\ +\x06\x20\xac\x42\xb7\xa5\x25\x11\xf4\x01\xad\xa3\x83\x11\x56\x43\ +\xea\xf1\x08\x09\xc9\xd5\x3a\xd2\x37\x4a\x1f\xf9\xb7\x69\x99\xce\ +\xd3\xcc\x18\xaa\x1f\x33\x75\x95\xa4\xe5\x06\xa2\x12\xa6\xb9\xf1\ +\xfa\xaa\xb8\x55\x7a\x91\x15\xbb\x8e\xaf\xf2\x08\xfe\xa1\x79\x14\ +\xdf\x2c\xeb\xed\x84\x51\x0c\xc5\xbc\x35\xbd\xbd\xeb\xab\x90\x98\ +\xdf\x2c\x86\x3d\x41\x99\x14\xee\x84\x73\xec\x12\xea\xf9\xd4\x62\ +\x12\x73\xca\x84\x9c\x50\x89\x85\xe0\x7e\xe0\x59\x3e\xc5\x82\x52\ +\xca\xc5\x84\x13\x60\xfa\x84\xb8\x16\x17\x70\x34\x70\x38\x1c\x26\ +\xae\xc4\x40\x11\xdc\xb3\x3e\x9f\x1c\x00\x26\x57\x20\x3c\xfa\xbd\ +\x98\x43\x06\xaa\x42\x23\xe8\x4f\xb7\x51\xb5\xd5\x6a\x78\x52\xf7\ +\x8d\x1c\x00\x60\xb0\x0a\x15\x18\x9b\x5f\x7f\x82\x3e\x88\x03\x06\ +\x9f\x68\x0b\xf1\x1d\x07\x2f\xc1\xc1\x7a\x14\x07\xc4\x00\x80\x05\ +\xae\xe0\xd4\xa2\x3e\x76\x3d\x9f\x13\xee\x4f\x24\xf6\x28\x0f\x2c\ +\x1a\x60\xe6\xf9\x0c\xd2\x4f\x2c\x44\x15\xf2\x27\x70\x33\xc4\x9e\ +\x94\xdc\x13\xe3\x38\xe0\x5f\x0e\x07\xcf\x01\x02\xdc\x82\x94\x3b\ +\xff\x0e\x84\x97\x01\x61\xac\xaa\x99\x8b\x5d\x26\xb8\xb9\x0e\xf6\ +\x88\x40\x04\xf2\x2f\x28\x9f\x00\x34\xa4\x20\x00\x0e\x80\x41\xf3\ +\xc8\x26\xd4\xc5\x5c\x4a\xe6\x7b\x96\x19\x3b\x4a\xe9\x73\xc0\x09\ +\x00\xc7\x65\xfe\x38\x38\xbc\x67\x83\x63\x34\xf3\xcf\x46\xd4\x11\ +\x21\x6d\xa2\x08\xf6\x3d\xcf\xf5\x19\xe3\x23\xe9\x7c\x69\x6e\x4f\ +\xb2\xd7\x02\xec\x6c\x89\x83\x1b\xa0\x60\xd0\xb7\x27\x1e\xa6\x84\ +\x71\x8f\x43\xfd\x06\x58\xb8\x01\xdc\x27\x2d\x04\x4f\xd2\xa3\x3e\ +\xd4\xaa\xa1\x72\x57\xf8\x81\xb4\x86\x44\x89\x03\x16\xc8\xc0\x3a\ +\x32\x65\x4d\x43\x2d\x11\xce\x01\x19\xd4\x95\x0e\xc4\x4e\x1d\xdd\ +\x21\xf7\xb6\xda\x25\x4e\x33\xad\x21\x2f\x70\x43\xe2\xc8\x1f\xce\ +\xf4\x47\xea\x77\x24\x15\x70\x7f\x79\x7b\xff\x33\x41\x22\x72\xf9\ +\xec\xec\x7c\xa9\x0e\x30\x56\xc1\xbd\xf9\xbf\x60\x49\xbb\x04\x9b\ +\xb9\xbf\x37\x61\xd8\x17\xd0\xe5\x39\xeb\xa1\xc1\x82\x33\x62\xe3\ +\x68\xec\x09\x70\x8c\x7e\xf8\x3d\xd2\x08\xa6\xce\xf2\xfa\x62\x6a\ +\xae\xc9\xd7\x17\x7f\x02\x3a\x43\xda\x26\ \x00\x00\x07\xc4\ \x00\ \x00\x37\x1e\x78\x9c\xed\x5b\x6d\x8f\x9b\x48\x12\xfe\x3e\xbf\x82\ @@ -33264,6 +33373,10 @@ qt_resource_name = "\ \x0a\xa2\x3b\x27\ \x00\x41\ \x00\x72\x00\x63\x00\x68\x00\x5f\x00\x43\x00\x68\x00\x65\x00\x63\x00\x6b\x00\x2e\x00\x73\x00\x76\x00\x67\ +\x00\x10\ +\x00\xf0\x67\xc7\ +\x00\x41\ +\x00\x72\x00\x63\x00\x68\x00\x5f\x00\x46\x00\x69\x00\x78\x00\x74\x00\x75\x00\x72\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\ \x00\x0d\ \x07\x4a\x92\xc7\ \x00\x41\ @@ -33344,8 +33457,8 @@ qt_resource_name = "\ qt_resource_struct = "\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x01\ -\x00\x00\x00\x10\x00\x02\x00\x00\x00\x01\x00\x00\x00\x3a\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x1f\x00\x00\x00\x1b\ +\x00\x00\x00\x10\x00\x02\x00\x00\x00\x01\x00\x00\x00\x3b\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x20\x00\x00\x00\x1b\ \x00\x00\x00\x1a\x00\x02\x00\x00\x00\x17\x00\x00\x00\x04\ \x00\x00\x01\x2e\x00\x00\x00\x00\x00\x01\x00\x02\x9d\x23\ \x00\x00\x02\x92\x00\x00\x00\x00\x00\x01\x00\x06\x6c\x9e\ @@ -33370,34 +33483,35 @@ qt_resource_struct = "\ \x00\x00\x01\x14\x00\x00\x00\x00\x00\x01\x00\x02\x52\xbc\ \x00\x00\x00\xe0\x00\x00\x00\x00\x00\x01\x00\x01\xbc\xaa\ \x00\x00\x02\x3e\x00\x00\x00\x00\x00\x01\x00\x05\x84\xf1\ -\x00\x00\x06\x96\x00\x01\x00\x00\x00\x01\x00\x07\xac\x79\ -\x00\x00\x05\x76\x00\x00\x00\x00\x00\x01\x00\x07\x63\x7d\ +\x00\x00\x05\x56\x00\x01\x00\x00\x00\x01\x00\x07\x5b\xb5\ +\x00\x00\x06\xbc\x00\x01\x00\x00\x00\x01\x00\x07\xb3\x28\ +\x00\x00\x05\x9c\x00\x00\x00\x00\x00\x01\x00\x07\x6a\x2c\ \x00\x00\x04\x12\x00\x00\x00\x00\x00\x01\x00\x07\x05\x81\ -\x00\x00\x07\xc6\x00\x01\x00\x00\x00\x01\x00\x08\x04\x4e\ -\x00\x00\x06\x68\x00\x01\x00\x00\x00\x01\x00\x07\xa5\xa4\ +\x00\x00\x07\xec\x00\x01\x00\x00\x00\x01\x00\x08\x0a\xfd\ +\x00\x00\x06\x8e\x00\x01\x00\x00\x00\x01\x00\x07\xac\x53\ \x00\x00\x04\x4c\x00\x01\x00\x00\x00\x01\x00\x07\x13\xf0\ \x00\x00\x04\x9e\x00\x01\x00\x00\x00\x01\x00\x07\x27\x77\ \x00\x00\x03\xb6\x00\x01\x00\x00\x00\x01\x00\x06\xea\xdf\ -\x00\x00\x07\x60\x00\x00\x00\x00\x00\x01\x00\x07\xe1\x0a\ -\x00\x00\x05\xb6\x00\x00\x00\x00\x00\x01\x00\x07\x7d\x57\ -\x00\x00\x05\x56\x00\x01\x00\x00\x00\x01\x00\x07\x5b\xb5\ +\x00\x00\x07\x86\x00\x00\x00\x00\x00\x01\x00\x07\xe7\xb9\ +\x00\x00\x05\xdc\x00\x00\x00\x00\x00\x01\x00\x07\x84\x06\ +\x00\x00\x05\x7c\x00\x01\x00\x00\x00\x01\x00\x07\x62\x64\ \x00\x00\x03\x94\x00\x01\x00\x00\x00\x01\x00\x06\xe1\xe6\ -\x00\x00\x06\x3c\x00\x01\x00\x00\x00\x01\x00\x07\x9a\x7a\ +\x00\x00\x06\x62\x00\x01\x00\x00\x00\x01\x00\x07\xa1\x29\ \x00\x00\x03\x38\x00\x01\x00\x00\x00\x01\x00\x06\xcf\xc5\ -\x00\x00\x07\x36\x00\x01\x00\x00\x00\x01\x00\x07\xd9\x75\ +\x00\x00\x07\x5c\x00\x01\x00\x00\x00\x01\x00\x07\xe0\x24\ \x00\x00\x04\x7a\x00\x01\x00\x00\x00\x01\x00\x07\x1d\x48\ \x00\x00\x03\x0e\x00\x01\x00\x00\x00\x01\x00\x06\xc6\x1d\ \x00\x00\x03\x74\x00\x01\x00\x00\x00\x01\x00\x06\xd9\x78\ -\x00\x00\x05\xe6\x00\x01\x00\x00\x00\x01\x00\x07\x8c\xc5\ +\x00\x00\x06\x0c\x00\x01\x00\x00\x00\x01\x00\x07\x93\x74\ \x00\x00\x05\x0a\x00\x00\x00\x00\x00\x01\x00\x07\x43\x72\ -\x00\x00\x06\x14\x00\x01\x00\x00\x00\x01\x00\x07\x92\x15\ +\x00\x00\x06\x3a\x00\x01\x00\x00\x00\x01\x00\x07\x98\xc4\ \x00\x00\x05\x34\x00\x01\x00\x00\x00\x01\x00\x07\x53\xf3\ -\x00\x00\x06\xc0\x00\x00\x00\x00\x00\x01\x00\x07\xb4\xbe\ +\x00\x00\x06\xe6\x00\x00\x00\x00\x00\x01\x00\x07\xbb\x6d\ \x00\x00\x04\xc2\x00\x01\x00\x00\x00\x01\x00\x07\x2c\x8e\ -\x00\x00\x07\x0a\x00\x01\x00\x00\x00\x01\x00\x07\xd0\xfb\ -\x00\x00\x06\xea\x00\x01\x00\x00\x00\x01\x00\x07\xc6\xc1\ -\x00\x00\x05\x96\x00\x01\x00\x00\x00\x01\x00\x07\x77\x3f\ -\x00\x00\x07\x8c\x00\x00\x00\x00\x00\x01\x00\x07\xf2\xd9\ +\x00\x00\x07\x30\x00\x01\x00\x00\x00\x01\x00\x07\xd7\xaa\ +\x00\x00\x07\x10\x00\x01\x00\x00\x00\x01\x00\x07\xcd\x70\ +\x00\x00\x05\xbc\x00\x01\x00\x00\x00\x01\x00\x07\x7d\xee\ +\x00\x00\x07\xb2\x00\x00\x00\x00\x00\x01\x00\x07\xf9\x88\ \x00\x00\x03\xe8\x00\x00\x00\x00\x00\x01\x00\x06\xf3\x21\ \x00\x00\x04\xec\x00\x00\x00\x00\x00\x01\x00\x07\x34\x76\ \x00\x00\x02\xda\x00\x01\x00\x00\x00\x01\x00\x06\xbe\xcd\ diff --git a/src/Mod/Arch/InitGui.py b/src/Mod/Arch/InitGui.py index 4a8d4ee9f..7d7fd9f5e 100644 --- a/src/Mod/Arch/InitGui.py +++ b/src/Mod/Arch/InitGui.py @@ -72,7 +72,8 @@ class ArchWorkbench(Workbench): self.archtools = ["Arch_Wall","Arch_Structure", "Arch_Floor","Arch_Building","Arch_Site", "Arch_Window","Arch_Roof","Arch_Axis", - "Arch_SectionPlane","Arch_Add","Arch_Remove"] + "Arch_SectionPlane","Arch_Add","Arch_Remove", + "Arch_Fixture"] self.meshtools = ["Arch_SplitMesh","Arch_MeshToShape", "Arch_SelectNonSolidMeshes","Arch_RemoveShape", "Arch_CloseHoles","Arch_MergeWalls"] diff --git a/src/Mod/Arch/Resources/Arch.qrc b/src/Mod/Arch/Resources/Arch.qrc index 8197a7a2c..4aafc08b0 100644 --- a/src/Mod/Arch/Resources/Arch.qrc +++ b/src/Mod/Arch/Resources/Arch.qrc @@ -31,6 +31,7 @@ icons/Arch_SelectNonManifold.svg icons/Arch_MergeWalls.svg icons/Arch_Wall_Tree_Assembly.svg + icons/Arch_Fixture.svg ui/archprefs-base.ui translations/Arch_af.qm translations/Arch_de.qm diff --git a/src/Mod/Arch/Resources/icons/Arch_Fixture.svg b/src/Mod/Arch/Resources/icons/Arch_Fixture.svg new file mode 100644 index 000000000..ee11cd0a8 --- /dev/null +++ b/src/Mod/Arch/Resources/icons/Arch_Fixture.svg @@ -0,0 +1,243 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + From 7de742b436548ba7d22346bc035a8a8d625bb910 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 7 Jul 2013 21:19:19 +0200 Subject: [PATCH 158/160] 0000735: Feature request for better Fillet/Chamfer --- src/Mod/Part/Gui/DlgFilletEdges.cpp | 80 +++++++++++++++++++++++++++++ src/Mod/Part/Gui/DlgFilletEdges.h | 1 + 2 files changed, 81 insertions(+) diff --git a/src/Mod/Part/Gui/DlgFilletEdges.cpp b/src/Mod/Part/Gui/DlgFilletEdges.cpp index f241f656b..f53fc7445 100644 --- a/src/Mod/Part/Gui/DlgFilletEdges.cpp +++ b/src/Mod/Part/Gui/DlgFilletEdges.cpp @@ -43,10 +43,13 @@ # include # include # include +# include +# include #endif #include "DlgFilletEdges.h" #include "ui_DlgFilletEdges.h" +#include "SoBrepShape.h" #include "../App/PartFeature.h" #include "../App/FeatureFillet.h" @@ -60,7 +63,9 @@ #include #include #include +#include #include +#include using namespace PartGui; @@ -250,6 +255,81 @@ void DlgFilletEdges::onSelectionChanged(const Gui::SelectionChanges& msg) } } } + + if (msg.Type != Gui::SelectionChanges::SetPreselect && + msg.Type != Gui::SelectionChanges::RmvPreselect) + QTimer::singleShot(20, this, SLOT(onHighlightEdges())); +} + +void DlgFilletEdges::onHighlightEdges() +{ + Gui::ViewProvider* view = Gui::Application::Instance->getViewProvider(d->object); + if (view) { + // deselect all faces + { + SoSearchAction searchAction; + searchAction.setType(PartGui::SoBrepFaceSet::getClassTypeId()); + searchAction.setInterest(SoSearchAction::FIRST); + searchAction.apply(view->getRoot()); + SoPath* selectionPath = searchAction.getPath(); + if (selectionPath) { + Gui::SoSelectionElementAction action(Gui::SoSelectionElementAction::None); + action.apply(selectionPath); + } + } + // deselect all points + { + SoSearchAction searchAction; + searchAction.setType(PartGui::SoBrepPointSet::getClassTypeId()); + searchAction.setInterest(SoSearchAction::FIRST); + searchAction.apply(view->getRoot()); + SoPath* selectionPath = searchAction.getPath(); + if (selectionPath) { + Gui::SoSelectionElementAction action(Gui::SoSelectionElementAction::None); + action.apply(selectionPath); + } + } + // select the edges + { + SoSearchAction searchAction; + searchAction.setType(PartGui::SoBrepEdgeSet::getClassTypeId()); + searchAction.setInterest(SoSearchAction::FIRST); + searchAction.apply(view->getRoot()); + SoPath* selectionPath = searchAction.getPath(); + if (selectionPath) { + ParameterGrp::handle hGrp = Gui::WindowParameter::getDefaultParameter()->GetGroup("View"); + SbColor selectionColor(0.1f, 0.8f, 0.1f); + unsigned long selection = (unsigned long)(selectionColor.getPackedValue()); + selection = hGrp->GetUnsigned("SelectionColor", selection); + float transparency; + selectionColor.setPackedValue((uint32_t)selection, transparency); + + // clear the selection first + Gui::SoSelectionElementAction clear(Gui::SoSelectionElementAction::None); + clear.apply(selectionPath); + + Gui::SoSelectionElementAction action(Gui::SoSelectionElementAction::Append); + action.setColor(selectionColor); + action.apply(selectionPath); + + QAbstractItemModel* model = ui->treeView->model(); + SoLineDetail detail; + action.setElement(&detail); + for (int i=0; irowCount(); ++i) { + QVariant value = model->index(i,0).data(Qt::CheckStateRole); + Qt::CheckState checkState = static_cast(value.toInt()); + + // is item checked + if (checkState & Qt::Checked) { + // the index value of the edge + int id = model->index(i,0).data(Qt::UserRole).toInt(); + detail.setLineIndex(id-1); + action.apply(selectionPath); + } + } + } + } + } } void DlgFilletEdges::onSelectEdge(const QString& subelement, int type) diff --git a/src/Mod/Part/Gui/DlgFilletEdges.h b/src/Mod/Part/Gui/DlgFilletEdges.h index 46df51366..0fab0dbeb 100644 --- a/src/Mod/Part/Gui/DlgFilletEdges.h +++ b/src/Mod/Part/Gui/DlgFilletEdges.h @@ -103,6 +103,7 @@ private Q_SLOTS: void on_filletStartRadius_valueChanged(double); void on_filletEndRadius_valueChanged(double); void toggleCheckState(const QModelIndex&); + void onHighlightEdges(); private: std::auto_ptr ui; From fc845d6faec6d755cef145c4089fc2704048fe1f Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 8 Jul 2013 17:18:46 +0200 Subject: [PATCH 159/160] 0000641: Make Clipping-Plane-placement editable + support multiple planes --- src/Gui/CMakeLists.txt | 7 + src/Gui/Clipping.cpp | 314 ++++++++++++++++++++++++++++++++++++++++ src/Gui/Clipping.h | 88 +++++++++++ src/Gui/Clipping.ui | 244 +++++++++++++++++++++++++++++++ src/Gui/CommandView.cpp | 16 ++ 5 files changed, 669 insertions(+) create mode 100644 src/Gui/Clipping.cpp create mode 100644 src/Gui/Clipping.h create mode 100644 src/Gui/Clipping.ui diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 3c442c80f..8ecf08ac0 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -122,6 +122,7 @@ set(Gui_MOC_HDRS CallTips.h CombiView.h Control.h + Clipping.h DemoMode.h DownloadDialog.h DownloadItem.h @@ -213,6 +214,7 @@ fc_wrap_cpp(Gui_MOC_SRCS ${Gui_MOC_HDRS}) SET(Gui_UIC_SRCS AboutApplication.ui + Clipping.ui DemoMode.ui DlgActions.ui DlgActivateWindow.ui @@ -289,6 +291,7 @@ SOURCE_GROUP("Command" FILES ${Command_SRCS}) # The dialog sources SET(Dialog_CPP_SRCS + Clipping.cpp DemoMode.cpp DlgActivateWindowImp.cpp DlgDisplayPropertiesImp.cpp @@ -316,6 +319,7 @@ SET(Dialog_CPP_SRCS ) SET(Dialog_HPP_SRCS + Clipping.h DemoMode.h DlgActivateWindowImp.h DlgDisplayPropertiesImp.h @@ -346,11 +350,14 @@ SET(Dialog_SRCS ${Dialog_CPP_SRCS} ${Dialog_HPP_SRCS} AboutApplication.ui + Clipping.ui DemoMode.ui DlgActivateWindow.ui DlgAuthorization.ui DlgDisplayProperties.ui DlgInputDialog.ui + DlgLocationAngle.ui + DlgLocationPos.ui DlgMacroExecute.ui DlgRunExternal.ui DlgMacroRecord.ui diff --git a/src/Gui/Clipping.cpp b/src/Gui/Clipping.cpp new file mode 100644 index 000000000..cf1240465 --- /dev/null +++ b/src/Gui/Clipping.cpp @@ -0,0 +1,314 @@ +/*************************************************************************** + * Copyright (c) 2013 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., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +# include +# include +#endif +# include + +#include "Clipping.h" +#include "ui_Clipping.h" +#include "Application.h" +#include "View3DInventor.h" +#include "View3DInventorViewer.h" + +using namespace Gui::Dialog; + +class Clipping::Private { +public: + Ui_Clipping ui; + QPointer view; + SoGroup* node; + SoClipPlane* clipX; + SoClipPlane* clipY; + SoClipPlane* clipZ; + SoClipPlane* clipView; + bool flipX; + bool flipY; + bool flipZ; + SoTimerSensor* sensor; + Private() : flipX(false), flipY(false), flipZ(false) + { + clipX = new SoClipPlane(); + clipX->on.setValue(false); + clipX->plane.setValue(SbPlane(SbVec3f(1,0,0),0)); + clipX->ref(); + + clipY = new SoClipPlane(); + clipY->on.setValue(false); + clipY->plane.setValue(SbPlane(SbVec3f(0,1,0),0)); + clipY->ref(); + + clipZ = new SoClipPlane(); + clipZ->on.setValue(false); + clipZ->plane.setValue(SbPlane(SbVec3f(0,0,1),0)); + clipZ->ref(); + + clipView = new SoClipPlane(); + clipView->on.setValue(false); + clipView->plane.setValue(SbPlane(SbVec3f(0,0,1),0)); + clipView->ref(); + + sensor = new SoTimerSensor(moveCallback, this); + } + ~Private() + { + clipX->unref(); + clipY->unref(); + clipZ->unref(); + clipView->unref(); + delete sensor; + } + static void moveCallback(void * data, SoSensor * sensor) + { + Private* self = reinterpret_cast(data); + if (self->view) { + Gui::View3DInventorViewer* view = self->view->getViewer(); + SoClipPlane* clip = self->clipView; + SbPlane pln = clip->plane.getValue(); + clip->plane.setValue(SbPlane(view->getViewDirection(),pln.getDistanceFromOrigin())); + } + } +}; + +/* TRANSLATOR Gui::Dialog::Clipping */ + +Clipping::Clipping(Gui::View3DInventor* view, QWidget* parent) + : QWidget(parent), d(new Private) +{ + // create widgets + d->ui.setupUi(this); + d->ui.clipView->setRange(-INT_MAX,INT_MAX); + d->ui.clipView->setSingleStep(0.1f); + d->ui.clipX->setRange(-INT_MAX,INT_MAX); + d->ui.clipX->setSingleStep(0.1f); + d->ui.clipY->setRange(-INT_MAX,INT_MAX); + d->ui.clipY->setSingleStep(0.1f); + d->ui.clipZ->setRange(-INT_MAX,INT_MAX); + d->ui.clipZ->setSingleStep(0.1f); + + d->ui.dirX->setRange(-INT_MAX,INT_MAX); + d->ui.dirX->setSingleStep(0.1f); + d->ui.dirY->setRange(-INT_MAX,INT_MAX); + d->ui.dirY->setSingleStep(0.1f); + d->ui.dirZ->setRange(-INT_MAX,INT_MAX); + d->ui.dirZ->setSingleStep(0.1f); + d->ui.dirZ->setValue(1.0f); + + d->view = view; + View3DInventorViewer* viewer = view->getViewer(); + d->node = static_cast(viewer->getSceneGraph()); + d->node->ref(); + d->node->insertChild(d->clipX, 0); + d->node->insertChild(d->clipY, 0); + d->node->insertChild(d->clipZ, 0); + d->node->insertChild(d->clipView, 0); + + SoGetBoundingBoxAction action(viewer->getViewportRegion()); + action.apply(viewer->getSceneGraph()); + SbBox3f box = action.getBoundingBox(); + + if (!box.isEmpty()) { + SbVec3f cnt = box.getCenter(); + d->ui.clipView->setValue(cnt[2]); + d->ui.clipX->setValue(cnt[0]); + d->ui.clipY->setValue(cnt[1]); + d->ui.clipZ->setValue(cnt[2]); + } +} + +/** Destroys the object and frees any allocated resources */ +Clipping::~Clipping() +{ + d->node->removeChild(d->clipX); + d->node->removeChild(d->clipY); + d->node->removeChild(d->clipZ); + d->node->removeChild(d->clipView); + d->node->unref(); + delete d; +} + +void Clipping::on_groupBoxX_toggled(bool on) +{ + if (on) { + d->ui.groupBoxView->setChecked(false); + } + + d->clipX->on.setValue(on); +} + +void Clipping::on_groupBoxY_toggled(bool on) +{ + if (on) { + d->ui.groupBoxView->setChecked(false); + } + + d->clipY->on.setValue(on); +} + +void Clipping::on_groupBoxZ_toggled(bool on) +{ + if (on) { + d->ui.groupBoxView->setChecked(false); + } + + d->clipZ->on.setValue(on); +} + +void Clipping::on_clipX_valueChanged(double val) +{ + SbPlane pln = d->clipX->plane.getValue(); + d->clipX->plane.setValue(SbPlane(pln.getNormal(),d->flipX ? -val : val)); +} + +void Clipping::on_clipY_valueChanged(double val) +{ + SbPlane pln = d->clipY->plane.getValue(); + d->clipY->plane.setValue(SbPlane(pln.getNormal(),d->flipY ? -val : val)); +} + +void Clipping::on_clipZ_valueChanged(double val) +{ + SbPlane pln = d->clipZ->plane.getValue(); + d->clipZ->plane.setValue(SbPlane(pln.getNormal(),d->flipZ ? -val : val)); +} + +void Clipping::on_flipClipX_clicked() +{ + d->flipX = !d->flipX; + SbPlane pln = d->clipX->plane.getValue(); + d->clipX->plane.setValue(SbPlane(-pln.getNormal(),-pln.getDistanceFromOrigin())); +} + +void Clipping::on_flipClipY_clicked() +{ + d->flipY = !d->flipY; + SbPlane pln = d->clipY->plane.getValue(); + d->clipY->plane.setValue(SbPlane(-pln.getNormal(),-pln.getDistanceFromOrigin())); +} + +void Clipping::on_flipClipZ_clicked() +{ + d->flipZ = !d->flipZ; + SbPlane pln = d->clipZ->plane.getValue(); + d->clipZ->plane.setValue(SbPlane(-pln.getNormal(),-pln.getDistanceFromOrigin())); +} + +void Clipping::on_groupBoxView_toggled(bool on) +{ + if (on) { + d->ui.groupBoxX->setChecked(false); + d->ui.groupBoxY->setChecked(false); + d->ui.groupBoxZ->setChecked(false); + } + + d->clipView->on.setValue(on); +} + +void Clipping::on_clipView_valueChanged(double val) +{ + SbPlane pln = d->clipView->plane.getValue(); + d->clipView->plane.setValue(SbPlane(pln.getNormal(),val)); +} + +void Clipping::on_fromView_clicked() +{ + if (d->view) { + Gui::View3DInventorViewer* view = d->view->getViewer(); + SbVec3f dir = view->getViewDirection(); + SbPlane pln = d->clipView->plane.getValue(); + d->clipView->plane.setValue(SbPlane(dir,pln.getDistanceFromOrigin())); + } +} + +void Clipping::on_adjustViewdirection_toggled(bool on) +{ + d->ui.dirX->setDisabled(on); + d->ui.dirY->setDisabled(on); + d->ui.dirZ->setDisabled(on); + d->ui.fromView->setDisabled(on); + + if (on) + d->sensor->schedule(); + else + d->sensor->unschedule(); +} + +void Clipping::on_dirX_valueChanged(double) +{ + double x = d->ui.dirX->value(); + double y = d->ui.dirY->value(); + double z = d->ui.dirZ->value(); + + SbPlane pln = d->clipView->plane.getValue(); + SbVec3f normal(x,y,z); + if (normal.sqrLength() > 0.0f) + d->clipView->plane.setValue(SbPlane(normal,pln.getDistanceFromOrigin())); +} + +void Clipping::on_dirY_valueChanged(double) +{ + double x = d->ui.dirX->value(); + double y = d->ui.dirY->value(); + double z = d->ui.dirZ->value(); + + SbPlane pln = d->clipView->plane.getValue(); + SbVec3f normal(x,y,z); + if (normal.sqrLength() > 0.0f) + d->clipView->plane.setValue(SbPlane(normal,pln.getDistanceFromOrigin())); +} + +void Clipping::on_dirZ_valueChanged(double) +{ + double x = d->ui.dirX->value(); + double y = d->ui.dirY->value(); + double z = d->ui.dirZ->value(); + + SbPlane pln = d->clipView->plane.getValue(); + SbVec3f normal(x,y,z); + if (normal.sqrLength() > 0.0f) + d->clipView->plane.setValue(SbPlane(normal,pln.getDistanceFromOrigin())); +} + +// --------------------------------------- + +/* TRANSLATOR Gui::Dialog::TaskClipping */ + +TaskClipping::TaskClipping(Gui::View3DInventor* view) +{ + QWidget* widget = new Clipping(view); + Gui::TaskView::TaskBox* taskbox = new Gui::TaskView::TaskBox( + QPixmap(), widget->windowTitle(), false, 0); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskClipping::~TaskClipping() +{ + // automatically deleted in the sub-class +} + +#include "moc_Clipping.cpp" diff --git a/src/Gui/Clipping.h b/src/Gui/Clipping.h new file mode 100644 index 000000000..67b0fa079 --- /dev/null +++ b/src/Gui/Clipping.h @@ -0,0 +1,88 @@ +/*************************************************************************** + * Copyright (c) 2013 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., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef GUI_DIALOG_CLIPPING_H +#define GUI_DIALOG_CLIPPING_H + +#include +#include +#include + +namespace Gui { +class View3DInventor; +namespace Dialog { + +/** + * @author Werner Mayer + */ +class GuiExport Clipping : public QWidget +{ + Q_OBJECT + +public: + Clipping(Gui::View3DInventor* view, QWidget* parent = 0); + ~Clipping(); + +protected Q_SLOTS: + void on_groupBoxX_toggled(bool); + void on_groupBoxY_toggled(bool); + void on_groupBoxZ_toggled(bool); + void on_clipX_valueChanged(double); + void on_clipY_valueChanged(double); + void on_clipZ_valueChanged(double); + void on_flipClipX_clicked(); + void on_flipClipY_clicked(); + void on_flipClipZ_clicked(); + void on_groupBoxView_toggled(bool); + void on_clipView_valueChanged(double); + void on_fromView_clicked(); + void on_adjustViewdirection_toggled(bool); + void on_dirX_valueChanged(double); + void on_dirY_valueChanged(double); + void on_dirZ_valueChanged(double); + +private: + +private: + class Private; + Private* d; +}; + +/** + * Embed the panel into a task dialog. + */ +class TaskClipping : public Gui::TaskView::TaskDialog +{ +public: + TaskClipping(Gui::View3DInventor* view); + ~TaskClipping(); + +public: + virtual QDialogButtonBox::StandardButtons getStandardButtons() const + { return QDialogButtonBox::Close; } +}; + +} // namespace Dialog +} // namespace Gui + +#endif // GUI_DIALOG_CLIPPING_H diff --git a/src/Gui/Clipping.ui b/src/Gui/Clipping.ui new file mode 100644 index 000000000..3cb877568 --- /dev/null +++ b/src/Gui/Clipping.ui @@ -0,0 +1,244 @@ + + + Gui::Dialog::Clipping + + + + 0 + 0 + 304 + 430 + + + + Clipping + + + + + + Clipping X + + + true + + + false + + + + + + + + + Flip + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Offset + + + + + + + + + + Clipping Y + + + true + + + false + + + + + + + + + Flip + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Offset + + + + + + + + + + Clipping Z + + + true + + + false + + + + + + + + + Flip + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Offset + + + + + + + + + + Clipping custom direction + + + true + + + false + + + + + + Qt::Horizontal + + + + 84 + 20 + + + + + + + + View + + + + + + + Adjust to view direction + + + + + + + Direction + + + + + + + + + + + + + + + + + + Offset + + + + + + + + + + + + + groupBoxX + clipX + flipClipX + groupBoxY + clipY + flipClipY + groupBoxZ + clipZ + flipClipZ + groupBoxView + clipView + fromView + adjustViewdirection + dirX + dirY + dirZ + + + + diff --git a/src/Gui/CommandView.cpp b/src/Gui/CommandView.cpp index bdcbb1336..ee441c695 100644 --- a/src/Gui/CommandView.cpp +++ b/src/Gui/CommandView.cpp @@ -38,6 +38,7 @@ #include "Application.h" #include "BitmapFactory.h" #include "Control.h" +#include "Clipping.h" #include "FileDialog.h" #include "MainWindow.h" #include "Tree.h" @@ -474,12 +475,15 @@ StdCmdToggleClipPlane::StdCmdToggleClipPlane() Action * StdCmdToggleClipPlane::createAction(void) { Action *pcAction = (Action*)Command::createAction(); +#if 0 pcAction->setCheckable(true); +#endif return pcAction; } void StdCmdToggleClipPlane::activated(int iMsg) { +#if 0 View3DInventor* view = qobject_cast(getMainWindow()->activeWindow()); if (view) { if (iMsg > 0 && !view->hasClippingPlane()) @@ -487,10 +491,17 @@ void StdCmdToggleClipPlane::activated(int iMsg) else if (iMsg == 0 && view->hasClippingPlane()) view->toggleClippingPlane(); } +#else + View3DInventor* view = qobject_cast(getMainWindow()->activeWindow()); + if (view) { + Gui::Control().showDialog(new Gui::Dialog::TaskClipping(view)); + } +#endif } bool StdCmdToggleClipPlane::isActive(void) { +#if 0 View3DInventor* view = qobject_cast(getMainWindow()->activeWindow()); if (view) { Action* action = qobject_cast(_pcAction); @@ -504,6 +515,11 @@ bool StdCmdToggleClipPlane::isActive(void) action->setChecked(false); return false; } +#else + if (Gui::Control().activeDialog()) + return false; + return true; +#endif } DEF_STD_CMD_ACL(StdCmdDrawStyle); From 7e13921de4fa3f4bca9d965e9887c89ab58072b9 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 8 Jul 2013 17:26:50 +0200 Subject: [PATCH 160/160] 0000641: Make Clipping-Plane-placement editable + support multiple planes --- src/Gui/Clipping.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Gui/Clipping.cpp b/src/Gui/Clipping.cpp index cf1240465..7aacc7a37 100644 --- a/src/Gui/Clipping.cpp +++ b/src/Gui/Clipping.cpp @@ -23,6 +23,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include # include # include # include

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 literal 148474 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