Merge branch 'master' of ssh://free-cad.git.sourceforge.net/gitroot/free-cad/free-cad

This commit is contained in:
jriegel 2012-08-15 09:24:43 +02:00
commit 413437fd6b
68 changed files with 5263 additions and 1737 deletions

View File

@ -152,6 +152,7 @@ SET(FreeCADBase_XML_SRCS
SOURCE_GROUP("XML" FILES ${FreeCADBase_XML_SRCS})
set(FreeCADBase_MOC_HDRS
Debugger.h
FutureWatcherProgress.h
)
fc_wrap_cpp(FreeCADBase_MOC_SRCS ${FreeCADBase_MOC_HDRS})
@ -182,6 +183,7 @@ SET(FreeCADBase_CPP_SRCS
BoundBoxPyImp.cpp
Builder3D.cpp
Console.cpp
Debugger.cpp
Exception.cpp
Factory.cpp
FileInfo.cpp
@ -234,6 +236,7 @@ SET(FreeCADBase_HPP_SRCS
BoundBox.h
Builder3D.h
Console.h
Debugger.h
Exception.h
Factory.h
FileInfo.h

80
src/Base/Debugger.cpp Normal file
View File

@ -0,0 +1,80 @@
/***************************************************************************
* Copyright (c) 2012 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 51 Franklin Street, *
* Fifth Floor, Boston, MA 02110-1301, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <QCoreApplication>
# include <QEvent>
#endif
#include "Debugger.h"
#include "Console.h"
using namespace Base;
Debugger::Debugger(QObject* parent)
: QObject(parent), isAttached(false)
{
}
Debugger::~Debugger()
{
}
void Debugger::attach()
{
QCoreApplication::instance()->installEventFilter(this);
isAttached = true;
}
void Debugger::detach()
{
QCoreApplication::instance()->removeEventFilter(this);
isAttached = false;
}
bool Debugger::eventFilter(QObject*, QEvent* event)
{
if (event->type() == QEvent::KeyPress) {
if (loop.isRunning()) {
loop.quit();
return true;
}
}
return false;
}
int Debugger::exec()
{
if (isAttached)
Base::Console().Message("TO CONTINUE PRESS ANY KEY...\n");
return loop.exec();
}
void Debugger::quit()
{
loop.quit();
}
#include "moc_Debugger.cpp"

76
src/Base/Debugger.h Normal file
View File

@ -0,0 +1,76 @@
/***************************************************************************
* Copyright (c) 2012 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 51 Franklin Street, *
* Fifth Floor, Boston, MA 02110-1301, USA *
* *
***************************************************************************/
#ifndef BASE_DEBUGGER_H
#define BASE_DEBUGGER_H
#include <QObject>
#include <QEventLoop>
namespace Base {
/**
This is a utility class to break the application at a point to inspect e.g. the result of
an algorithm.
You usually use it like this
\code
...
Base::Debugger dbg;
dbg.attach();
dbg.exec();
...
\endcode
Or you can connect it with a button and let the user click it in order to continue.
\code
QPushButton* btn = new QPushButton();
btn->setText("Continue");
btn->show();
Base::Debugger dbg;
connect(btn, SIGNAL(clicked()), &dbg, SLOT(quit()));
dbg.exec();
\endcode
\author Werner Mayer
*/
class BaseExport Debugger : public QObject
{
Q_OBJECT
public:
Debugger(QObject* parent=0);
~Debugger();
void attach();
void detach();
bool eventFilter(QObject*, QEvent*);
int exec();
public Q_SLOTS:
void quit();
private:
bool isAttached;
QEventLoop loop;
};
}
#endif // BASE_DEBUGGER_H

View File

@ -105,6 +105,8 @@
// QtCore
#include <QBuffer>
#include <QByteArray>
#include <QCoreApplication>
#include <QEvent>
#include <QIODevice>
#include <QDataStream>
#include <QWriteLocker>

View File

@ -1457,9 +1457,10 @@ namespace Gui {
*/
class GUIApplication : public GUIApplicationNativeEventAware
{
int systemExit;
public:
GUIApplication(int & argc, char ** argv)
: GUIApplicationNativeEventAware(argc, argv)
GUIApplication(int & argc, char ** argv, int exitcode)
: GUIApplicationNativeEventAware(argc, argv), systemExit(exitcode)
{
}
@ -1480,6 +1481,10 @@ public:
else
return QApplication::notify(receiver, event);
}
catch (const Base::SystemExitException&) {
qApp->exit(systemExit);
return true;
}
catch (const Base::Exception& e) {
Base::Console().Error("Unhandled Base::Exception caught in GUIApplication::notify.\n"
"The error message is: %s\n", e.what());
@ -1543,7 +1548,8 @@ void Application::runApplication(void)
Base::Console().Log("Init: Creating Gui::Application and QApplication\n");
// if application not yet created by the splasher
int argc = App::Application::GetARGC();
GUIApplication mainApp(argc, App::Application::GetARGV());
int systemExit = 1000;
GUIApplication mainApp(argc, App::Application::GetARGV(), systemExit);
// set application icon and window title
const std::map<std::string,std::string>& cfg = App::Application::Config();
std::map<std::string,std::string>::const_iterator it;
@ -1716,9 +1722,15 @@ void Application::runApplication(void)
Base::Console().Log("Init: Entering event loop\n");
try {
mainApp.exec();
int ret = mainApp.exec();
if (ret == systemExit)
throw Base::SystemExitException();
}
catch(...) {
catch (const Base::SystemExitException&) {
Base::Console().Message("System exit\n");
throw;
}
catch (...) {
// catching nasty stuff coming out of the event loop
App::Application::destructObserver();
Base::Console().Error("Event loop left through unhandled exception\n");

View File

@ -281,6 +281,9 @@ void Command::invoke(int i)
if (isActive())
activated( i );
}
catch (const Base::SystemExitException&) {
throw;
}
catch (Base::PyException &e) {
e.ReportException();
Base::Console().Error("Stack Trace: %s\n",e.getStackTrace().c_str());

View File

@ -66,10 +66,14 @@ void DlgSettingsViewColor::saveSettings()
checkBoxSelection->onSave();
HighlightColor->onSave();
SelectionColor->onSave();
CursorTextColor->onSave();
EditedEdgeColor->onSave();
EditedVertexColor->onSave();
ConstructionColor->onSave();
FullyConstrainedColor->onSave();
DefaultShapeColor->onSave();
DefaultShapeLineColor->onSave();
DefaultShapeLineWidth->onSave();
}
void DlgSettingsViewColor::loadSettings()
@ -85,10 +89,14 @@ void DlgSettingsViewColor::loadSettings()
checkBoxSelection->onRestore();
HighlightColor->onRestore();
SelectionColor->onRestore();
CursorTextColor->onRestore();
EditedEdgeColor->onRestore();
EditedVertexColor->onRestore();
ConstructionColor->onRestore();
FullyConstrainedColor->onRestore();
DefaultShapeColor->onRestore();
DefaultShapeLineColor->onRestore();
DefaultShapeLineWidth->onRestore();
}
/**

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>601</width>
<height>407</height>
<height>445</height>
</rect>
</property>
<property name="windowTitle">
@ -361,7 +361,20 @@
<string>Default colors</string>
</property>
<layout class="QGridLayout" name="colgridLayout">
<item row="0" column="0">
<item row="2" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0">
<layout class="QGridLayout" name="_2">
<property name="margin">
<number>0</number>
@ -369,7 +382,7 @@
<property name="spacing">
<number>6</number>
</property>
<item row="0" column="0">
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="minimumSize">
<size>
@ -382,28 +395,28 @@
</property>
</widget>
</item>
<item row="1" column="0">
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Edited vertex color</string>
</property>
</widget>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Construction geometry</string>
</property>
</widget>
</item>
<item row="3" column="0">
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Fully constrained geometry</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="3" column="1">
<widget class="Gui::PrefColorButton" name="ConstructionColor">
<property name="toolTip">
<string>The color of construction geometry in edit mode</string>
@ -423,7 +436,7 @@
</property>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="1">
<widget class="Gui::PrefColorButton" name="FullyConstrainedColor">
<property name="toolTip">
<string>The color of fully constrained geometry in edit mode</string>
@ -443,7 +456,7 @@
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="Gui::PrefColorButton" name="EditedVertexColor">
<property name="toolTip">
<string>The color of vertices being edited</string>
@ -463,7 +476,7 @@
</property>
</widget>
</item>
<item row="0" column="1">
<item row="1" column="1">
<widget class="Gui::PrefColorButton" name="EditedEdgeColor">
<property name="toolTip">
<string>The color of edges being edited</string>
@ -483,20 +496,124 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Cursor text color</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::PrefColorButton" name="CursorTextColor">
<property name="color">
<color>
<red>0</red>
<green>0</green>
<blue>255</blue>
</color>
</property>
<property name="prefEntry" stdset="0">
<cstring>CursorTextColor</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>View</cstring>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
<item row="0" column="0">
<layout class="QGridLayout" name="_1">
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="minimumSize">
<size>
<width>240</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Default shape color</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::PrefColorButton" name="DefaultShapeColor">
<property name="toolTip">
<string>The default color for new shapes</string>
</property>
<property name="color">
<color>
<red>204</red>
<green>204</green>
<blue>204</blue>
</color>
</property>
<property name="prefEntry" stdset="0">
<cstring>DefaultShapeColor</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>View</cstring>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="_5">
<item row="0" column="0">
<widget class="QLabel" name="label_7">
<property name="minimumSize">
<size>
<width>182</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Default line width and color</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="Gui::PrefColorButton" name="DefaultShapeLineColor">
<property name="toolTip">
<string>The default line color for new shapes</string>
</property>
<property name="color">
<color>
<red>25</red>
<green>25</green>
<blue>25</blue>
</color>
</property>
<property name="prefEntry" stdset="0">
<cstring>DefaultShapeLineColor</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>View</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::PrefSpinBox" name="DefaultShapeLineWidth">
<property name="toolTip">
<string>The default line thickness for new shapes</string>
</property>
<property name="suffix">
<string>px</string>
</property>
<property name="value">
<number>2</number>
</property>
<property name="prefEntry" stdset="0">
<cstring>DefaultShapeLineWidth</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>View</cstring>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
@ -509,6 +626,11 @@
<extends>QPushButton</extends>
<header>Gui/Widgets.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefSpinBox</class>
<extends>QSpinBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefColorButton</class>
<extends>Gui::ColorButton</extends>
@ -530,6 +652,11 @@
<tabstop>checkBoxSelection</tabstop>
<tabstop>HighlightColor</tabstop>
<tabstop>SelectionColor</tabstop>
<tabstop>CursorTextColor</tabstop>
<tabstop>EditedEdgeColor</tabstop>
<tabstop>EditedVertexColor</tabstop>
<tabstop>ConstructionColor</tabstop>
<tabstop>FullyConstrainedColor</tabstop>
<tabstop>radioButtonSimple</tabstop>
<tabstop>radioButtonGradient</tabstop>
<tabstop>checkMidColor</tabstop>

View File

@ -187,6 +187,9 @@ bool Document::setEdit(Gui::ViewProvider* p, int ModNum)
View3DInventor *activeView = dynamic_cast<View3DInventor *>(getActiveView());
if (activeView && activeView->getViewer()->setEditingViewProvider(p,ModNum)) {
d->_pcInEdit = p;
Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog();
if (dlg)
dlg->setDocumentName(this->getDocument()->getName());
if (d->_pcInEdit->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId()))
signalInEdit(*(static_cast<ViewProviderDocumentObject*>(d->_pcInEdit)));
}

View File

@ -233,7 +233,7 @@ void MacroManager::run(MacroType eType,const char *sName)
Base::Interpreter().runFile(sName, this->localEnv);
}
catch (const Base::SystemExitException&) {
qApp->quit();
throw;
}
catch (const Base::PyException& e) {
Base::Console().Error("%s%s: %s\n",

View File

@ -1157,8 +1157,7 @@ void MainWindow::delayedStartup()
App::Application::processCmdLineFiles();
}
catch (const Base::SystemExitException&) {
QApplication::quit();
return;
throw;
}
const std::map<std::string,std::string>& cfg = App::Application::Config();

View File

@ -709,7 +709,7 @@ void PythonConsole::runSource(const QString& line)
}
if (ret == QMessageBox::Yes) {
PyErr_Clear();
qApp->quit();
throw;
}
else {
PyErr_Clear();

View File

@ -69,6 +69,8 @@ public:
const std::string& getDocumentName() const
{ return documentName; }
void setDocumentName(const std::string& doc)
{ documentName = doc; }
virtual bool isAllowedAlterDocument(void) const
{ return false; }
virtual bool isAllowedAlterView(void) const
@ -94,6 +96,8 @@ protected:
/// List of TaskBoxes of that dialog
std::vector<QWidget*> Content;
ButtonPosition pos;
private:
std::string documentName;
};

View File

@ -63,14 +63,17 @@
using namespace Gui;
PROPERTY_SOURCE(Gui::ViewProviderGeometryObject, Gui::ViewProviderDocumentObject)
const App::PropertyIntegerConstraint::Constraints intPercent = {0,100,1};
ViewProviderGeometryObject::ViewProviderGeometryObject() : pcBoundSwitch(0)
{
ADD_PROPERTY(ShapeColor,(0.8f,0.8f,0.8f));
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
unsigned long shcol = hGrp->GetUnsigned("DefaultShapeColor",3435973887UL); // light gray (204,204,204)
float r,g,b;
r = ((shcol >> 24) & 0xff) / 255.0; g = ((shcol >> 16) & 0xff) / 255.0; b = ((shcol >> 8) & 0xff) / 255.0;
ADD_PROPERTY(ShapeColor,(r, g, b));
ADD_PROPERTY(Transparency,(0));
Transparency.setConstraints(&intPercent);
App::Material mat(App::Material::DEFAULT);
@ -86,7 +89,8 @@ ViewProviderGeometryObject::ViewProviderGeometryObject() : pcBoundSwitch(0)
pcShapeMaterial = new SoMaterial;
pcShapeMaterial->ref();
ShapeMaterial.touch();
//ShapeMaterial.touch(); materials are rarely used, so better to initialize with default shape color
ShapeColor.touch();
pcBoundingBox = new Gui::SoFCBoundingBox;
pcBoundingBox->ref();

View File

@ -498,6 +498,8 @@ const char* ViewProviderPythonFeatureImp::getDefaultDisplayMode() const
Py::Callable method(vp.getAttr(std::string("getDefaultDisplayMode")));
Py::Tuple args(0);
Py::String str(method.apply(args));
if (str.isUnicode())
str = str.encode("ascii"); // json converts strings into unicode
mode = str.as_std_string();
return mode.c_str();
}

View File

@ -300,6 +300,9 @@ int main( int argc, char ** argv )
else
App::Application::runApplication();
}
catch (const Base::SystemExitException&) {
exit(0);
}
catch (const Base::Exception& e) {
Base::Console().Error("%s\n", e.what());
}

View File

@ -43,6 +43,22 @@ def getStringList(objects):
result += "]"
return result
def getDefaultColor(objectType):
'''getDefaultColor(string): returns a color value for the given object
type (Wall, Structure, Window)'''
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch")
if objectType == "Wall":
c = p.GetUnsigned("WallColor")
elif objectType == "Structure":
c = p.GetUnsigned("StructureColor")
else:
c = p.GetUnsigned("WindowsColor")
r = float((c>>24)&0xFF)/255.0
g = float((c>>16)&0xFF)/255.0
b = float((c>>8)&0xFF)/255.0
result = (r,g,b,1.0)
return result
def addComponents(objectsList,host):
'''addComponents(objectsList,hostObject): adds the given object or the objects
from the given list as components to the given host Object. Use this for
@ -278,7 +294,7 @@ def getCutVolume(cutplane,shapes):
v = placement.Rotation.multVec(FreeCAD.Vector(0,1,0))
if not bb.isCutPlane(placement.Base,ax):
print "No objects are cut by the plane"
return None,None
return None,None,None
else:
corners = [FreeCAD.Vector(bb.XMin,bb.YMin,bb.ZMin),
FreeCAD.Vector(bb.XMin,bb.YMax,bb.ZMin),
@ -305,7 +321,44 @@ def getCutVolume(cutplane,shapes):
cutface.Placement = placement
cutnormal = DraftVecUtils.scaleTo(ax,wm)
cutvolume = cutface.extrude(cutnormal)
return cutface,cutvolume
cutnormal = DraftVecUtils.neg(cutnormal)
invcutvolume = cutface.extrude(cutnormal)
return cutface,cutvolume,invcutvolume
def getShapeFromMesh(mesh):
import Part, MeshPart
if mesh.isSolid() and (mesh.countComponents() == 1):
# use the best method
faces = []
for f in mesh.Facets:
p=f.Points+[f.Points[0]]
pts = []
for pp in p:
pts.append(FreeCAD.Vector(pp[0],pp[1],pp[2]))
faces.append(Part.Face(Part.makePolygon(pts)))
shell = Part.makeShell(faces)
solid = Part.Solid(shell)
solid = solid.removeSplitter()
return solid
faces = []
segments = mesh.getPlanarSegments(0.001) # use rather strict tolerance here
for i in segments:
if len(i) > 0:
wires = MeshPart.wireFromSegment(mesh, i)
if wires:
faces.append(makeFace(wires))
try:
se = Part.makeShell(faces)
except:
return None
else:
try:
solid = Part.Solid(se)
except:
return se
else:
return solid
def meshToShape(obj,mark=True):
@ -313,36 +366,18 @@ def meshToShape(obj,mark=True):
mark is True (default), non-solid objects will be marked in red'''
name = obj.Name
import Part, MeshPart, DraftGeomUtils
if "Mesh" in obj.PropertiesList:
faces = []
mesh = obj.Mesh
plac = obj.Placement
segments = mesh.getPlanarSegments(0.001) # use rather strict tolerance here
print len(segments)," segments ",segments
for i in segments:
print "treating",segments.index(i),i
if len(i) > 0:
wires = MeshPart.wireFromSegment(mesh, i)
print "wire done"
print wires
if wires:
faces.append(makeFace(wires))
print "done facing"
print "faces",faces
try:
se = Part.makeShell(faces)
solid = Part.Solid(se)
except:
raise
else:
if solid.isClosed():
solid = getShapeFromMesh(mesh)
if solid:
if solid.isClosed() and solid.isValid():
FreeCAD.ActiveDocument.removeObject(name)
newobj = FreeCAD.ActiveDocument.addObject("Part::Feature",name)
newobj.Shape = solid
newobj.Placement = plac
if not solid.isClosed():
if (not solid.isClosed()) or (not solid.isValid()):
if mark:
newobj.ViewObject.ShapeColor = (1.0,0.0,0.0,1.0)
return newobj
@ -428,8 +463,8 @@ def download(url):
else:
return filepath
def check(objectslist,includehidden=True):
"""check(objectslist,includehidden=True): checks if the given objects contain only solids"""
def check(objectslist,includehidden=False):
"""check(objectslist,includehidden=False): checks if the given objects contain only solids"""
objs = Draft.getGroupContents(objectslist)
if not includehidden:
objs = Draft.removeHidden(objs)
@ -439,11 +474,11 @@ def check(objectslist,includehidden=True):
bad.append([o,"is not a Part-based object"])
else:
s = o.Shape
if not s.isClosed():
if (not s.isClosed()) and (not (Draft.getType(o) == "Axis")):
bad.append([o,"is not closed"])
elif not s.isValid():
bad.append([o,"is not valid"])
elif not s.Solids:
elif (not s.Solids) and (not (Draft.getType(o) == "Axis")):
bad.append([o,"doesn't contain any solid"])
else:
f = 0

View File

@ -184,12 +184,14 @@ class _ArchDrawingView:
def __init__(self, obj):
obj.addProperty("App::PropertyLink","Source","Base","The linked object")
obj.addProperty("App::PropertyEnumeration","RenderingMode","Drawing View","The rendering mode to use")
obj.addProperty("App::PropertyBool","ShowCut","Drawing View","If cut geometry is shown or not")
obj.addProperty("App::PropertyFloat","LineWidth","Drawing View","The line width of the rendered objects")
obj.RenderingMode = ["Solid","Wireframe"]
obj.RenderingMode = "Wireframe"
obj.LineWidth = 0.35
obj.ShowCut = False
obj.Proxy = self
self.Type = "DrawingView"
self.Type = "ArchSectionView"
def execute(self, obj):
if obj.Source:
@ -199,6 +201,40 @@ class _ArchDrawingView:
if prop in ["Source","RenderingMode"]:
obj.ViewResult = self.updateSVG(obj)
def __getstate__(self):
return None
def __setstate__(self,state):
return None
def getDisplayModes(self,vobj):
modes=["Default"]
return modes
def setDisplayMode(self,mode):
return mode
def getFlatShape(self):
"returns a flat shape representation of the view"
if hasattr(self,"baseshape"):
import Drawing
[V0,V1,H0,H1] = Drawing.project(self.baseshape,self.direction)
return V0.Edges+V1.Edges
else:
print "No shape has been computed yet"
return None
def getDXF(self):
"returns a flat shape representation of the view"
if hasattr(self,"baseshape"):
import Drawing
[V0,V1,H0,H1] = Drawing.project(self.baseshape,self.direction)
DxfOutput = Drawing.projectToDXF(self.baseshape,self.direction)
return DxfOutput
else:
print "No shape has been computed yet"
return None
def updateSVG(self, obj,join=False):
"encapsulates a svg fragment into a transformation node"
import Part, DraftGeomUtils
@ -209,6 +245,9 @@ class _ArchDrawingView:
objs = Draft.removeHidden(objs)
svg = ''
st = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("CutLineThickness")
if not st: st = 2
# generating SVG
linewidth = obj.LineWidth/obj.Scale
if obj.RenderingMode == "Solid":
@ -217,42 +256,74 @@ class _ArchDrawingView:
render = ArchVRM.Renderer()
render.setWorkingPlane(obj.Source.Placement)
render.addObjects(Draft.getGroupContents(objs,walls=True))
render.cut(obj.Source.Shape)
render.cut(obj.Source.Shape,obj.ShowCut)
svg += render.getViewSVG(linewidth=linewidth)
svg += render.getSectionSVG(linewidth=linewidth*2)
svg += render.getSectionSVG(linewidth=linewidth*st)
if obj.ShowCut:
svg += render.getHiddenSVG(linewidth=linewidth)
# print render.info()
else:
# render using the Drawing module
import Drawing, Part
shapes = []
hshapes = []
sshapes = []
p = FreeCAD.Placement(obj.Source.Placement)
direction = p.Rotation.multVec(FreeCAD.Vector(0,0,1))
self.direction = p.Rotation.multVec(FreeCAD.Vector(0,0,1))
for o in objs:
if o.isDerivedFrom("Part::Feature"):
shapes.extend(o.Shape.Solids)
cutface,cutvolume = ArchCommands.getCutVolume(obj.Source.Shape.copy(),shapes)
if o.Shape.isValid():
shapes.extend(o.Shape.Solids)
else:
FreeCAD.Console.PrintWarning("Skipping invalid object: "+o.Name)
cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(obj.Source.Shape.copy(),shapes)
if cutvolume:
nsh = []
for sh in shapes:
for sol in sh.Solids:
c = sol.cut(cutvolume)
nsh.append(c)
s = sol.section(cutface)
nsh.extend(c.Solids)
sshapes.append(s)
if obj.ShowCut:
c = sol.cut(invcutvolume)
hshapes.append(c)
shapes = nsh
base = Part.makeCompound(shapes)
#if shapes:
# base = shapes.pop().copy()
#for sh in shapes:
# try:
# base = base.fuse(sh)
# except:
# print "unable to fuse, passing..."
svgf = Drawing.projectToSVG(base,direction)
if shapes:
self.shapes = shapes
self.baseshape = Part.makeCompound(shapes)
svgf = Drawing.projectToSVG(self.baseshape,self.direction)
if svgf:
svgf = svgf.replace('stroke-width="0.35"','stroke-width="' + str(linewidth) + 'px"')
svgf = svgf.replace('stroke-width="1"','stroke-width="' + str(linewidth) + 'px"')
svgf = svgf.replace('stroke-width:0.01','stroke-width:' + str(linewidth) + 'px')
svg += svgf
svg += svgf
if hshapes:
hshapes = Part.makeCompound(hshapes)
svgh = Drawing.projectToSVG(hshapes,self.direction)
if svgh:
svgh = svgh.replace('stroke-width="0.35"','stroke-width="' + str(linewidth) + 'px"')
svgh = svgh.replace('stroke-width="1"','stroke-width="' + str(linewidth) + 'px"')
svgh = svgh.replace('stroke-width:0.01','stroke-width:' + str(linewidth) + 'px')
svgh = svgh.replace('fill="none"','fill="none"\nstroke-dasharray="0.09,0.05"')
svg += svgh
if sshapes:
edges = []
for s in sshapes:
edges.extend(s.Edges)
wires = DraftGeomUtils.findWires(edges)
faces = []
for w in wires:
if (w.ShapeType == "Wire") and w.isClosed():
faces.append(Part.Face(w))
sshapes = Part.makeCompound(faces)
svgs = Drawing.projectToSVG(sshapes,self.direction)
if svgs:
svgs = svgs.replace('stroke-width="0.35"','stroke-width="' + str(linewidth*st) + 'px"')
svgs = svgs.replace('stroke-width="1"','stroke-width="' + str(linewidth*st) + 'px"')
svgs = svgs.replace('stroke-width:0.01','stroke-width:' + str(linewidth*st) + 'px')
svg += svgs
result = ''
result += '<g id="' + obj.Name + '"'

View File

@ -44,12 +44,7 @@ def makeStructure(baseobj=None,length=1,width=1,height=1,name=str(translate("Arc
obj.Width = width
obj.Height = height
obj.Length = length
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch")
c = p.GetUnsigned("StructureColor")
r = float((c>>24)&0xFF)/255.0
g = float((c>>16)&0xFF)/255.0
b = float((c>>8)&0xFF)/255.0
obj.ViewObject.ShapeColor = (r,g,b,1.0)
obj.ViewObject.ShapeColor = ArchCommands.getDefaultColor("Structure")
return obj
def makeStructuralSystem(objects,axes):
@ -171,7 +166,13 @@ class _Structure(ArchComponent.Component):
elif (len(base.Wires) == 1):
if base.Wires[0].isClosed():
base = Part.Face(base.Wires[0])
base = base.extrude(normal)
base = base.extrude(normal)
elif obj.Base.isDerivedFrom("Mesh::Feature"):
if obj.Base.Mesh.isSolid():
if obj.Base.Mesh.countComponents() == 1:
sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh)
if sh.isClosed() and sh.isValid() and sh.Solids:
base = sh
else:
if obj.Normal == Vector(0,0,0):
normal = Vector(0,0,1)
@ -221,7 +222,12 @@ class _Structure(ArchComponent.Component):
# finalizing
else:
if base:
if not base.isNull():
if base.isValid() and (not base.isNull()) and base.Solids:
if base.Volume < 0:
base.reverse()
if base.Volume < 0:
FreeCAD.Console.PrintError(str(translate("Arch","Couldn't compute the wall shape")))
return
base = base.removeSplitter()
obj.Shape = base
if not DraftGeomUtils.isNull(pl):

View File

@ -25,12 +25,13 @@
import FreeCAD,math,Part,ArchCommands,DraftVecUtils,DraftGeomUtils
DEBUG = True # if we want debug messages
MAXLOOP = 10 # the max number of loop before abort
# WARNING: in this module, faces are lists whose first item is the actual OCC face, the
# other items being additional information such as color, etc.
DEBUG = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetBool("ShowVRMDebug")
class Renderer:
"A renderer object"
def __init__(self,wp=None):
@ -73,6 +74,7 @@ class Renderer:
self.iscut = False
self.joined = False
self.sections = []
self.hiddenEdges = []
def setWorkingPlane(self,wp):
"sets a Draft WorkingPlane or Placement for this renderer"
@ -151,6 +153,8 @@ class Renderer:
self.faces = [self.projectFace(f) for f in self.faces]
if self.sections:
self.sections = [self.projectFace(f) for f in self.sections]
if self.hiddenEdges:
self.hiddenEdges = [self.projectEdge(e) for e in self.hiddenEdges]
self.oriented = True
#print "VRM: end reorient"
@ -200,6 +204,14 @@ class Renderer:
#print "VRM: projectFace end: ",len(sh.Vertexes)," verts"
return [sh]+face[1:]
def projectEdge(self,edge):
"projects a single edge on the WP"
if len(edge.Vertexes) > 1:
v1 = self.wp.getLocalCoords(edge.Vertexes[0].Point)
v2 = self.wp.getLocalCoords(edge.Vertexes[-1].Point)
return Part.Line(v1,v2).toShape()
return edge
def flattenFace(self,face):
"Returns a face where all vertices have Z = 0"
wires = []
@ -219,7 +231,7 @@ class Renderer:
else:
return [sh]+face[1:]
def cut(self,cutplane):
def cut(self,cutplane,hidden=False):
"Cuts through the shapes with a given cut plane and builds section faces"
if DEBUG: print "\n\n======> Starting cut\n\n"
if self.iscut:
@ -231,7 +243,7 @@ class Renderer:
shps = []
for sh in self.shapes:
shps.append(sh[0])
cutface,cutvolume = ArchCommands.getCutVolume(cutplane,shps)
cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(cutplane,shps)
if cutface and cutvolume:
shapes = []
faces = []
@ -246,6 +258,9 @@ class Renderer:
if DraftGeomUtils.isCoplanar([f,cutface]):
print "COPLANAR"
sections.append([f,fill])
if hidden:
c = sol.cut(invcutvolume)
self.hiddenEdges.extend(c.Edges)
self.shapes = shapes
self.faces = faces
self.sections = sections
@ -555,7 +570,8 @@ class Renderer:
v = e.Vertexes[-1].Point
svg += 'A '+ tostr(r) + ' '+ tostr(r) +' 0 0 1 '+ tostr(v.x) +' '
svg += tostr(v.y) + ' '
svg += 'Z '
if len(edges) > 1:
svg += 'Z '
return svg
def getViewSVG(self,linewidth=0.01):
@ -608,4 +624,25 @@ class Renderer:
svg += 'fill-rule: evenodd'
svg += '"/>\n'
return svg
def getHiddenSVG(self,linewidth=0.02):
"Returns a SVG fragment from cut geometry"
if DEBUG: print "Printing ", len(self.sections), " hidden faces"
if not self.oriented:
self.reorient()
svg = ''
for e in self.hiddenEdges:
svg +='<path '
svg += 'd="'
svg += self.getPathData(e)
svg += '" '
svg += 'stroke="#000000" '
svg += 'stroke-width="' + str(linewidth) + '" '
svg += 'style="stroke-width:' + str(linewidth) + ';'
svg += 'stroke-miterlimit:1;'
svg += 'stroke-linejoin:round;'
svg += 'stroke-dasharray:0.09,0.05;'
svg += 'fill:none;'
svg += '"/>\n'
return svg

View File

@ -21,7 +21,7 @@
#* *
#***************************************************************************
import FreeCAD,FreeCADGui,Draft,ArchComponent,DraftVecUtils
import FreeCAD,FreeCADGui,Draft,ArchComponent,DraftVecUtils,ArchCommands
from FreeCAD import Vector
from PyQt4 import QtCore
from DraftTools import translate
@ -37,17 +37,16 @@ def makeWall(baseobj=None,width=None,height=None,align="Center",name=str(transla
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name)
_Wall(obj)
_ViewProviderWall(obj.ViewObject)
if baseobj: obj.Base = baseobj
if width: obj.Width = width
if height: obj.Height = height
if baseobj:
obj.Base = baseobj
if width:
obj.Width = width
if height:
obj.Height = height
obj.Align = align
if obj.Base: obj.Base.ViewObject.hide()
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch")
c = p.GetUnsigned("WallColor")
r = float((c>>24)&0xFF)/255.0
g = float((c>>16)&0xFF)/255.0
b = float((c>>8)&0xFF)/255.0
obj.ViewObject.ShapeColor = (r,g,b,1.0)
if obj.Base:
obj.Base.ViewObject.hide()
obj.ViewObject.ShapeColor = ArchCommands.getDefaultColor("Wall")
return obj
def joinWalls(walls):
@ -357,7 +356,7 @@ class _Wall(ArchComponent.Component):
# computing shape
base = None
if obj.Base.isDerivedFrom("Part::Feature"):
if not obj.Base.Shape.isNull():
if obj.Base.Shape.isValid() and (not obj.Base.Shape.isNull()):
base = obj.Base.Shape.copy()
if base.Solids:
pass
@ -380,9 +379,21 @@ class _Wall(ArchComponent.Component):
if sh:
base = sh
else:
base = None
FreeCAD.Console.PrintError(str(translate("Arch","Error: Invalid base object")))
elif obj.Base.isDerivedFrom("Mesh::Feature"):
if obj.Base.Mesh.isSolid():
if obj.Base.Mesh.countComponents() == 1:
sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh)
if sh.isClosed() and sh.isValid() and sh.Solids and (not sh.isNull()):
base = sh
else:
FreeCAD.Console.PrintWarning("This mesh is an invalid solid")
obj.Base.ViewObject.show()
if base:
for app in obj.Additions:
if Draft.getType(app) == "Window":
# window
@ -418,7 +429,12 @@ class _Wall(ArchComponent.Component):
base = base.cut(hole.Shape)
hole.ViewObject.hide() # to be removed
if not base.isNull():
if base.isValid() and (not base.isNull()) and base.Solids:
if base.Volume < 0:
base.reverse()
if base.Volume < 0:
FreeCAD.Console.PrintError(str(translate("Arch","Couldn't compute the wall shape")))
return
try:
base = base.removeSplitter()
except:

View File

@ -21,7 +21,7 @@
#* *
#***************************************************************************
import FreeCAD,FreeCADGui,Draft,ArchComponent,DraftVecUtils
import FreeCAD,FreeCADGui,Draft,ArchComponent,DraftVecUtils,ArchCommands
from FreeCAD import Vector
from PyQt4 import QtCore,QtGui
from DraftTools import translate
@ -49,12 +49,7 @@ def makeWindow(baseobj=None,width=None,name=str(translate("Arch","Window"))):
if obj.Base:
obj.Base.ViewObject.DisplayMode = "Wireframe"
obj.Base.ViewObject.hide()
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch")
c = p.GetUnsigned("WindowColor")
r = float((c>>24)&0xFF)/255.0
g = float((c>>16)&0xFF)/255.0
b = float((c>>8)&0xFF)/255.0
obj.ViewObject.ShapeColor = (r,g,b,1.0)
obj.ViewObject.ShapeColor = ArchCommands.getDefaultColor("Window")
return obj
def makeDefaultWindowPart(obj):

View File

@ -2,8 +2,8 @@
# Resource object code
#
# Created: Sun Jul 22 16:38:54 2012
# by: The Resource Compiler for PyQt (Qt v4.8.1)
# Created: Sun Aug 5 16:52:51 2012
# by: The Resource Compiler for PyQt (Qt v4.8.2)
#
# WARNING! All changes made in this file will be lost!
@ -6042,85 +6042,100 @@ qt_resource_data = "\
\x00\x00\x00\x12\x00\x57\x00\x65\x00\x72\x00\x6b\x00\x7a\x00\x65\
\x00\x75\x00\x67\x00\x65\x08\x00\x00\x00\x00\x06\x00\x00\x00\x05\
\x54\x6f\x6f\x6c\x73\x07\x00\x00\x00\x04\x61\x72\x63\x68\x01\
\x00\x00\x04\xd0\
\x00\x00\x05\xb5\
\x00\
\x00\x1e\xaa\x78\x9c\xed\x59\x6d\x6f\xdb\x36\x10\xfe\x9e\x5f\x41\
\xe8\xd3\x06\x6c\x95\xed\xd8\x6e\x13\xc8\x2a\xd6\x74\x79\x01\x5a\
\x2c\x81\xd3\xe6\xe3\x20\x4b\x67\x8b\xab\x24\x7a\x24\x95\xd8\xfd\
\xf5\x3d\x92\x92\x65\xbd\x58\x89\x63\x27\x01\x82\x00\x31\x22\xf2\
\x4e\xc7\xe3\xc3\xe3\xa3\x3b\xd2\xf9\xb8\x88\x23\x72\x0b\x5c\x50\
\x96\x8c\xac\xee\xbb\x8e\x45\x20\xf1\x59\x40\x93\xd9\xc8\xfa\x76\
\x7d\xfa\xe7\x07\xeb\xa3\x7b\xe0\xa4\xb4\x50\xea\xa3\x92\x7b\x40\
\x1c\x3f\xf2\x84\x70\xcf\x52\x7a\x7c\xfc\x99\x7a\x11\x9b\xe1\xff\
\x68\x36\x06\x29\xf1\x65\xf1\x17\xf7\x43\xc7\x36\x3a\xa8\x7c\x47\
\x83\x19\x48\xa2\xdb\x23\xeb\xea\x46\x37\x2d\x92\x78\x31\x8c\xac\
\x36\x1b\x6a\x28\xe2\xcc\x39\x9b\x03\x97\xcb\xec\x85\x19\xb0\x18\
\x24\x5f\x6a\x21\x71\x38\xf8\x52\x3f\x11\x67\xe1\x76\x1c\x7b\x91\
\x35\x96\xaa\xb1\xcc\x1a\xe8\x81\x0c\xdd\xc1\xfb\x81\x63\x9b\x47\
\xd3\x1d\x02\x9d\x85\xd2\x1d\xf6\x8e\x1c\x3b\x7b\xd6\x36\xed\xdc\
\xa8\x63\xe7\x83\x37\x79\x72\x47\x93\x80\xdd\x5d\x53\x19\x41\xe6\
\x8c\x90\x1c\x7d\x77\xcf\x20\x01\xee\x45\x44\x64\x73\x71\xec\x4c\
\x50\x37\x19\x79\x4b\x96\x16\xd8\x7c\xff\xc4\x16\x5f\x74\x57\x66\
\xb1\x32\xa4\x98\x7b\x3e\x1a\xb2\xb2\x09\x24\x69\x3c\x01\xee\x0e\
\x1d\x3b\x7b\x32\xee\xaf\x8f\x50\x33\x11\x7b\x7c\x46\x93\x8a\x85\
\xa3\x56\x0b\x54\x42\x5c\x20\xb9\xbe\x96\x67\x9c\xa5\x73\xf4\x39\
\x5f\xcd\x59\xde\x36\xea\xb5\xc1\x65\x01\x56\x03\x5e\x6a\xcd\xc9\
\xb8\x01\xb4\xba\x4f\xad\xd0\x65\x83\x61\xd4\x4a\xea\x7b\x91\xe9\
\xfd\xb7\x57\x8c\x5b\x4c\xa8\xc1\xd0\x79\xcd\x50\xc8\x38\xfd\xc9\
\x12\xd9\x60\xaa\x6a\xac\x0e\xd1\x17\x6f\x02\x51\x6e\x29\x52\x8d\
\xd2\xeb\x0d\x18\xc1\x42\x96\x14\x56\x38\x7d\x86\xa9\x97\x46\x68\
\x9a\x45\x8c\x93\x29\xfe\xee\xbc\x28\xaa\x22\xd5\x0c\x97\xe9\x34\
\xbe\xad\x39\x6f\x97\xbd\xaf\x4d\x46\x05\x1c\xf0\x1a\x0e\x63\xdd\
\xdd\x3a\x0d\xd4\x05\x54\x95\xc8\x1b\x95\xd9\x00\x86\x9a\x7b\x25\
\x8f\x8f\xcf\x57\xf6\x1c\x5b\x77\xde\x37\x81\xfa\x7e\xa0\x3f\xe1\
\x9c\x26\xb8\x52\x42\x06\xb8\xdd\x46\x56\xa7\x0a\x1d\x6a\x94\x7a\
\x72\x36\xe8\x77\x4a\x64\xb0\x92\x66\x44\xd0\xeb\x94\x38\xa1\x70\
\xab\x6a\x70\x03\xd2\x06\xb8\x2d\x90\x2e\x87\x8d\xa6\xc5\x4b\x0e\
\xd3\x13\xb5\xd6\x9f\x52\x29\x11\xc6\x7c\x93\x29\xd9\x1c\x65\x3a\
\x0e\x26\x46\xd6\x1a\x51\x8c\x45\xd7\x74\xde\x1c\x54\xd7\x21\x15\
\x04\xff\x64\x08\x24\xa8\x05\x58\x02\x77\xe4\x06\x83\x8c\xb0\xc9\
\x7f\x48\x8a\x0f\x8f\xb5\x9a\x13\xda\x66\xc5\x05\xdd\x57\xc1\x9f\
\x43\xe0\xf6\x06\x03\x45\xc2\x41\x45\x34\xe3\x00\x89\xdb\x3d\xc2\
\xa5\x31\x8f\x65\xf1\x24\x4a\xc1\xed\xbe\x47\xa9\x7e\x2a\x2f\x5b\
\x6d\xa8\x87\x79\xad\x60\xfe\x3b\x51\x9f\x9b\x8d\x11\xe6\x67\x88\
\x28\x98\xf4\x6a\xe1\x60\x8f\x05\x49\x0d\x77\xe9\xc9\xf0\xfe\xd1\
\xbe\xb2\xc0\xce\xbe\xb3\xfb\xda\xfd\x8e\x6d\x98\x70\x45\x93\x25\
\xf1\xae\xa4\xb9\x13\x65\xee\x8d\x30\x51\x90\xfa\x32\xe5\xf0\x72\
\xac\x79\x0f\xfd\xbf\xf1\xe6\x73\xf2\xe6\x7d\xdf\xe2\xdd\x98\x73\
\x9c\x47\xdb\xf3\xd2\x67\x77\xd0\x69\xa1\xcf\xe1\x51\x1b\x7d\x7e\
\x18\xbe\x10\x7d\xae\xb0\x7a\xe3\xd0\xcd\x89\xe7\x70\xb7\xc4\x73\
\xb0\xbf\xc4\x53\xd7\x3e\x2f\x48\xa2\xfd\x37\x12\xdd\x8c\xf5\x73\
\x93\xe8\x61\xeb\x62\x6c\x43\x5d\x83\xa3\x16\xe6\x3a\xec\xb5\x31\
\x57\xff\xa5\x98\xeb\x46\xef\x85\xd7\x4b\x5b\x65\x61\xc9\xd6\x9a\
\xde\x23\x4e\x09\x8a\x8f\xef\xc3\xce\x09\x2e\x4e\x4f\x08\x8d\xe7\
\x8c\xcb\x7d\x1f\x0e\xec\xef\x68\x60\xf0\x70\x86\x2e\xb6\x59\x08\
\xfe\x8f\x75\x7c\x56\x7b\x4c\x09\x26\xc5\x71\x4a\x33\x56\x6d\x39\
\xca\xc5\x14\xd3\x13\x93\xa6\x68\x63\x10\xfc\xa1\xf3\x15\x84\xf2\
\x9f\x39\x24\xe3\x10\xb0\xb6\x33\x98\x82\x62\x75\x6c\x4d\x80\xa4\
\x42\xe9\x61\x3d\xc3\x90\xe7\x67\x44\xb2\x4c\x85\xc4\x8c\xeb\x77\
\x89\x5c\xce\xb7\x48\xa1\xb7\xf8\xd4\x7c\x13\x55\xe7\xa6\xc4\xbb\
\xf5\x28\x7e\xc0\x22\x78\xfc\x80\x5b\x6c\x67\x9c\xfc\xc5\xd4\x5f\
\x39\xf0\x2a\xb7\xf4\xee\x71\x7e\xf8\x14\x71\xbe\x4b\x36\x7e\xc2\
\xc1\x93\x20\x88\x26\x17\xa1\x93\x14\xf0\xfc\xd0\x1c\x2a\x9a\xf4\
\x5b\x47\xed\x53\x04\xad\x26\x38\xcc\x8e\x70\x93\x24\x98\x77\x08\
\x32\x59\xee\xba\x43\xb6\x08\x58\x5f\xcf\x1c\x63\x56\xbb\x21\xde\
\x02\xb6\x31\x60\xfb\x4f\x12\xb0\xed\x99\xcf\xe6\x88\xb9\x30\x7c\
\x3a\x4d\x79\x42\x75\x81\xf8\x9b\xef\x25\x24\xf6\x7e\x80\xa6\xe7\
\x98\x05\x10\x91\x10\xbc\xdb\xe5\xef\xcf\x12\x43\x86\xdf\x31\x86\
\x4e\x73\x8f\x5e\x65\x18\x6d\x9f\xca\x94\xaa\x90\x3c\x69\x28\x1f\
\x7f\x3f\xa4\xf8\x28\xea\x8e\xef\x99\x8d\x52\xd5\x51\x4f\x60\xb6\
\xa8\x35\xca\x65\x46\x56\x61\xf4\x6a\x15\x46\x5e\x5c\xf4\x6b\xc5\
\x45\xa9\xae\xa8\xba\x52\xaa\x26\x0a\x90\xd6\x90\x5c\x83\x31\xdb\
\x97\xf9\x69\x48\x76\x5d\x35\xb2\x86\x16\x31\xf7\x4e\x23\xab\xdb\
\xb5\x6c\xa5\x39\xa7\x8b\xd8\x9b\x4f\xd3\xc4\x57\x40\xb9\xff\x5f\
\xea\xf6\x29\x67\xf1\x57\x1a\xc3\x98\xa5\xdc\xc7\x18\xac\x68\xa9\
\xab\xc7\x54\x48\x16\x9b\x11\x85\xf6\x64\xbd\xc7\x78\xb9\x76\x3d\
\xb9\x56\xc2\x14\x57\x92\x6a\x3d\x16\x12\x92\x40\xb8\x57\x97\xa9\
\x08\x73\x79\xde\x79\x60\xe0\xf2\x02\x9c\x36\x5a\xb1\xcd\x95\xa5\
\x78\x17\x2a\xe4\x74\xaf\x46\xa0\x3a\x70\xbb\x27\x95\x82\xaa\xd1\
\x9b\xba\xcb\x9b\x5c\x52\xd6\xf6\xe7\x56\xc6\x73\xcd\x08\x15\xd2\
\xdd\x9d\x29\x77\xe8\xeb\x61\x0e\x42\x2f\xb6\xd0\x61\xe1\xb3\x24\
\x01\xbd\xd8\xaa\xed\xd8\x29\x75\x0f\x7e\x01\x09\x6b\xe1\xfc\
\x00\x27\xfd\x78\x9c\xed\x5a\x6d\x4f\xe3\x38\x10\xfe\xce\xaf\xb0\
\xf2\xe9\x4e\xba\x23\xa5\x50\x58\x50\x9a\xd5\x2d\x1c\x0b\xd2\xae\
\x8e\xbd\xb2\xbb\x1f\x4f\x69\x32\x6d\x7c\x9b\xd8\x39\xc7\xa1\xed\
\xfe\xfa\x1b\xdb\x49\xd3\xbc\x34\x50\x5a\x40\x42\x20\x10\xb1\xc7\
\x9d\x19\x3f\x9e\x79\x3c\x76\xe3\xbc\x9f\xc7\x11\xb9\x03\x91\x52\
\xce\x86\xd6\xc1\x7e\xcf\x22\xc0\x7c\x1e\x50\x36\x1d\x5a\x5f\x6f\
\x2f\x7f\x7f\x67\xbd\x77\xf7\x9c\x8c\x96\x83\x8e\x70\x90\xbb\x47\
\x1c\x3f\xf2\xd2\xd4\xfd\x98\xd1\xb3\xb3\x0b\xea\x45\x7c\x8a\xff\
\xa3\xe9\x08\xa4\xc4\x0f\xa7\x7f\x08\x3f\x74\x6c\x33\x06\x07\xcf\
\x68\x30\x05\x49\x74\x7b\x68\x7d\xf9\xae\x9b\x16\x61\x5e\x0c\x43\
\xab\x4b\x87\x32\x45\x9c\x44\xf0\x04\x84\x5c\xe4\x1f\x98\x02\x8f\
\x41\x8a\x85\x16\x12\x47\x80\x2f\xf5\x13\x71\xe6\x6e\xcf\xb1\xe7\
\x79\x63\xa1\x1a\x8b\xbc\x81\x1e\xc8\xd0\x1d\x9c\x0c\x1c\xdb\x3c\
\x9a\xee\x10\xe8\x34\x94\xee\x71\xff\xd4\xb1\xf3\x67\xad\xd3\x2e\
\x94\x3a\x76\x61\xbc\xcd\x93\x19\x65\x01\x9f\xdd\x52\x19\x41\xee\
\x4c\x2a\x05\xfa\xee\x7e\x04\x06\xc2\x8b\x48\x9a\xcf\xc5\xb1\x73\
\x41\x53\x65\xe4\x2d\x78\x56\x62\xf3\xed\x03\x9f\x7f\xd2\x5d\xb9\
\xc6\x9a\xc9\x34\xf1\x7c\x54\x64\xe5\x13\x60\x59\x3c\x06\xe1\x1e\
\x3b\x76\xfe\x64\xdc\x5f\xb5\xd0\x50\x11\x7b\x62\x4a\x59\x4d\xc3\
\x69\xa7\x06\x2a\x21\x2e\x91\x5c\x5d\xcb\x8f\x82\x67\x09\xfa\x5c\
\xac\xe6\xb4\x68\x9b\xe1\x0d\xe3\xb2\x04\xab\x05\x2f\xb5\xe6\x64\
\xd4\x02\x5a\xd3\xa7\x4e\xe8\x72\x63\x18\xb5\x92\xfa\x5e\x64\x7a\
\xff\xe9\x97\x76\xcb\x09\xb5\x28\xba\x6a\x28\x0a\xb9\xa0\x3f\x39\
\x93\x2d\xaa\xea\xca\x9a\x10\x7d\xf2\xc6\x10\x15\x9a\x22\xd5\xa8\
\x7c\xbc\x05\x23\x98\xcb\xca\x80\x25\x4e\x17\x30\xf1\xb2\x08\x55\
\xf3\x88\x0b\x32\xc1\xbf\x99\x17\x45\x75\xa4\xda\xe1\x32\x9d\xc6\
\xb7\x15\xe7\xed\xaa\xf7\x8d\xc9\xa8\x80\x03\xd1\xc0\x61\xa4\xbb\
\x3b\xa7\x81\x63\x01\x87\x4a\xe4\x8d\xda\x6c\x00\x43\xcd\xfd\x22\
\xcf\xce\xae\x96\xfa\x1c\x5b\x77\xde\x37\x81\x66\x3e\xd0\x9f\x70\
\x45\x19\xae\x54\x2a\x03\x4c\xb7\xa1\xd5\xab\x43\x87\x23\x2a\x3d\
\x05\x1b\x1c\xf5\x2a\x64\xb0\x94\xe6\x44\xd0\xef\x55\x38\xa1\x74\
\xab\xae\x70\x0d\xd2\x06\xb8\x0d\x90\xae\x86\x8d\xa6\xc5\x1b\x01\
\x93\x73\xb5\xd6\x1f\x32\x29\x11\xc6\x22\xc9\x94\x2c\x41\x99\x8e\
\x83\xb1\x91\x75\x46\x14\xe7\xd1\x2d\x4d\xda\x83\xea\x36\xa4\x29\
\xc1\x5f\x19\x02\x09\x1a\x01\xc6\x60\x46\xbe\x63\x90\x11\x3e\xfe\
\x17\x49\xf1\xe1\xb1\xd6\x70\x42\xeb\xac\xb9\xa0\xfb\x6a\xf8\x0b\
\x08\xdc\xfe\x60\xa0\x48\x38\xa8\x89\xa6\x02\x80\xb9\x07\xa7\xb8\
\x34\xe6\xb1\x2a\x1e\x47\x19\xb8\x07\x27\x28\xd5\x4f\xd5\x65\x6b\
\x98\x7a\x98\xd7\x0a\xe6\x3f\x99\xda\x6e\xd6\x46\x98\x9f\x23\xa2\
\x60\xd2\xab\x85\xc6\x1e\x0b\x92\x32\x77\xe3\xc9\xf0\x7e\x6b\x9f\
\x79\x60\xe7\xfb\xec\xae\xb2\xdf\xb1\x0d\x13\x2e\x69\xb2\x22\xde\
\x96\x34\xb7\xa2\xcc\x9d\x11\x26\x0a\x32\x5f\x66\x02\x5e\x8e\x35\
\xef\xa1\xff\x37\xde\x7c\x4e\xde\xbc\x6f\x2f\xde\x8e\x39\x47\x45\
\xb4\x3d\x2f\x7d\x1e\x0c\x7a\x1d\xf4\x79\x7c\xda\x45\x9f\xef\x8e\
\x5f\x88\x3e\x97\x58\xbd\x71\xe8\xfa\xc2\xf3\x78\xbb\xc2\x73\xb0\
\xbb\xc2\x53\x9f\x7d\x5e\x90\x44\x8f\xde\x48\x74\x3d\xd6\xcf\x4d\
\xa2\x87\x9d\x8b\xb1\x09\x75\x0d\x4e\x3b\x98\xeb\xb0\xdf\xc5\x5c\
\x47\x2f\xc5\x5c\xdf\x75\x2e\xbc\x5e\xda\xaa\x0a\x2b\xba\x56\xc6\
\x3d\xe2\x96\xa0\xdc\x7c\x1f\x76\x4f\x70\x7d\x79\x4e\x68\x9c\x70\
\x21\x77\x7d\x39\xb0\xbb\xab\x81\xc1\xc3\x19\xba\x4c\xb3\x10\xfc\
\x1f\xab\xf8\x2c\x73\x4c\x09\xc6\xe5\x75\x4a\x3b\x56\x5d\x35\xca\
\xf5\x04\xcb\x13\x53\xa6\x68\x65\x10\xfc\xa6\xeb\x15\x84\xf2\xaf\
\x04\xd8\x28\x04\x3c\xdb\x19\x4c\x41\xb1\x3a\xb6\xc6\x40\xb2\x54\
\x8d\xc3\xf3\x0c\x47\x9e\x9f\x12\xc9\xf3\x21\x24\xe6\x42\x7f\x96\
\xc8\x45\xb2\x41\x09\xbd\xc1\x56\xf3\x35\xad\x3b\x37\x21\xde\x9d\
\x47\x71\x03\x8b\xe0\xf1\x06\x37\x48\x67\x9c\xfc\xf5\xc4\x5f\x3a\
\xf0\x2a\x53\x7a\xfb\x38\x3f\x7c\x8a\x38\xdf\xa6\x1a\x3f\x17\xe0\
\x49\x48\x89\x26\x97\x54\x17\x29\xe0\xf9\xa1\xb9\x54\x34\xe5\xb7\
\x8e\xda\xa7\x08\x5a\x4d\x70\x58\x1d\x61\x92\x30\xac\x3b\x52\x32\
\x5e\x6c\x9b\x21\x1b\x04\xac\xaf\x67\x8e\x31\xab\xdd\x48\xdf\x02\
\xb6\x35\x60\x8f\x9e\x24\x60\xbb\x2b\x9f\xf5\x11\x73\x6d\xf8\x74\
\x92\x09\x46\xf5\x01\xf1\x17\xdf\x63\x24\xf6\x7e\x80\xa6\xe7\x98\
\x07\x10\x91\x10\xbc\xbb\xc5\xaf\xcf\x12\x43\x86\xdf\x31\x86\x2e\
\x0b\x8f\x5e\x65\x18\x3d\x5d\x29\x73\xb8\x59\x29\xd3\xbf\x20\x02\
\x58\x00\xaa\xb1\xf3\x6f\x3a\x0e\x77\x57\xce\x9c\x3c\x49\xd6\x74\
\x1f\xde\x3a\x69\x7e\x14\xf2\x19\x09\x60\x9c\x4d\x09\x65\x48\xf2\
\xb1\x3e\xe4\x91\x20\x53\x52\xd2\x01\xeb\x06\xf1\xbb\x3e\x6d\xb5\
\x75\x63\x01\xcb\x25\xe3\x46\x0c\x69\xea\x4d\x9f\x89\xeb\x95\x03\
\xdf\xfe\xfe\x7c\xa1\x2c\xbf\xca\x0c\xdd\x3e\x64\xdf\x6d\x77\x47\
\xf2\x58\x46\x3f\x47\x2f\x3d\xdc\x89\x53\x12\x51\xa6\x58\x9c\xfa\
\x3f\x18\x86\x06\x11\x2a\x42\x5f\xee\xa2\xa4\x7b\x3e\x6f\x17\x25\
\x3b\xb9\x28\xb9\xe0\x19\x1e\x4f\x46\x09\x65\x6d\xbc\x17\x68\x69\
\x8a\xd2\xad\xce\x72\xa3\x04\x7c\x3a\xa1\x58\xe3\x2a\x16\x8a\x3d\
\x86\x45\x26\x45\xf6\xd1\x15\xc3\x1d\x85\x19\x04\xf5\xd8\x8b\xb3\
\x54\xaa\x03\x9d\x97\x24\x11\x45\x31\x9e\xe4\x7c\x8c\x53\x35\x6a\
\x0b\xbe\xba\xf3\xa2\x0c\x6a\x3e\x9a\x39\xba\xfd\xfd\x5e\xf5\xc7\
\xb1\x73\xc9\x53\xb2\x22\xe6\xde\x27\x9c\xd2\x6d\x31\xef\x57\xc9\
\x8c\x9b\xd7\x2e\x15\x62\x28\x6a\x84\xea\x57\xf7\x0f\xe1\x83\x92\
\x0a\xbe\xe5\x3a\x2a\x44\xd0\xac\x57\x36\x48\xff\x6a\xe6\xe7\x49\
\xdf\x6f\x24\x7d\x91\xef\x47\x8d\x7c\xaf\xa4\x7a\xdd\x95\x4a\x82\
\x97\x20\xad\x20\xb9\x02\x63\xbe\xd5\x14\xdf\xe4\xe4\xaf\xda\x0c\
\xad\x63\x8b\x98\x77\x66\x86\xd6\xc1\x81\x65\xab\x91\x09\x9d\xc7\
\x5e\x32\xc9\x98\xaf\x80\x72\xff\xbb\xd1\xed\x4b\xc1\xe3\xcf\x98\
\x90\x23\x9e\x09\x1f\xeb\xe7\xda\x28\xf5\xda\x14\xa6\x23\x8f\x8d\
\xc5\x54\x7b\xb2\xda\x63\xbc\x5c\x79\xb5\x6a\xe5\xfa\xb5\x7c\x9d\
\x4a\xad\xc7\x5c\x62\x09\x92\xba\x5f\x6e\xb2\x34\x2c\xe4\x45\xe7\
\x9e\x81\xcb\xc3\x12\x45\x69\xb1\xcd\xeb\x56\xe9\x7e\xa8\x90\xd3\
\xbd\x1a\x81\xba\xe1\x6e\x4f\x6a\x97\xc1\xad\xde\x34\x5d\x5e\xe7\
\x92\xd2\xb6\x3b\xb7\xf2\x6a\xb3\x1d\xa1\x52\xfa\x2c\xce\x54\xf6\
\x81\x76\x8f\x6a\x43\xb6\x77\xab\xda\xa1\xdf\xb8\x13\x90\xea\x18\
\x4c\x75\xb4\xfa\x9c\x31\xd0\x31\xa8\xda\x8e\x9d\x51\x77\xef\x7f\
\xd6\x19\x97\xf4\
\x00\x00\x07\x4c\
\x00\
\x00\x29\xd1\x78\x9c\xed\x59\x5b\x8f\xe2\x46\x16\x7e\xef\x5f\xe1\
@ -11371,35 +11386,35 @@ qt_resource_struct = "\
\x00\x00\x01\x8a\x00\x00\x00\x00\x00\x01\x00\x01\x1d\x6e\
\x00\x00\x00\xba\x00\x00\x00\x00\x00\x01\x00\x00\x6c\x7e\
\x00\x00\x00\x38\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
\x00\x00\x05\x6e\x00\x01\x00\x00\x00\x01\x00\x02\x52\xde\
\x00\x00\x04\x7a\x00\x00\x00\x00\x00\x01\x00\x02\x15\x0f\
\x00\x00\x03\x16\x00\x00\x00\x00\x00\x01\x00\x01\xb7\x13\
\x00\x00\x06\x9e\x00\x01\x00\x00\x00\x01\x00\x02\xa9\x48\
\x00\x00\x05\x40\x00\x01\x00\x00\x00\x01\x00\x02\x4c\x0c\
\x00\x00\x03\x50\x00\x01\x00\x00\x00\x01\x00\x01\xc5\x82\
\x00\x00\x03\xa2\x00\x01\x00\x00\x00\x01\x00\x01\xd9\x09\
\x00\x00\x02\xba\x00\x01\x00\x00\x00\x01\x00\x01\x9c\x71\
\x00\x00\x06\x38\x00\x00\x00\x00\x00\x01\x00\x02\x86\x04\
\x00\x00\x04\xba\x00\x00\x00\x00\x00\x01\x00\x02\x2e\xe9\
\x00\x00\x04\x5a\x00\x01\x00\x00\x00\x01\x00\x02\x0d\x47\
\x00\x00\x02\x98\x00\x01\x00\x00\x00\x01\x00\x01\x93\x78\
\x00\x00\x06\x0e\x00\x01\x00\x00\x00\x01\x00\x02\x7e\x6f\
\x00\x00\x03\x7e\x00\x01\x00\x00\x00\x01\x00\x01\xce\xda\
\x00\x00\x02\x4e\x00\x01\x00\x00\x00\x01\x00\x01\x82\xd0\
\x00\x00\x02\x78\x00\x01\x00\x00\x00\x01\x00\x01\x8c\x78\
\x00\x00\x04\xea\x00\x01\x00\x00\x00\x01\x00\x02\x3e\x57\
\x00\x00\x04\x0e\x00\x00\x00\x00\x00\x01\x00\x01\xf5\x04\
\x00\x00\x05\x18\x00\x01\x00\x00\x00\x01\x00\x02\x43\xa7\
\x00\x00\x04\x38\x00\x01\x00\x00\x00\x01\x00\x02\x05\x85\
\x00\x00\x05\x98\x00\x00\x00\x00\x00\x01\x00\x02\x59\xb8\
\x00\x00\x03\xc6\x00\x01\x00\x00\x00\x01\x00\x01\xde\x20\
\x00\x00\x05\xe2\x00\x01\x00\x00\x00\x01\x00\x02\x75\xf5\
\x00\x00\x05\xc2\x00\x01\x00\x00\x00\x01\x00\x02\x6b\xbb\
\x00\x00\x04\x9a\x00\x01\x00\x00\x00\x01\x00\x02\x28\xd1\
\x00\x00\x06\x64\x00\x00\x00\x00\x00\x01\x00\x02\x97\xd3\
\x00\x00\x02\xec\x00\x00\x00\x00\x00\x01\x00\x01\xa4\xb3\
\x00\x00\x03\xf0\x00\x00\x00\x00\x00\x01\x00\x01\xe6\x08\
\x00\x00\x02\x1a\x00\x01\x00\x00\x00\x01\x00\x01\x7b\x80\
\x00\x00\x05\x6e\x00\x01\x00\x00\x00\x01\x00\x02\x53\xc3\
\x00\x00\x04\x7a\x00\x00\x00\x00\x00\x01\x00\x02\x15\xf4\
\x00\x00\x03\x16\x00\x00\x00\x00\x00\x01\x00\x01\xb7\xf8\
\x00\x00\x06\x9e\x00\x01\x00\x00\x00\x01\x00\x02\xaa\x2d\
\x00\x00\x05\x40\x00\x01\x00\x00\x00\x01\x00\x02\x4c\xf1\
\x00\x00\x03\x50\x00\x01\x00\x00\x00\x01\x00\x01\xc6\x67\
\x00\x00\x03\xa2\x00\x01\x00\x00\x00\x01\x00\x01\xd9\xee\
\x00\x00\x02\xba\x00\x01\x00\x00\x00\x01\x00\x01\x9d\x56\
\x00\x00\x06\x38\x00\x00\x00\x00\x00\x01\x00\x02\x86\xe9\
\x00\x00\x04\xba\x00\x00\x00\x00\x00\x01\x00\x02\x2f\xce\
\x00\x00\x04\x5a\x00\x01\x00\x00\x00\x01\x00\x02\x0e\x2c\
\x00\x00\x02\x98\x00\x01\x00\x00\x00\x01\x00\x01\x94\x5d\
\x00\x00\x06\x0e\x00\x01\x00\x00\x00\x01\x00\x02\x7f\x54\
\x00\x00\x03\x7e\x00\x01\x00\x00\x00\x01\x00\x01\xcf\xbf\
\x00\x00\x02\x4e\x00\x01\x00\x00\x00\x01\x00\x01\x83\xb5\
\x00\x00\x02\x78\x00\x01\x00\x00\x00\x01\x00\x01\x8d\x5d\
\x00\x00\x04\xea\x00\x01\x00\x00\x00\x01\x00\x02\x3f\x3c\
\x00\x00\x04\x0e\x00\x00\x00\x00\x00\x01\x00\x01\xf5\xe9\
\x00\x00\x05\x18\x00\x01\x00\x00\x00\x01\x00\x02\x44\x8c\
\x00\x00\x04\x38\x00\x01\x00\x00\x00\x01\x00\x02\x06\x6a\
\x00\x00\x05\x98\x00\x00\x00\x00\x00\x01\x00\x02\x5a\x9d\
\x00\x00\x03\xc6\x00\x01\x00\x00\x00\x01\x00\x01\xdf\x05\
\x00\x00\x05\xe2\x00\x01\x00\x00\x00\x01\x00\x02\x76\xda\
\x00\x00\x05\xc2\x00\x01\x00\x00\x00\x01\x00\x02\x6c\xa0\
\x00\x00\x04\x9a\x00\x01\x00\x00\x00\x01\x00\x02\x29\xb6\
\x00\x00\x06\x64\x00\x00\x00\x00\x00\x01\x00\x02\x98\xb8\
\x00\x00\x02\xec\x00\x00\x00\x00\x00\x01\x00\x01\xa5\x98\
\x00\x00\x03\xf0\x00\x00\x00\x00\x00\x01\x00\x01\xe6\xed\
\x00\x00\x02\x1a\x00\x01\x00\x00\x00\x01\x00\x01\x7c\x65\
\x00\x00\x01\xf2\x00\x01\x00\x00\x00\x01\x00\x01\x76\xac\
"

View File

@ -224,6 +224,75 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>2D rendering</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="Gui::PrefCheckBox" name="gui::prefcheckbox_4">
<property name="toolTip">
<string>Show debug information during 2D rendering</string>
</property>
<property name="text">
<string>Show renderer debug messages</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>ShowVRMDebug</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Arch</cstring>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Cut areas line thickness ratio</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="Gui::PrefDoubleSpinBox" name="gui::prefdoublespinbox">
<property name="toolTip">
<string>Specifies how many times the viewed line thickness must be applied to cut lines</string>
</property>
<property name="value">
<double>2.000000000000000</double>
</property>
<property name="prefEntry" stdset="0">
<cstring>CutLineThickness</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Arch</cstring>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
@ -257,6 +326,11 @@
<extends>QCheckBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefDoubleSpinBox</class>
<extends>QDoubleSpinBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>

View File

@ -1562,10 +1562,8 @@ def makeSketch(objectslist,autoconstraints=False,addTo=None,name="Sketch"):
if tp == "BSpline":
print "makeSketch: BSplines not supported"
elif tp == "Circle":
if obj.FirstAngle == obj.LastAngle:
nobj.addGeometry(obj.Shape.Edges[0].Curve)
else:
nobj.addGeometry(Part.ArcOfCircle(obj.Shape.Edges[0].Curve,math.radians(obj.FirstAngle),math.radians(obj.LastAngle)))
g = (DraftGeomUtils.geom(obj.Shape.Edges[0],nobj.Placement))
nobj.addGeometry(g)
# TODO add Radius constraits
ok = True
elif tp == "Rectangle":
@ -1586,25 +1584,26 @@ def makeSketch(objectslist,autoconstraints=False,addTo=None,name="Sketch"):
nobj.addConstraint(Constraint("Vertical",last))
ok = True
elif tp in ["Wire","Polygon"]:
closed = False
if tp == "Polygon":
closed = True
elif hasattr(obj,"Closed"):
closed = obj.Closed
for edge in obj.Shape.Edges:
nobj.addGeometry(edge.Curve)
if autoconstraints:
last = nobj.GeometryCount
segs = range(last-len(obj.Shape.Edges),last-1)
for seg in segs:
nobj.addConstraint(Constraint("Coincident",seg,EndPoint,seg+1,StartPoint))
if DraftGeomUtils.isAligned(nobj.Geometry[seg],"x"):
nobj.addConstraint(Constraint("Vertical",seg))
elif DraftGeomUtils.isAligned(nobj.Geometry[seg],"y"):
nobj.addConstraint(Constraint("Horizontal",seg))
if closed:
nobj.addConstraint(Constraint("Coincident",last-1,EndPoint,segs[0],StartPoint))
ok = True
if obj.FilletRadius == 0:
closed = False
if tp == "Polygon":
closed = True
elif hasattr(obj,"Closed"):
closed = obj.Closed
for edge in obj.Shape.Edges:
nobj.addGeometry(edge.Curve)
if autoconstraints:
last = nobj.GeometryCount
segs = range(last-len(obj.Shape.Edges),last-1)
for seg in segs:
nobj.addConstraint(Constraint("Coincident",seg,EndPoint,seg+1,StartPoint))
if DraftGeomUtils.isAligned(nobj.Geometry[seg],"x"):
nobj.addConstraint(Constraint("Vertical",seg))
elif DraftGeomUtils.isAligned(nobj.Geometry[seg],"y"):
nobj.addConstraint(Constraint("Horizontal",seg))
if closed:
nobj.addConstraint(Constraint("Coincident",last-1,EndPoint,segs[0],StartPoint))
ok = True
if (not ok) and obj.isDerivedFrom("Part::Feature"):
if not DraftGeomUtils.isPlanar(obj.Shape):
print "Error: The given object is not planar and cannot be converted into a sketch."

View File

@ -39,14 +39,14 @@ precision = params.GetInt("precision")
def vec(edge):
"vec(edge) or vec(line) -- returns a vector from an edge or a Part.line"
# if edge is not straight, you'll get strange results!
if isinstance(edge,Part.Shape):
return edge.Vertexes[-1].Point.sub(edge.Vertexes[0].Point)
elif isinstance(edge,Part.Line):
return edge.EndPoint.sub(edge.StartPoint)
else:
return None
"vec(edge) or vec(line) -- returns a vector from an edge or a Part.line"
# if edge is not straight, you'll get strange results!
if isinstance(edge,Part.Shape):
return edge.Vertexes[-1].Point.sub(edge.Vertexes[0].Point)
elif isinstance(edge,Part.Line):
return edge.EndPoint.sub(edge.StartPoint)
else:
return None
def edg(p1,p2):
"edg(Vector,Vector) -- returns an edge from 2 vectors"
@ -370,17 +370,18 @@ def geom(edge,plac=FreeCAD.Placement()):
c = edge.Curve.Center
cu = Part.Circle(edge.Curve.Center,normal,edge.Curve.Radius)
ref = plac.Rotation.multVec(Vector(1,0,0))
a1 = math.pi + DraftVecUtils.angle(v1.sub(c),ref,normal)
a2 = DraftVecUtils.angle(v2.sub(c),ref,normal)
a1 = DraftVecUtils.angle(v1.sub(c),ref,DraftVecUtils.neg(normal))
a2 = DraftVecUtils.angle(v2.sub(c),ref,DraftVecUtils.neg(normal))
# direction check
if a1 > a2:
if edge.Curve.Axis.getAngle(normal) > 1:
a1,a2 = a2,a1
#print "creating sketch arc from ",cu, ", p1=",v1, " (",math.degrees(a1), "d) p2=",v2," (", math.degrees(a2),"d)"
p= Part.ArcOfCircle(cu,a1,a2)
return p
else:
print edge.Curve
return edge.Curve
def mirror (point, edge):
@ -539,57 +540,62 @@ def sortEdges(lEdges, aVertex=None):
def findWires(edgeslist):
'''finds connected wires in the given list of edges'''
'''finds connected wires in the given list of edges'''
def touches(e1,e2):
if len(e1.Vertexes) < 2:
return False
if len(e2.Vertexes) < 2:
return False
if DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[0].Point):
return True
if DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[-1].Point):
return True
if DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[0].Point):
return True
if DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[-1].Point):
return True
return False
edges = edgeslist[:]
wires = []
lost = []
while edges:
e = edges[0]
if not wires:
# create first group
edges.remove(e)
wires.append([e])
def touches(e1,e2):
if len(e1.Vertexes) < 2:
return False
if len(e2.Vertexes) < 2:
return False
if DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[0].Point):
return True
if DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[-1].Point):
return True
if DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[0].Point):
return True
if DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[-1].Point):
return True
return False
edges = edgeslist[:]
wires = []
lost = []
while edges:
e = edges[0]
if not wires:
# create first group
edges.remove(e)
wires.append([e])
else:
found = False
for w in wires:
if not found:
for we in w:
if touches(e,we):
edges.remove(e)
w.append(e)
found = True
break
if not found:
if e in lost:
# we already tried this edge, and still nothing
edges.remove(e)
wires.append([e])
lost = []
else:
found = False
for w in wires:
if not found:
for we in w:
if touches(e,we):
edges.remove(e)
w.append(e)
found = True
break
if not found:
if e in lost:
# we already tried this edge, and still nothing
edges.remove(e)
wires.append([e])
lost = []
else:
# put to the end of the list
edges.remove(e)
edges.append(e)
lost.append(e)
nwires = []
for w in wires:
nwires.append(Part.Wire(w))
return nwires
# put to the end of the list
edges.remove(e)
edges.append(e)
lost.append(e)
nwires = []
for w in wires:
try:
wi = Part.Wire(w)
except:
print "couldn't join some edges"
else:
nwires.append(wi)
return nwires
def superWire(edgeslist,closed=False):
'''superWire(edges,[closed]): forces a wire between edges that don't necessarily
@ -767,8 +773,8 @@ def getNormal(shape):
if (shape.ShapeType == "Face") and hasattr(shape,"normalAt"):
n = shape.normalAt(0.5,0.5)
elif shape.ShapeType == "Edge":
if isinstance(shape.Curve,Part.Circle):
n = shape.Curve.Axis
if isinstance(shape.Edges[0].Curve,Part.Circle):
n = shape.Edges[0].Curve.Axis
else:
for e in shape.Edges:
if isinstance(e.Curve,Part.Circle):

View File

@ -990,7 +990,7 @@ class DraftToolBar:
def setCurrentText(self,tstr):
if (not self.taskmode) or (self.taskmode and self.isTaskOn):
self.textValue.setText(tstr)
def sendText(self):
'''
this function sends the entered text to the active draft command

View File

@ -317,16 +317,16 @@ class Snapper:
"returns a 3D point, projected on the current working plane"
view = Draft.get3DView()
pt = view.getPoint(x,y)
if hasattr(FreeCAD,"DraftWorkingPlane"):
if view.getCameraType() == "Perspective":
camera = view.getCameraNode()
p = camera.getField("position").getValue()
dv = pt.sub(Vector(p[0],p[1],p[2]))
else:
dv = view.getViewDirection()
return FreeCAD.DraftWorkingPlane.projectPoint(pt,dv)
else:
return pt
if self.mask != "z":
if hasattr(FreeCAD,"DraftWorkingPlane"):
if view.getCameraType() == "Perspective":
camera = view.getCameraNode()
p = camera.getField("position").getValue()
dv = pt.sub(Vector(p[0],p[1],p[2]))
else:
dv = view.getViewDirection()
return FreeCAD.DraftWorkingPlane.projectPoint(pt,dv)
return pt
def snapToExtensions(self,point,last,constrain,eline):
"returns a point snapped to extension or parallel line to last object, if any"

View File

@ -3711,7 +3711,7 @@ class Draft2Sketch():
elif obj.isDerivedFrom("Part::Part2DObjectPython"):
Draft.makeSketch(obj,autoconstraints=True)
elif obj.isDerivedFrom("Part::Feature"):
if len(obj.Shape.Wires) == 1:
if (len(obj.Shape.Wires) == 1) or (len(obj.Shape.Edges) == 1):
Draft.makeSketch(obj,autoconstraints=False)
FreeCAD.ActiveDocument.commitTransaction()

View File

@ -1356,65 +1356,76 @@ def export(objectslist,filename,nospline=False):
"called when freecad exports a file. If nospline=True, bsplines are exported as straight segs"
global exportList
exportList = objectslist
dxf = dxfLibrary.Drawing()
if (len(exportList) == 1) and (exportList[0].isDerivedFrom("Drawing::FeaturePage")):
if (len(exportList) == 1) and (Draft.getType(exportList[0]) == "ArchSectionView"):
# arch view: export it "as is"
dxf = exportList[0].Proxy.getDXF()
if dxf:
f = open(filename,"w")
f.write(dxf)
f.close()
elif (len(exportList) == 1) and (exportList[0].isDerivedFrom("Drawing::FeaturePage")):
# page: special hack-export! (see below)
exportPage(exportList[0],filename)
return
for ob in exportList:
print "processing ",ob.Name
if ob.isDerivedFrom("Part::Feature"):
if not ob.Shape.isNull():
if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft").GetBool("dxfmesh"):
writeMesh(ob,dxf)
else:
if ob.Shape.ShapeType == 'Compound':
if (len(ob.Shape.Wires) == 1):
# only one wire in this compound, no lone edge -> polyline
if (len(ob.Shape.Wires[0].Edges) == len(ob.Shape.Edges)):
writeShape(ob,dxf,nospline)
else:
# other cases, treat edges
dxf = dxfLibrary.Drawing()
for ob in exportList:
print "processing ",ob.Name
if ob.isDerivedFrom("Part::Feature"):
if not ob.Shape.isNull():
if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft").GetBool("dxfmesh"):
writeMesh(ob,dxf)
else:
if ob.Shape.ShapeType == 'Compound':
if (len(ob.Shape.Wires) == 1):
# only one wire in this compound, no lone edge -> polyline
if (len(ob.Shape.Wires[0].Edges) == len(ob.Shape.Edges)):
writeShape(ob,dxf,nospline)
else:
# 1 wire + lone edges -> block
block = getBlock(ob)
dxf.blocks.append(block)
dxf.append(dxfLibrary.Insert(name=ob.Name.upper()))
else:
# 1 wire + lone edges -> block
# all other cases: block
block = getBlock(ob)
dxf.blocks.append(block)
dxf.append(dxfLibrary.Insert(name=ob.Name.upper()))
else:
# all other cases: block
block = getBlock(ob)
dxf.blocks.append(block)
dxf.append(dxfLibrary.Insert(name=ob.Name.upper()))
else:
writeShape(ob,dxf,nospline)
elif (ob.Type == "App::Annotation"):
# texts
# temporary - as dxfLibrary doesn't support mtexts well, we use several single-line texts
# well, anyway, at the moment, Draft only writes single-line texts, so...
for text in ob.LabelText:
point = DraftVecUtils.tup(FreeCAD.Vector(ob.Position.x,
ob.Position.y-ob.LabelText.index(text),
ob.Position.z))
if gui: height = float(ob.ViewObject.FontSize)
else: height = 1
dxf.append(dxfLibrary.Text(text,point,height=height,
color=getACI(ob,text=True),
style='STANDARD',
layer=getGroup(ob,exportList)))
elif 'Dimline' in ob.PropertiesList:
p1 = DraftVecUtils.tup(ob.Start)
p2 = DraftVecUtils.tup(ob.End)
base = Part.Line(ob.Start,ob.End).toShape()
proj = DraftGeomUtils.findDistance(ob.Dimline,base)
if not proj:
pbase = DraftVecUtils.tup(ob.End)
else:
pbase = DraftVecUtils.tup(ob.End.add(DraftVecUtils.neg(proj)))
dxf.append(dxfLibrary.Dimension(pbase,p1,p2,color=getACI(ob),
layer=getGroup(ob,exportList)))
dxf.saveas(filename)
writeShape(ob,dxf,nospline)
elif Draft.getType(ob) == "Annotation":
# texts
# temporary - as dxfLibrary doesn't support mtexts well, we use several single-line texts
# well, anyway, at the moment, Draft only writes single-line texts, so...
for text in ob.LabelText:
point = DraftVecUtils.tup(FreeCAD.Vector(ob.Position.x,
ob.Position.y-ob.LabelText.index(text),
ob.Position.z))
if gui: height = float(ob.ViewObject.FontSize)
else: height = 1
dxf.append(dxfLibrary.Text(text,point,height=height,
color=getACI(ob,text=True),
style='STANDARD',
layer=getGroup(ob,exportList)))
elif Draft.getType(ob) == "Dimension":
p1 = DraftVecUtils.tup(ob.Start)
p2 = DraftVecUtils.tup(ob.End)
base = Part.Line(ob.Start,ob.End).toShape()
proj = DraftGeomUtils.findDistance(ob.Dimline,base)
if not proj:
pbase = DraftVecUtils.tup(ob.End)
else:
pbase = DraftVecUtils.tup(ob.End.add(DraftVecUtils.neg(proj)))
dxf.append(dxfLibrary.Dimension(pbase,p1,p2,color=getACI(ob),
layer=getGroup(ob,exportList)))
dxf.saveas(filename)
FreeCAD.Console.PrintMessage("successfully exported "+filename+"\r\n")
def exportPage(page,filename):

View File

@ -255,6 +255,17 @@ float MeshAlgorithm::GetAverageEdgeLength() const
return fLen;
}
Base::Vector3f MeshAlgorithm::GetGravityPoint() const
{
Base::Vector3f center;
MeshPointIterator cP(_rclMesh);
for (cP.Init(); cP.More(); cP.Next()) {
center += *cP;
}
return center / (float)_rclMesh.CountPoints();
}
void MeshAlgorithm::GetMeshBorders (std::list<std::vector<Base::Vector3f> > &rclBorders) const
{
std::vector<unsigned long> aulAllFacets(_rclMesh.CountFacets());

View File

@ -115,6 +115,10 @@ public:
* Calculates the average length of edges.
*/
float GetAverageEdgeLength() const;
/**
* Calculates the gravity point of the mesh.
*/
Base::Vector3f GetGravityPoint() const;
/**
* Returns all boundaries of the mesh.
*/

View File

@ -30,11 +30,15 @@
# include <QSet>
#endif
#include <boost/signals.hpp>
#include <boost/bind.hpp>
#include "ui_TaskFaceColors.h"
#include "TaskFaceColors.h"
#include "ViewProviderExt.h"
#include <Gui/Application.h>
#include <Gui/Control.h>
#include <Gui/Document.h>
#include <Gui/Selection.h>
@ -69,15 +73,20 @@ namespace PartGui {
class FaceColors::Private
{
public:
typedef boost::signals::connection Connection;
Ui_TaskFaceColors* ui;
ViewProviderPartExt* vp;
App::DocumentObject* obj;
Gui::Document* doc;
std::vector<App::Color> current,perface;
QSet<int> index;
Connection connectDelDoc;
Connection connectDelObj;
Private(ViewProviderPartExt* vp) : ui(new Ui_TaskFaceColors()), vp(vp)
{
obj = vp->getObject();
doc = Gui::Application::Instance->getDocument(obj->getDocument());
// build up map edge->face
TopTools_IndexedMapOfShape mapOfShape;
@ -110,14 +119,33 @@ FaceColors::FaceColors(ViewProviderPartExt* vp, QWidget* parent)
FaceSelection* gate = new FaceSelection(d->vp->getObject());
Gui::Selection().addSelectionGate(gate);
d->connectDelDoc = Gui::Application::Instance->signalDeleteDocument.connect(boost::bind
(&FaceColors::slotDeleteDocument, this, _1));
d->connectDelObj = Gui::Application::Instance->signalDeletedObject.connect(boost::bind
(&FaceColors::slotDeleteObject, this, _1));
}
FaceColors::~FaceColors()
{
Gui::Selection().rmvSelectionGate();
d->connectDelDoc.disconnect();
d->connectDelObj.disconnect();
delete d;
}
void FaceColors::slotDeleteDocument(const Gui::Document& Doc)
{
if (d->doc == &Doc)
Gui::Control().closeDialog();
}
void FaceColors::slotDeleteObject(const Gui::ViewProvider& obj)
{
if (d->vp == &obj)
Gui::Control().closeDialog();
}
void FaceColors::on_defaultButton_clicked()
{
std::fill(d->perface.begin(), d->perface.end(), d->vp->ShapeColor.getValue());

View File

@ -27,6 +27,11 @@
#include <Gui/TaskView/TaskView.h>
#include <Gui/TaskView/TaskDialog.h>
namespace Gui {
class Document;
class ViewProvider;
}
namespace PartGui {
class ViewProviderPartExt;
@ -49,6 +54,8 @@ private Q_SLOTS:
protected:
void onSelectionChanged(const Gui::SelectionChanges& msg);
void changeEvent(QEvent *e);
void slotDeleteDocument(const Gui::Document&);
void slotDeleteObject(const Gui::ViewProvider&);
private:
class Private;

View File

@ -125,9 +125,14 @@ ViewProviderPartExt::ViewProviderPartExt()
{
VisualTouched = true;
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
unsigned long lcol = hGrp->GetUnsigned("DefaultShapeLineColor",421075455UL); // dark grey (25,25,25)
float r,g,b;
r = ((lcol >> 24) & 0xff) / 255.0; g = ((lcol >> 16) & 0xff) / 255.0; b = ((lcol >> 8) & 0xff) / 255.0;
int lwidth = hGrp->GetInt("DefaultShapeLineWidth",2);
App::Material mat;
mat.ambientColor.set(0.2f,0.2f,0.2f);
mat.diffuseColor.set(0.1f,0.1f,0.1f);
mat.diffuseColor.set(r,g,b);
mat.specularColor.set(0.0f,0.0f,0.0f);
mat.emissiveColor.set(0.0f,0.0f,0.0f);
mat.shininess = 1.0f;
@ -137,10 +142,10 @@ ViewProviderPartExt::ViewProviderPartExt()
ADD_PROPERTY(LineColor,(mat.diffuseColor));
ADD_PROPERTY(PointColor,(mat.diffuseColor));
ADD_PROPERTY(DiffuseColor,(ShapeColor.getValue()));
ADD_PROPERTY(LineWidth,(2.0f));
ADD_PROPERTY(LineWidth,(lwidth));
LineWidth.setConstraints(&sizeRange);
PointSize.setConstraints(&sizeRange);
ADD_PROPERTY(PointSize,(2.0f));
ADD_PROPERTY(PointSize,(lwidth));
ADD_PROPERTY(Deviation,(0.5f));
Deviation.setConstraints(&tessRange);
ADD_PROPERTY(ControlPoints,(false));

View File

@ -45,6 +45,8 @@ SET(ShipIcons_SRCS
Icons/SimRunIco.xpm
Icons/SimStopIco.png
Icons/SimStopIco.xpm
Icons/SimPostIco.png
Icons/SimPostIco.xpm
Icons/Tank.png
Icons/Tank.xcf
Icons/Tank.xpm
@ -150,10 +152,20 @@ SET(SimRun_SRCS
simRun/clSim/Utils.py
simRun/Sim/__init__.py
simRun/Sim/initialization.py
simRun/Sim/matrixGen.py
simRun/Sim/computeSources.py
simRun/Sim/fsEvolution.py
)
SOURCE_GROUP("simrun" FILES ${SimRun_SRCS})
SET(all_files ${ShipMain_SRCS} ${ShipIcons_SRCS} ${ShipExamples_SRCS} ${ShipLoadExample_SRCS} ${ShipCreateShip_SRCS} ${ShipOutlineDraw_SRCS} ${ShipAreasCurve_SRCS} ${ShipHydrostatics_SRCS} ${ShipUtils_SRCS} ${ShipWeights_SRCS} ${ShipCreateTank_SRCS} ${ShipGZ_SRCS} ${SimCreate_SRCS} ${SimRun_SRCS})
SET(SimPost_SRCS
simPost/__init__.py
simPost/TaskPanel.py
simPost/TaskPanel.ui
)
SOURCE_GROUP("simpost" FILES ${SimPost_SRCS})
SET(all_files ${ShipMain_SRCS} ${ShipIcons_SRCS} ${ShipExamples_SRCS} ${ShipLoadExample_SRCS} ${ShipCreateShip_SRCS} ${ShipOutlineDraw_SRCS} ${ShipAreasCurve_SRCS} ${ShipHydrostatics_SRCS} ${ShipUtils_SRCS} ${ShipWeights_SRCS} ${ShipCreateTank_SRCS} ${ShipGZ_SRCS} ${SimCreate_SRCS} ${SimRun_SRCS} ${SimPost_SRCS})
ADD_CUSTOM_TARGET(Ship ALL
SOURCES ${all_files}
@ -239,6 +251,12 @@ INSTALL(
DESTINATION
Mod/Ship/simRun
)
INSTALL(
FILES
${SimPost_SRCS}
DESTINATION
Mod/Ship/simPost
)
INSTALL(
FILES
${ShipMain_SRCS}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because it is too large Load Diff

View File

@ -1,68 +1,68 @@
#***************************************************************************
#* *
#* Copyright (c) 2011, 2012 *
#* Jose Luis Cercos Pita <jlcercos@gmail.com> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
class ShipWorkbench ( Workbench ):
""" @brief Workbench of Ship design module. Here toolbars & icons are append. """
from shipUtils import Paths, Translator
import ShipGui
Icon = Paths.iconsPath() + "/Ico.png"
MenuText = str(Translator.translate("Ship design"))
ToolTip = str(Translator.translate("Ship design"))
def Initialize(self):
from shipUtils import Translator
# ToolBar
list = ["Ship_LoadExample", "Ship_CreateShip", "Ship_OutlineDraw", "Ship_AreasCurve", "Ship_Hydrostatics"]
self.appendToolbar("Ship design",list)
list = ["Ship_Weights", "Ship_CreateTank", "Ship_GZ"]
self.appendToolbar("Weights",list)
# Simulation stuff only if pyOpenCL & numpy are present
hasOpenCL = True
hasNumpy = True
try:
import pyopencl
except ImportError:
hasOpenCL = False
msg = Translator.translate("pyOpenCL not installed, ship simulations disabled\n")
App.Console.PrintWarning(msg)
try:
import numpy
except ImportError:
hasNumpy = False
msg = Translator.translate("numpy not installed, ship simulations disabled\n")
App.Console.PrintWarning(msg)
if hasOpenCL and hasNumpy:
list = ["Ship_CreateSim", "Ship_RunSim", "Ship_StopSim"]
self.appendToolbar("Simulation",list)
# Menu
list = ["Ship_LoadExample", "Ship_CreateShip", "Ship_OutlineDraw", "Ship_AreasCurve", "Ship_Hydrostatics"]
self.appendMenu("Ship design",list)
list = ["Ship_Weights", "Ship_CreateTank", "Ship_GZ"]
self.appendMenu("Weights",list)
if hasOpenCL and hasNumpy:
list = ["Ship_CreateSim", "Ship_RunSim", "Ship_StopSim"]
self.appendMenu("Simulation",list)
Gui.addWorkbench(ShipWorkbench())
#***************************************************************************
#* *
#* Copyright (c) 2011, 2012 *
#* Jose Luis Cercos Pita <jlcercos@gmail.com> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
class ShipWorkbench ( Workbench ):
""" @brief Workbench of Ship design module. Here toolbars & icons are append. """
from shipUtils import Paths, Translator
import ShipGui
Icon = Paths.iconsPath() + "/Ico.png"
MenuText = str(Translator.translate("Ship design"))
ToolTip = str(Translator.translate("Ship design"))
def Initialize(self):
from shipUtils import Translator
# ToolBar
list = ["Ship_LoadExample", "Ship_CreateShip", "Ship_OutlineDraw", "Ship_AreasCurve", "Ship_Hydrostatics"]
self.appendToolbar("Ship design",list)
list = ["Ship_Weights", "Ship_CreateTank", "Ship_GZ"]
self.appendToolbar("Weights",list)
# Simulation stuff only if pyOpenCL & numpy are present
hasOpenCL = True
hasNumpy = True
try:
import pyopencl
except ImportError:
hasOpenCL = False
msg = Translator.translate("pyOpenCL not installed, ship simulations disabled\n")
App.Console.PrintWarning(msg)
try:
import numpy
except ImportError:
hasNumpy = False
msg = Translator.translate("numpy not installed, ship simulations disabled\n")
App.Console.PrintWarning(msg)
if hasOpenCL and hasNumpy:
list = ["Ship_CreateSim", "Ship_RunSim", "Ship_StopSim", "Ship_TrackSim"]
self.appendToolbar("Simulation",list)
# Menu
list = ["Ship_LoadExample", "Ship_CreateShip", "Ship_OutlineDraw", "Ship_AreasCurve", "Ship_Hydrostatics"]
self.appendMenu("Ship design",list)
list = ["Ship_Weights", "Ship_CreateTank", "Ship_GZ"]
self.appendMenu("Weights",list)
if hasOpenCL and hasNumpy:
list = ["Ship_CreateSim", "Ship_RunSim", "Ship_StopSim", "Ship_TrackSim"]
self.appendMenu("Simulation",list)
Gui.addWorkbench(ShipWorkbench())

View File

@ -46,6 +46,8 @@ nobase_data_DATA = \
Icons/SimRunIco.xpm \
Icons/SimStopIco.png \
Icons/SimStopIco.xpm \
Icons/SimPostIco.png \
Icons/SimPostIco.xpm \
Icons/Tank.png \
Icons/Tank.xcf \
Icons/Tank.xpm \
@ -102,7 +104,13 @@ nobase_data_DATA = \
simRun/clSim/initialization.py \
simRun/clSim/Utils.py \
simRun/Sim/__init__.py \
simRun/Sim/initialization.py
simRun/Sim/initialization.py \
simRun/Sim/matrixGen.py \
simRun/Sim/computeSources.py \
simRun/Sim/fsEvolution.py \
simPost/__init__.py \
simPost/TaskPanel.py \
simPost/TaskPanel.ui
CLEANFILES = $(BUILT_SOURCES)

View File

@ -1,169 +1,183 @@
#***************************************************************************
#* *
#* Copyright (c) 2011, 2012 *
#* Jose Luis Cercos Pita <jlcercos@gmail.com> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
from PyQt4 import QtCore, QtGui
import FreeCAD, FreeCADGui, os
class LoadExample:
def Activated(self):
import shipLoadExample
shipLoadExample.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/LoadIco.png"
MenuText = str(Translator.translate('Load an example ship geometry'))
ToolTip = str(Translator.translate('Load an example ship geometry able to be converted into a ship.'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class CreateShip:
def Activated(self):
import shipCreateShip
shipCreateShip.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/Ico.png"
MenuText = str(Translator.translate('Create a new ship'))
ToolTip = str(Translator.translate('Create a new ship in order to work with them'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class OutlineDraw:
def Activated(self):
import shipOutlineDraw
shipOutlineDraw.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/OutlineDrawIco.png"
MenuText = str(Translator.translate('Outline draw'))
ToolTip = str(Translator.translate('Plot ship outline draw'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class AreasCurve:
def Activated(self):
import shipAreasCurve
shipAreasCurve.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/AreaCurveIco.png"
MenuText = str(Translator.translate('Areas curve'))
ToolTip = str(Translator.translate('Plot transversal areas curve'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class Hydrostatics:
def Activated(self):
import shipHydrostatics
shipHydrostatics.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/HydrostaticsIco.png"
MenuText = str(Translator.translate('Hydrostatics'))
ToolTip = str(Translator.translate('Plot ship hydrostatics'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class SetWeights:
def Activated(self):
import tankWeights
tankWeights.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/Weight.png"
MenuText = str(Translator.translate('Set ship weights'))
ToolTip = str(Translator.translate('Set ship weights, tanks must be added later'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class CreateTank:
def Activated(self):
import tankCreateTank
tankCreateTank.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/Tank.png"
MenuText = str(Translator.translate('Create a new tank'))
ToolTip = str(Translator.translate('Create a new ship tank'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class GZ:
def Activated(self):
import tankGZ
tankGZ.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/HydrostaticsIco.png"
MenuText = str(Translator.translate('GZ curve'))
ToolTip = str(Translator.translate('Transversal stability GZ curve computation'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class CreateSim:
def Activated(self):
import simCreate
simCreate.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/SimCreateIco.png"
MenuText = str(Translator.translate('Create a new simulation'))
ToolTip = str(Translator.translate('Create a new simulation in order to process later'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class RunSim:
def Activated(self):
import simRun
simRun.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/SimRunIco.png"
MenuText = str(Translator.translate('Run a simulation'))
ToolTip = str(Translator.translate('Run a simulation'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class StopSim:
def Activated(self):
import simRun
simRun.stop()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/SimStopIco.png"
MenuText = str(Translator.translate('Stop active simulation'))
ToolTip = str(Translator.translate('Stop active simulation'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
FreeCADGui.addCommand('Ship_LoadExample', LoadExample())
FreeCADGui.addCommand('Ship_CreateShip', CreateShip())
FreeCADGui.addCommand('Ship_OutlineDraw', OutlineDraw())
FreeCADGui.addCommand('Ship_AreasCurve', AreasCurve())
FreeCADGui.addCommand('Ship_Hydrostatics', Hydrostatics())
FreeCADGui.addCommand('Ship_Weights', SetWeights())
FreeCADGui.addCommand('Ship_CreateTank', CreateTank())
FreeCADGui.addCommand('Ship_GZ', GZ())
FreeCADGui.addCommand('Ship_CreateSim', CreateSim())
FreeCADGui.addCommand('Ship_RunSim', RunSim())
FreeCADGui.addCommand('Ship_StopSim', StopSim())
#***************************************************************************
#* *
#* Copyright (c) 2011, 2012 *
#* Jose Luis Cercos Pita <jlcercos@gmail.com> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
from PyQt4 import QtCore, QtGui
import FreeCAD, FreeCADGui, os
class LoadExample:
def Activated(self):
import shipLoadExample
shipLoadExample.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/LoadIco.png"
MenuText = str(Translator.translate('Load an example ship geometry'))
ToolTip = str(Translator.translate('Load an example ship geometry able to be converted into a ship.'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class CreateShip:
def Activated(self):
import shipCreateShip
shipCreateShip.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/Ico.png"
MenuText = str(Translator.translate('Create a new ship'))
ToolTip = str(Translator.translate('Create a new ship in order to work with them'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class OutlineDraw:
def Activated(self):
import shipOutlineDraw
shipOutlineDraw.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/OutlineDrawIco.png"
MenuText = str(Translator.translate('Outline draw'))
ToolTip = str(Translator.translate('Plot ship outline draw'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class AreasCurve:
def Activated(self):
import shipAreasCurve
shipAreasCurve.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/AreaCurveIco.png"
MenuText = str(Translator.translate('Areas curve'))
ToolTip = str(Translator.translate('Plot transversal areas curve'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class Hydrostatics:
def Activated(self):
import shipHydrostatics
shipHydrostatics.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/HydrostaticsIco.png"
MenuText = str(Translator.translate('Hydrostatics'))
ToolTip = str(Translator.translate('Plot ship hydrostatics'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class SetWeights:
def Activated(self):
import tankWeights
tankWeights.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/Weight.png"
MenuText = str(Translator.translate('Set ship weights'))
ToolTip = str(Translator.translate('Set ship weights, tanks must be added later'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class CreateTank:
def Activated(self):
import tankCreateTank
tankCreateTank.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/Tank.png"
MenuText = str(Translator.translate('Create a new tank'))
ToolTip = str(Translator.translate('Create a new ship tank'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class GZ:
def Activated(self):
import tankGZ
tankGZ.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/HydrostaticsIco.png"
MenuText = str(Translator.translate('GZ curve'))
ToolTip = str(Translator.translate('Transversal stability GZ curve computation'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class CreateSim:
def Activated(self):
import simCreate
simCreate.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/SimCreateIco.png"
MenuText = str(Translator.translate('Create a new simulation'))
ToolTip = str(Translator.translate('Create a new simulation in order to process later'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class RunSim:
def Activated(self):
import simRun
simRun.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/SimRunIco.png"
MenuText = str(Translator.translate('Run a simulation'))
ToolTip = str(Translator.translate('Run a simulation'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class StopSim:
def Activated(self):
import simRun
simRun.stop()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/SimStopIco.png"
MenuText = str(Translator.translate('Stop active simulation'))
ToolTip = str(Translator.translate('Stop active simulation'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class TrackSim:
def Activated(self):
import simPost
simPost.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/SimPostIco.png"
MenuText = str(Translator.translate('Track simulation'))
ToolTip = str(Translator.translate('Track simulation'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
FreeCADGui.addCommand('Ship_LoadExample', LoadExample())
FreeCADGui.addCommand('Ship_CreateShip', CreateShip())
FreeCADGui.addCommand('Ship_OutlineDraw', OutlineDraw())
FreeCADGui.addCommand('Ship_AreasCurve', AreasCurve())
FreeCADGui.addCommand('Ship_Hydrostatics', Hydrostatics())
FreeCADGui.addCommand('Ship_Weights', SetWeights())
FreeCADGui.addCommand('Ship_CreateTank', CreateTank())
FreeCADGui.addCommand('Ship_GZ', GZ())
FreeCADGui.addCommand('Ship_CreateSim', CreateSim())
FreeCADGui.addCommand('Ship_RunSim', RunSim())
FreeCADGui.addCommand('Ship_StopSim', StopSim())
FreeCADGui.addCommand('Ship_TrackSim', TrackSim())

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,6 @@ from PyQt4 import QtGui,QtCore
import Preview, Plot
import Instance
from shipUtils import Paths, Translator
from surfUtils import Geometry
from shipHydrostatics import Tools as Hydrostatics
class TaskPanel:
@ -114,7 +113,7 @@ class TaskPanel:
""" Set initial values for fields
"""
# Get objects
selObjs = Geometry.getSelectedObjs()
selObjs = Gui.Selection.getSelection()
if not selObjs:
msg = Translator.translate("Ship instance must be selected (no object selected)\n")
App.Console.PrintError(msg)

View File

@ -28,7 +28,6 @@ import FreeCADGui as Gui
from PyQt4 import QtGui,QtCore
# Module
from shipUtils import Paths, Translator
from surfUtils import Geometry
class TaskPanel:
def __init__(self):

View File

@ -27,7 +27,6 @@ from FreeCAD import Base, Vector
import Part
# FreeCADShip modules
from shipUtils import Paths, Translator
from surfUtils import Geometry
def Plot(scale, sections, shape):
""" Creates the outline draw.
@ -52,7 +51,7 @@ def Plot(scale, sections, shape):
x0 = xMid - 0.5*xTot
y0 = 297.0 - yMid - 0.5*yTot # 297 = A3_width
# Get border
edges = Geometry.getEdges([shape])
edges = self.getEdges([shape])
border = edges[0]
for i in range(0,len(edges)):
border = border.oldFuse(edges[i]) # Only group objects, don't try to build more complex entities
@ -95,3 +94,31 @@ def Plot(scale, sections, shape):
FreeCAD.ActiveDocument.OutlineDrawPlot.addObject(FreeCAD.ActiveDocument.OutlineDrawUpView)
FreeCAD.ActiveDocument.recompute()
return obj
def getEdges(self, objs=None):
""" Returns object edges (list of them)
@param objs Object to get the faces, none if selected
object may used.
@return Selected edges. None if errors happens
"""
edges = []
if not objs:
objs = FreeCADGui.Selection.getSelection()
if not objs:
return None
for i in range(0, len(objs)):
obj = objs[i]
if obj.isDerivedFrom('Part::Feature'):
# get shape
shape = obj.Shape
if not shape:
return None
obj = shape
if not obj.isDerivedFrom('Part::TopoShape'):
return None
objEdges = obj.Edges
if not objEdges:
continue
for j in range(0, len(objEdges)):
edges.append(objEdges[j])
return edges

View File

@ -30,7 +30,6 @@ from PyQt4 import QtGui,QtCore
import Preview, Plot
import Instance
from shipUtils import Paths, Translator
from surfUtils import Geometry
class TaskPanel:
def __init__(self):
@ -116,7 +115,7 @@ class TaskPanel:
""" Set initial values for fields
"""
# Get selected objects
selObjs = Geometry.getSelectedObjs()
selObjs = Gui.Selection.getSelection()
if not selObjs:
msg = Translator.translate("Ship instance must be selected (no object selected)\n")
App.Console.PrintError(msg)

View File

@ -1,174 +1,177 @@
#***************************************************************************
#* *
#* Copyright (c) 2011, 2012 *
#* Jose Luis Cercos Pita <jlcercos@gmail.com> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
# FreeCAD modules
import FreeCAD as App
import FreeCADGui as Gui
# Qt library
from PyQt4 import QtGui,QtCore
# Module
import SimInstance
from shipUtils import Paths, Translator
class TaskPanel:
def __init__(self):
self.ui = Paths.modulePath() + "/simCreate/TaskPanel.ui"
def accept(self):
form = self.form
# Read waves data
w = []
for i in range(0,form.waves.rowCount() - 1):
item = form.waves.item(i,0)
A = item.text().toFloat()[0]
item = form.waves.item(i,1)
T = item.text().toFloat()[0]
item = form.waves.item(i,2)
phi = item.text().toFloat()[0]
item = form.waves.item(i,3)
head = item.text().toFloat()[0]
w.append([A,T,phi,head])
obj = App.ActiveDocument.addObject("Part::FeaturePython","ShipSimulation")
sim = SimInstance.ShipSimulation(obj,
[form.length.value(), form.beam.value(), form.n.value()],
w)
SimInstance.ViewProviderShipSimulation(obj.ViewObject)
return True
def reject(self):
return True
def clicked(self, index):
pass
def open(self):
pass
def needsFullSpace(self):
return True
def isAllowedAlterSelection(self):
return False
def isAllowedAlterView(self):
return True
def isAllowedAlterDocument(self):
return False
def helpRequested(self):
pass
def setupUi(self):
mw = self.getMainWindow()
form = mw.findChild(QtGui.QWidget, "TaskPanel")
form.length = form.findChild(QtGui.QDoubleSpinBox, "Length")
form.beam = form.findChild(QtGui.QDoubleSpinBox, "Beam")
form.n = form.findChild(QtGui.QSpinBox, "N")
form.waves = form.findChild(QtGui.QTableWidget, "Waves")
self.form = form
# Initial values
if self.initValues():
return True
self.retranslateUi()
# Connect Signals and Slots
QtCore.QObject.connect(form.length, QtCore.SIGNAL("valueChanged(double)"), self.onFS)
QtCore.QObject.connect(form.beam, QtCore.SIGNAL("valueChanged(double)"), self.onFS)
QtCore.QObject.connect(form.n, QtCore.SIGNAL("valueChanged(int)"), self.onFS)
QtCore.QObject.connect(form.waves,QtCore.SIGNAL("cellChanged(int,int)"),self.onWaves);
def getMainWindow(self):
"returns the main window"
# using QtGui.qApp.activeWindow() isn't very reliable because if another
# widget than the mainwindow is active (e.g. a dialog) the wrong widget is
# returned
toplevel = QtGui.qApp.topLevelWidgets()
for i in toplevel:
if i.metaObject().className() == "Gui::MainWindow":
return i
raise Exception("No main window found")
def initValues(self):
""" Set initial values for fields
"""
msg = Translator.translate("Ready to work\n")
App.Console.PrintMessage(msg)
return False
def retranslateUi(self):
""" Set user interface locale strings.
"""
self.form.setWindowTitle(Translator.translate("Create a new ship simulation"))
self.form.findChild(QtGui.QGroupBox, "FSDataBox").setTitle(Translator.translate("Free surface"))
self.form.findChild(QtGui.QLabel, "LengthLabel").setText(Translator.translate("Length"))
self.form.findChild(QtGui.QLabel, "BeamLabel").setText(Translator.translate("Beam"))
self.form.findChild(QtGui.QLabel, "NLabel").setText(Translator.translate("Number of points"))
self.form.findChild(QtGui.QGroupBox, "WavesDataBox").setTitle(Translator.translate("Waves"))
labels = []
labels.append(Translator.translate("Amplitude") + " [m]")
labels.append(Translator.translate("Period") + " [s]")
labels.append(Translator.translate("Phase") + " [rad]")
labels.append(Translator.translate("Heading") + " [deg]")
self.form.waves.setHorizontalHeaderLabels(labels)
def onFS(self, value):
""" Method called when free surface data is changed.
@param value Changed value.
"""
pass
def onWaves(self, row, column):
""" Method called when waves data is changed.
@param row Affected row.
@param col Affected column.
"""
item = self.form.waves.item(row,column)
# Row deletion
if column == 0:
if not item.text():
self.form.waves.removeRow(row)
# Ensure that exist one empty item at the end
nRow = self.form.waves.rowCount()
last = self.form.waves.item(nRow-1,0)
if last:
if(last.text() != ''):
self.form.waves.setRowCount(nRow+1)
# Fields must be numbers
for i in range(0,self.form.waves.rowCount()-1): # Avoid last row
for j in range(0,self.form.waves.columnCount()): # Avoid name column
item = self.form.waves.item(i,j)
if not item:
item = QtGui.QTableWidgetItem('0.0')
self.form.waves.setItem(i,j,item)
continue
(number,flag) = item.text().toFloat()
if not flag:
item.setText('0.0')
def createTask():
panel = TaskPanel()
Gui.Control.showDialog(panel)
if panel.setupUi():
Gui.Control.closeDialog(panel)
return None
return panel
#***************************************************************************
#* *
#* Copyright (c) 2011, 2012 *
#* Jose Luis Cercos Pita <jlcercos@gmail.com> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
# FreeCAD modules
import FreeCAD as App
import FreeCADGui as Gui
# Qt library
from PyQt4 import QtGui,QtCore
# Module
import SimInstance
from shipUtils import Paths, Translator
class TaskPanel:
def __init__(self):
self.ui = Paths.modulePath() + "/simCreate/TaskPanel.ui"
def accept(self):
form = self.form
# Read waves data
w = []
for i in range(0,form.waves.rowCount() - 1):
item = form.waves.item(i,0)
A = item.text().toFloat()[0]
item = form.waves.item(i,1)
T = item.text().toFloat()[0]
item = form.waves.item(i,2)
phi = item.text().toFloat()[0]
item = form.waves.item(i,3)
head = item.text().toFloat()[0]
w.append([A,T,phi,head])
obj = App.ActiveDocument.addObject("Part::FeaturePython","ShipSimulation")
sim = SimInstance.ShipSimulation(obj,
[form.length.value(), form.beam.value(), form.n.value()],
w)
SimInstance.ViewProviderShipSimulation(obj.ViewObject)
return True
def reject(self):
return True
def clicked(self, index):
pass
def open(self):
pass
def needsFullSpace(self):
return True
def isAllowedAlterSelection(self):
return False
def isAllowedAlterView(self):
return True
def isAllowedAlterDocument(self):
return False
def helpRequested(self):
pass
def setupUi(self):
mw = self.getMainWindow()
form = mw.findChild(QtGui.QWidget, "TaskPanel")
form.length = form.findChild(QtGui.QDoubleSpinBox, "Length")
form.beam = form.findChild(QtGui.QDoubleSpinBox, "Beam")
form.n = form.findChild(QtGui.QSpinBox, "N")
form.waves = form.findChild(QtGui.QTableWidget, "Waves")
self.form = form
# Initial values
if self.initValues():
return True
self.retranslateUi()
# Connect Signals and Slots
QtCore.QObject.connect(form.length, QtCore.SIGNAL("valueChanged(double)"), self.onFS)
QtCore.QObject.connect(form.beam, QtCore.SIGNAL("valueChanged(double)"), self.onFS)
QtCore.QObject.connect(form.n, QtCore.SIGNAL("valueChanged(int)"), self.onFS)
QtCore.QObject.connect(form.waves,QtCore.SIGNAL("cellChanged(int,int)"),self.onWaves);
def getMainWindow(self):
"returns the main window"
# using QtGui.qApp.activeWindow() isn't very reliable because if another
# widget than the mainwindow is active (e.g. a dialog) the wrong widget is
# returned
toplevel = QtGui.qApp.topLevelWidgets()
for i in toplevel:
if i.metaObject().className() == "Gui::MainWindow":
return i
raise Exception("No main window found")
def initValues(self):
""" Set initial values for fields
"""
msg = Translator.translate("Ready to work\n")
App.Console.PrintMessage(msg)
return False
def retranslateUi(self):
""" Set user interface locale strings.
"""
self.form.setWindowTitle(Translator.translate("Create a new ship simulation"))
self.form.findChild(QtGui.QGroupBox, "FSDataBox").setTitle(Translator.translate("Free surface"))
self.form.findChild(QtGui.QLabel, "LengthLabel").setText(Translator.translate("Length"))
self.form.findChild(QtGui.QLabel, "BeamLabel").setText(Translator.translate("Beam"))
self.form.findChild(QtGui.QLabel, "NLabel").setText(Translator.translate("Number of points"))
self.form.findChild(QtGui.QGroupBox, "WavesDataBox").setTitle(Translator.translate("Waves"))
labels = []
labels.append(Translator.translate("Amplitude") + " [m]")
labels.append(Translator.translate("Period") + " [s]")
labels.append(Translator.translate("Phase") + " [rad]")
labels.append(Translator.translate("Heading") + " [deg]")
self.form.waves.setHorizontalHeaderLabels(labels)
def onFS(self, value):
""" Method called when free surface data is changed.
@param value Changed value.
"""
pass
def onWaves(self, row, column):
""" Method called when waves data is changed.
@param row Affected row.
@param col Affected column.
"""
item = self.form.waves.item(row,column)
# Row deletion
if column == 0:
if not item.text():
self.form.waves.removeRow(row)
# Ensure that exist one empty item at the end
nRow = self.form.waves.rowCount()
if not nRow:
self.form.waves.setRowCount(1)
else:
last = self.form.waves.item(nRow-1,0)
if last:
if(last.text() != ''):
self.form.waves.setRowCount(nRow+1)
# Fields must be numbers
for i in range(0,self.form.waves.rowCount()-1): # Avoid last row
for j in range(0,self.form.waves.columnCount()): # Avoid name column
item = self.form.waves.item(i,j)
if not item:
item = QtGui.QTableWidgetItem('0.0')
self.form.waves.setItem(i,j,item)
continue
(number,flag) = item.text().toFloat()
if not flag:
item.setText('0.0')
def createTask():
panel = TaskPanel()
Gui.Control.showDialog(panel)
if panel.setupUi():
Gui.Control.closeDialog(panel)
return None
return panel

View File

@ -0,0 +1,156 @@
#***************************************************************************
#* *
#* Copyright (c) 2011, 2012 *
#* Jose Luis Cercos Pita <jlcercos@gmail.com> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
# FreeCAD modules
import FreeCAD as App
import FreeCADGui as Gui
# Qt library
from PyQt4 import QtGui,QtCore
# pyOpenCL
import pyopencl as cl
# Module
import SimInstance
from shipUtils import Paths, Translator
from simRun import Simulation
Sim = Simulation.FreeCADShipSimulation
# from Simulation import FreeCADShipSimulation as Sim
class TaskPanel:
def __init__(self):
self.ui = Paths.modulePath() + "/simPost/TaskPanel.ui"
def accept(self):
return True
def reject(self):
return True
def clicked(self, index):
pass
def open(self):
pass
def needsFullSpace(self):
return True
def isAllowedAlterSelection(self):
return False
def isAllowedAlterView(self):
return True
def isAllowedAlterDocument(self):
return False
def helpRequested(self):
pass
def setupUi(self):
mw = self.getMainWindow()
form = mw.findChild(QtGui.QWidget, "TaskPanel")
form.time = form.findChild(QtGui.QLabel, "TimeLabel")
form.first = form.findChild(QtGui.QPushButton, "First")
form.prev = form.findChild(QtGui.QPushButton, "Prev")
form.now = form.findChild(QtGui.QPushButton, "Now")
form.next = form.findChild(QtGui.QPushButton, "Next")
form.last = form.findChild(QtGui.QPushButton, "Last")
self.form = form
# Initial values
if self.initValues():
return True
self.retranslateUi()
# Connect Signals and Slots
QtCore.QObject.connect(form.first, QtCore.SIGNAL("pressed()"), self.onFirst)
QtCore.QObject.connect(form.prev, QtCore.SIGNAL("pressed()"), self.onPrev)
QtCore.QObject.connect(form.now, QtCore.SIGNAL("pressed()"), self.onNow)
QtCore.QObject.connect(form.next, QtCore.SIGNAL("pressed()"), self.onNext)
QtCore.QObject.connect(form.last, QtCore.SIGNAL("pressed()"), self.onLast)
def getMainWindow(self):
"returns the main window"
# using QtGui.qApp.activeWindow() isn't very reliable because if another
# widget than the mainwindow is active (e.g. a dialog) the wrong widget is
# returned
toplevel = QtGui.qApp.topLevelWidgets()
for i in toplevel:
if i.metaObject().className() == "Gui::MainWindow":
return i
raise Exception("No main window found")
def initValues(self):
""" Set initial values for fields
"""
msg = Translator.translate("Ready to work\n")
App.Console.PrintMessage(msg)
return False
def retranslateUi(self):
""" Set user interface locale strings.
"""
self.form.setWindowTitle(Translator.translate("Track simulation"))
self.form.findChild(QtGui.QPushButton, "Now").setText(Translator.translate("Now"))
def onFirst(self):
""" Called when first frame button is pressed.
"""
def onPrev(self):
""" Called when previous frame button is pressed.
"""
def onNow(self):
""" Called when actual frame button is pressed.
"""
sim = Sim()
pos = sim.sim.FS_Position[:]
nx = sim.FS['Nx']
ny = sim.FS['Ny']
for i in range(0, nx):
for j in range(0, ny):
pos[i*ny+j].z = float(sim.FS['pos'][i,j][2])
sim.sim.FS_Position = pos[:]
App.ActiveDocument.recompute()
self.form.time.setText("t = %g s" % (sim.t))
def onNext(self):
""" Called when next frame button is pressed.
"""
def onLast(self):
""" Called when last frame button is pressed.
"""
def createTask():
try:
simulator = Sim()
except:
msg = Translator.translate("Can't find any active simulation!\n")
App.Console.PrintError(msg)
return
panel = TaskPanel()
Gui.Control.showDialog(panel)
if panel.setupUi():
Gui.Control.closeDialog(panel)
return None
return panel

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TaskPanel</class>
<widget class="QWidget" name="TaskPanel">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>300</width>
<height>102</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>300</width>
<height>16777215</height>
</size>
</property>
<property name="windowTitle">
<string>Track simulation</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QPushButton" name="First">
<property name="text">
<string>|&lt;</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="Prev">
<property name="text">
<string>&lt;</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="Next">
<property name="text">
<string>&gt;</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QPushButton" name="Last">
<property name="text">
<string>&gt;|</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="Now">
<property name="text">
<string>Now</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="5">
<widget class="QLabel" name="TimeLabel">
<property name="text">
<string>t = 0 s</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,40 @@
#***************************************************************************
#* *
#* Copyright (c) 2011, 2012 *
#* Jose Luis Cercos Pita <jlcercos@gmail.com> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
# FreeCAD modules
import FreeCAD
import FreeCADGui
# Qt libraries
from PyQt4 import QtGui,QtCore
# Main object
import TaskPanel
def load():
""" Loads the tool """
TaskPanel.createTask()
def stop():
""" Stops the simulation """
TaskPanel.stopSimulation()

View File

@ -21,4 +21,7 @@
#* *
#***************************************************************************
import initialization
from initialization import *
from matrixGen import *
from computeSources import *
from fsEvolution import *

View File

@ -0,0 +1,69 @@
#***************************************************************************
#* *
#* Copyright (c) 2011, 2012 *
#* Jose Luis Cercos Pita <jlcercos@gmail.com> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
# numpy
import numpy as np
grav=9.81
class simComputeSources:
def __init__(self, context=None, queue=None):
""" Constructor.
@param context OpenCL context where apply. Only for compatibility,
must be None.
@param queue OpenCL command queue. Only for compatibility,
must be None.
"""
self.context = context
self.queue = queue
def execute(self, fs, A):
""" Compute potential sources (for velocity potential and
acceleration potential).
@param fs Free surface instance.
@param A Linear system matrix.
"""
self.fs = fs
# Allocate memory
nx = self.fs['Nx']
ny = self.fs['Ny']
nF = nx*ny
nB = 0 # No body for the moment
N = nx*ny + nB
b = np.ndarray(N, dtype=np.float32)
bb = np.ndarray(N, dtype=np.float32)
s = np.ndarray(N, dtype=np.float32)
ss = np.ndarray(N, dtype=np.float32)
# Create independent terms
for i in range(0,nx):
for j in range(0,ny):
b[i*ny+j] = self.fs['velPot'][i,j]
bb[i*ny+j] = self.fs['accPot'][i,j]
# Solve systems
s = np.linalg.solve(A, b)
ss = np.linalg.solve(A, bb)
# Store sources
for i in range(0,nx):
for j in range(0,ny):
self.fs['velSrc'][i,j] = s[i*ny+j]
self.fs['accSrc'][i,j] = ss[i*ny+j]

View File

@ -0,0 +1,177 @@
#***************************************************************************
#* *
#* Copyright (c) 2011, 2012 *
#* Jose Luis Cercos Pita <jlcercos@gmail.com> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
# numpy
import numpy as np
grav=9.81
class simFSEvolution:
def __init__(self, context=None, queue=None):
""" Constructor.
@param context OpenCL context where apply. Only for compatibility,
must be None.
@param queue OpenCL command queue. Only for compatibility,
must be None.
"""
self.context = context
self.queue = queue
def execute(self, fs, waves, dt, t):
""" Compute free surface for next time step.
@param fs Free surface instance.
@param waves Waves instance.
@param dt Time step.
@param t Actual time (without adding dt).
"""
self.fs = fs
nx = self.fs['Nx']
ny = self.fs['Ny']
nF = nx*ny
grad = self.evaluateGradient()
# In order to improve results in really long simulations free surface
# will performed considering external waves and second order effects
# in two different ways. First external waves at time t will be
# substracted, then second order waves will be computed, and finally
# external waves at t+dt will be added.
for i in range(0,nx):
for j in range(0,ny):
pos = np.copy(self.fs['pos'][i,j])
# Substract external waves at time t.
for w in waves['data']:
A = w[0]
T = w[1]
phase = w[2]
heading = np.pi*w[3]/180.0
wl = 0.5 * grav / np.pi * T*T
k = 2.0*np.pi/wl
frec = 2.0*np.pi/T
l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading)
amp = A*np.sin(k*l - frec*t + phase)
pos[2] = pos[2] - amp
amp = - grav/frec*A*np.sin(k*l - frec*t + phase)
self.fs['velPot'][i,j] = self.fs['velPot'][i,j] - amp
amp = grav*A*np.cos(k*l - frec*t + phase)
self.fs['accPot'][i,j] = self.fs['accPot'][i,j] - amp
# Now compute second order waves using position copy,
# where external waves are excluded, in order impose
# free surface boundary condition relative to second
# order phenomena.
self.fs['velPot'][i,j] = self.fs['velPot'][i,j] + \
dt*self.fs['accPot'][i,j]
# self.fs['accPot'][i,j] = self.fs['accPot'][i,j] + \
# grav*pos[2]
# Restore external waves to velocity and acceleration
# potentials.
for w in waves['data']:
A = w[0]
T = w[1]
phase = w[2]
heading = np.pi*w[3]/180.0
wl = 0.5 * grav / np.pi * T*T
k = 2.0*np.pi/wl
frec = 2.0*np.pi/T
l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading)
amp = - grav/frec*A*np.sin(k*l - frec*(t+dt) + phase)
self.fs['velPot'][i,j] = self.fs['velPot'][i,j] + amp
amp = grav*A*np.cos(k*l - frec*(t+dt) + phase)
self.fs['accPot'][i,j] = self.fs['accPot'][i,j] + amp
# Update free surface point position
gradVal = np.dot(np.abs(grad[i*ny+j]),grad[i*ny+j])
gradVal = np.copysign(np.sqrt(np.abs(gradVal)), gradVal)
self.fs['pos'][i,j][2] = self.fs['pos'][i,j][2] + dt*gradVal
# Impose values at beach (far free surface)
for i in range(0,nx):
for j in [0,ny-1]:
self.beach(i,j, waves, dt, t)
for j in range(0,ny):
for i in [0,nx-1]:
self.beach(i,j, waves, dt, t)
def evaluateGradient(self):
""" Evaluate potential gradients over free surface.
@return Potential gradients.
"""
nx = self.fs['Nx']
ny = self.fs['Ny']
nF = nx*ny
grad = np.ndarray((nF,3), dtype=np.float32)
for i in range(0,nx):
for j in range(0,ny):
pos = self.fs['pos'][i,j]
grad[i*ny+j] = self.gradientphi(pos)
gradVal = np.dot(np.abs(grad[i*ny+j]),grad[i*ny+j])
gradVal = np.copysign(np.sqrt(np.abs(gradVal)), gradVal)
return grad
def gradientphi(self, pos):
""" Compute gradient over desired position.
@param pos Point to evaluate.
@return Potential gradient.
"""
nx = self.fs['Nx']
ny = self.fs['Ny']
grad = np.zeros(3, dtype=np.float32)
for i in range(0,nx):
for j in range(0,ny):
# Get source position (desingularized)
srcPos = np.copy(self.fs['pos'][i,j])
area = self.fs['area'][i,j]
srcPos[2] = srcPos[2] + np.sqrt(area)
src = self.fs['velSrc'][i,j]
# Get distance between points
d = pos-srcPos
grad = grad + d/np.dot(d,d)*src*area
# Discard Z induced effect by desingularization
grad[2] = 0.
return grad
def beach(self, i,j, waves, dt, t):
""" Compute far free surface where only
incident waves can be taken into account.
@param i First free surface cell index.
@param j Second free surface cell index.
@param waves Waves instance.
@param dt Time step.
@param t Actual time (without adding dt).
"""
pos = self.fs['pos'][i,j]
pos[2] = 0.
self.fs['velPot'][i,j] = 0.
self.fs['accPot'][i,j] = 0.
for w in waves['data']:
A = w[0]
T = w[1]
phase = w[2]
heading = np.pi*w[3]/180.0
wl = 0.5 * grav / np.pi * T*T
k = 2.0*np.pi/wl
frec = 2.0*np.pi/T
l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading)
amp = A*np.sin(k*l - frec*(t+dt) + phase)
self.fs['pos'][i,j][2] = self.fs['pos'][i,j][2] + amp
amp = - grav/frec*A*np.sin(k*l - frec*(t+dt) + phase)
self.fs['velPot'][i,j] = self.fs['velPot'][i,j] + amp
amp = grav*A*np.cos(k*l - frec*(t+dt) + phase)
self.fs['accPot'][i,j] = self.fs['accPot'][i,j] + amp

View File

@ -26,9 +26,9 @@ import numpy as np
grav=9.81
class perform:
class simInitialization:
def __init__(self, FSmesh, waves, context=None, queue=None):
""" Constructor, includes program loading.
""" Constructor.
@param FSmesh Initial free surface mesh.
@param waves Considered simulation waves (A,T,phi,heading).
@param context OpenCL context where apply. Only for compatibility,
@ -40,6 +40,11 @@ class perform:
self.queue = queue
self.loadData(FSmesh, waves)
self.execute()
# Compute time step
self.dt = 0.1
for w in self.waves['data']:
if(self.dt > w[1]/200.0):
self.dt = w[1]/200.0
def loadData(self, FSmesh, waves):
""" Convert data to numpy format.
@ -51,12 +56,12 @@ class perform:
nW = len(waves)
# Mesh data
p = np.ndarray((nx,ny, 3), dtype=np.float32)
v = np.ndarray((nx,ny, 3), dtype=np.float32)
f = np.ndarray((nx,ny, 3), dtype=np.float32)
n = np.ndarray((nx,ny, 3), dtype=np.float32)
a = np.ndarray((nx,ny, 1), dtype=np.float32)
phi = np.ndarray((nx,ny, 1), dtype=np.float32)
Phi = np.ndarray((nx,ny, 1), dtype=np.float32)
a = np.ndarray((nx,ny), dtype=np.float32)
phi = np.ndarray((nx,ny), dtype=np.float32)
Phi = np.ndarray((nx,ny), dtype=np.float32)
s = np.ndarray((nx,ny), dtype=np.float32)
ss = np.ndarray((nx,ny), dtype=np.float32)
for i in range(0, nx):
for j in range(0, ny):
pos = FSmesh[i][j].pos
@ -65,18 +70,16 @@ class perform:
p[i,j,0] = pos.x
p[i,j,1] = pos.y
p[i,j,2] = pos.z
v[i,j,0] = 0.
v[i,j,1] = 0.
v[i,j,2] = 0.
f[i,j,0] = 0.
f[i,j,1] = 0.
f[i,j,2] = 0.
n[i,j,0] = normal.x
n[i,j,1] = normal.y
n[i,j,2] = normal.z
a[i,j] = area
self.fs = {'Nx':nx, 'Ny':ny, 'pos':p, 'vel':v, 'acc':f, \
'normal':n, 'area':a, 'velPot':phi, 'accPot':Phi}
phi[i,j] = 0.
Phi[i,j] = 0.
s[i,j] = 0.
ss[i,j] = 0.
self.fs = {'Nx':nx, 'Ny':ny, 'pos':p, 'normal':n, 'area':a, \
'velPot':phi, 'accPot':Phi, 'velSrc':s, 'accSrc':ss}
# Waves data
w = np.ndarray((nW, 4), dtype=np.float32)
for i in range(0,nW):
@ -85,6 +88,11 @@ class perform:
w[i,2] = waves[i][2]
w[i,3] = waves[i][3]
self.waves = {'N':nW, 'data':w}
# Linear system matrix
nF = nx*ny
nB = 0 # No body for the moment
N = nx*ny + nB
self.A = np.ndarray((N, N), dtype=np.float32)
def execute(self):
""" Compute initial conditions. """
@ -92,6 +100,7 @@ class perform:
ny = self.fs['Ny']
for i in range(0,nx):
for j in range(0,ny):
self.fs['pos'][i,j][2] = 0.
for w in self.waves['data']:
A = w[0]
T = w[1]
@ -104,11 +113,7 @@ class perform:
l = pos[0]*np.cos(heading) + pos[1]*np.sin(heading)
amp = A*np.sin(k*l + phase)
self.fs['pos'][i,j][2] = self.fs['pos'][i,j][2] + amp
amp = frec*A*np.cos(k*l + phase)
self.fs['vel'][i,j][2] = self.fs['vel'][i,j][2] - amp
amp = frec*frec*A*np.sin(k*l + phase)
self.fs['acc'][i,j][2] = self.fs['acc'][i,j][2] - amp
amp = grav/frec*A*np.sin(k*l + phase)
amp = - grav/frec*A*np.sin(k*l + phase)
self.fs['velPot'][i,j] = self.fs['velPot'][i,j] + amp
amp = grav*A*np.cos(k*l + phase)
self.fs['accPot'][i,j] = self.fs['accPot'][i,j] + amp

View File

@ -0,0 +1,79 @@
#***************************************************************************
#* *
#* Copyright (c) 2011, 2012 *
#* Jose Luis Cercos Pita <jlcercos@gmail.com> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
# numpy
import numpy as np
grav=9.81
class simMatrixGen:
def __init__(self, context=None, queue=None):
""" Constructor.
@param context OpenCL context where apply. Only for compatibility,
must be None.
@param queue OpenCL command queue. Only for compatibility,
must be None.
"""
self.context = context
self.queue = queue
def execute(self, fs, A):
""" Compute system matrix.
@param fs Free surface instance.
@param A Linear system matrix.
"""
self.fs = fs
nx = self.fs['Nx']
ny = self.fs['Ny']
nF = nx*ny
nB = 0 # No body for the moment
N = nx*ny + nB
# Fluid sources rows
for i in range(0,nx):
for j in range(0,ny):
# Append fluid effect
pos = self.fs['pos'][i,j]
A[i*ny+j,0:nF] = self.fluidEffect(pos)
# Append body effect
# ...
def fluidEffect(self, pos):
""" Compute fluid effect terms over desired position. Desingularized
sources must taken into account.
@param pos Point to evaluate.
@return Fluid effect row.
"""
nx = self.fs['Nx']
ny = self.fs['Ny']
nF = nx*ny
row = np.ndarray(nF, dtype=np.float32)
for i in range(0,nx):
for j in range(0,ny):
# Get source position (desingularized)
source = np.copy(self.fs['pos'][i,j])
area = self.fs['area'][i,j]
source[2] = source[2] + np.sqrt(area)
# Get distance between points
d = np.linalg.norm(pos-source)
row[i*ny+j] = np.log(d)*area
return row

View File

@ -21,7 +21,6 @@
#* *
#***************************************************************************
import time
from math import *
import threading
@ -49,11 +48,12 @@ class Singleton(type):
class FreeCADShipSimulation(threading.Thread):
__metaclass__ = Singleton
def __init__ (self, device, endTime, output, FSmesh, waves):
def __init__ (self, device, endTime, output, simInstance, FSmesh, waves):
""" Thread constructor.
@param device Device to use.
@param endTime Maximum simulation time.
@param output [Rate,Type] Output rate, Type=0 if FPS, 1 if IPF.
@param simInstance Simulaation instance.
@param FSmesh Free surface mesh faces.
@param waves Waves parameters (A,T,phi,heading)
"""
@ -71,6 +71,7 @@ class FreeCADShipSimulation(threading.Thread):
# Storage data
self.endTime = endTime
self.output = output
self.sim = simInstance
self.FSmesh = FSmesh
self.waves = waves
@ -80,19 +81,37 @@ class FreeCADShipSimulation(threading.Thread):
self.active = True
# Simulation stuff
if self.device == None:
from Sim import initialization
from Sim import *
else:
from clSim import initialization
msg = Translator.translate("\t[Sim]: Initializating OpenCL...\n")
from clSim import *
msg = Translator.translate("\t[Sim]: Initializating...\n")
FreeCAD.Console.PrintMessage(msg)
init = initialization.perform(self.FSmesh,self.waves,self.context,self.queue)
msg = Translator.translate("\t[Sim]: Iterating (outputs will be noticed)...\n")
init = simInitialization(self.FSmesh,self.waves,self.context,self.queue)
matGen = simMatrixGen(self.context,self.queue)
solver = simComputeSources(self.context,self.queue)
fsEvol = simFSEvolution(self.context,self.queue)
A = init.A
FS = init.fs
waves = init.waves
dt = init.dt
self.t = 0.0
self.FS = FS
nx = FS['Nx']
ny = FS['Ny']
msg = Translator.translate("\t[Sim]: Iterating...\n")
FreeCAD.Console.PrintMessage(msg)
while self.active:
print("Im thread, Im running...")
time.sleep(1)
# ...
print("Im thread, step done!")
while self.active and self.t < self.endTime:
msg = Translator.translate("\t\t[Sim]: Generating linear system matrix...\n")
FreeCAD.Console.PrintMessage(msg)
matGen.execute(FS, A)
msg = Translator.translate("\t\t[Sim]: Solving linear systems...\n")
FreeCAD.Console.PrintMessage(msg)
solver.execute(FS, A)
msg = Translator.translate("\t\t[Sim]: Time integrating...\n")
FreeCAD.Console.PrintMessage(msg)
fsEvol.execute(FS, waves, dt, self.t)
self.t = self.t + dt
FreeCAD.Console.PrintMessage('t = %g s\n' % (self.t))
# Set thread as stopped (and prepare it to restarting)
self.active = False
threading.Event().set()

View File

@ -69,7 +69,7 @@ class TaskPanel:
msg = Translator.translate("Launching simulation...\n")
App.Console.PrintMessage(msg)
# Build simulation thread
simulator = Sim(device, endTime, output, FSMesh, waves)
simulator = Sim(device, endTime, output, self.sim, FSMesh, waves)
simulator.start()
msg = Translator.translate("Done!\n")
App.Console.PrintMessage(msg)

View File

@ -1350,6 +1350,8 @@ void SketchObject::rebuildExternalGeometry(void)
break;
}
}
rebuildVertexIndex();
}
std::vector<Part::Geometry*> SketchObject::getCompleteGeometry(void) const
@ -1491,8 +1493,6 @@ void SketchObject::Restore(XMLReader &reader)
{
// read the father classes
Part::Part2DObject::Restore(reader);
Constraints.acceptGeometry(getCompleteGeometry());
rebuildVertexIndex();
}
void SketchObject::onChanged(const App::Property* prop)

View File

@ -1636,15 +1636,7 @@ void CmdSketcherConstrainAngle::activated(int iMsg)
const std::vector<Sketcher::Constraint *> &ConStr = dynamic_cast<Sketcher::SketchObject*>(selection[0].getObject())->Constraints.getValues();
Sketcher::Constraint *constr = ConStr[ConStr.size() -1];
float sf = 1.f;
Gui::Document *doc = getActiveGuiDocument();
if (doc && doc->getInEdit() && doc->getInEdit()->isDerivedFrom(SketcherGui::ViewProviderSketch::getClassTypeId())) {
SketcherGui::ViewProviderSketch *vp = dynamic_cast<SketcherGui::ViewProviderSketch*>(doc->getInEdit());
sf = vp->getScaleFactor();
constr->LabelDistance = 2. * sf;
vp->draw(); // Redraw
}
updateDatumDistance(getActiveGuiDocument(), constr);
//updateActive();
getSelection().clearSelection();

View File

@ -25,6 +25,7 @@
#ifndef _PreComp_
#endif
#include <boost/math/special_functions/fpclassify.hpp>
#include <Base/Console.h>
#include <Gui/Application.h>
@ -142,15 +143,20 @@ public:
virtual void mouseMove(Base::Vector2D onSketchPos)
{
setPositionText(onSketchPos);
if (Mode==STATUS_SEEK_First) {
setPositionText(onSketchPos);
if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) {
renderSuggestConstraintsCursor(sugConstr1);
return;
}
}
else if (Mode==STATUS_SEEK_Second){
float length = (onSketchPos - EditCurve[0]).Length();
float angle = (onSketchPos - EditCurve[0]).GetAngle(Base::Vector2D(1.f,0.f));
SbString text;
text.sprintf(" (%.1f,%.1fdeg)", length, angle * 180 / M_PI);
setPositionText(onSketchPos, text);
EditCurve[1] = onSketchPos;
sketchgui->drawEdit(EditCurve);
if (seekAutoConstraint(sugConstr2, onSketchPos, onSketchPos - EditCurve[0])) {
@ -301,15 +307,21 @@ public:
virtual void mouseMove(Base::Vector2D onSketchPos)
{
setPositionText(onSketchPos);
if (Mode==STATUS_SEEK_First) {
setPositionText(onSketchPos);
if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) {
renderSuggestConstraintsCursor(sugConstr1);
return;
}
}
else if (Mode==STATUS_SEEK_Second) {
float dx = onSketchPos.fX - EditCurve[0].fX;
float dy = onSketchPos.fY - EditCurve[0].fY;
SbString text;
text.sprintf(" (%.1f x %.1f)", dx, dy);
setPositionText(onSketchPos, text);
EditCurve[2] = onSketchPos;
EditCurve[1] = Base::Vector2D(onSketchPos.fX ,EditCurve[0].fY);
EditCurve[3] = Base::Vector2D(EditCurve[0].fX,onSketchPos.fY);
@ -488,50 +500,106 @@ class DrawSketchHandlerLineSet: public DrawSketchHandler
{
public:
DrawSketchHandlerLineSet()
: Mode(STATUS_SEEK_First),LineMode(LINE_MODE_Line),EditCurve(2),
firstVertex(-1),firstCurve(-1),previousCurve(-1),previousPosId(-1),
isTangent(false) {}
: Mode(STATUS_SEEK_First),SegmentMode(SEGMENT_MODE_Line),
TransitionMode(TRANSITION_MODE_Free),suppressTransition(false),EditCurve(2),
firstVertex(-1),firstCurve(-1),previousCurve(-1),previousPosId(Sketcher::none) {}
virtual ~DrawSketchHandlerLineSet() {}
/// mode table
enum SelectMode {
enum SELECT_MODE {
STATUS_SEEK_First, /**< enum value ----. */
STATUS_SEEK_Second, /**< enum value ----. */
STATUS_Do,
STATUS_Close
};
enum SelectLineMode
enum SEGMENT_MODE
{
LINE_MODE_Arc,
LINE_MODE_Line
SEGMENT_MODE_Arc,
SEGMENT_MODE_Line
};
enum TRANSITION_MODE
{
TRANSITION_MODE_Free,
TRANSITION_MODE_Tangent,
TRANSITION_MODE_Perpendicular_L,
TRANSITION_MODE_Perpendicular_R
};
virtual void registerPressedKey(bool pressed, int key)
{
if (key == SoKeyboardEvent::A && pressed && previousCurve != -1) {
if (LineMode != LINE_MODE_Arc) {
Base::Vector2D onSketchPos = EditCurve[isTangent ? 2 : 1];
LineMode = LINE_MODE_Arc;
if (previousCurve != -1)
isTangent = true;
else
isTangent = false;
EditCurve.resize(32);
mouseMove(onSketchPos); // trigger an update of EditCurve
if (Mode != STATUS_SEEK_Second)
return; // SegmentMode can be changed only in STATUS_SEEK_Second mode
if (key == SoKeyboardEvent::M && pressed && previousCurve != -1) {
// loop through the following modes:
// SEGMENT_MODE_Line, TRANSITION_MODE_Free / TRANSITION_MODE_Tangent
// SEGMENT_MODE_Line, TRANSITION_MODE_Perpendicular_L
// SEGMENT_MODE_Line, TRANSITION_MODE_Tangent / TRANSITION_MODE_Free
// SEGMENT_MODE_Arc, TRANSITION_MODE_Tangent
// SEGMENT_MODE_Arc, TRANSITION_MODE_Perpendicular_L
// SEGMENT_MODE_Arc, TRANSITION_MODE_Perpendicular_R
Base::Vector2D onSketchPos;
if (SegmentMode == SEGMENT_MODE_Line)
onSketchPos = EditCurve[EditCurve.size()-1];
else
onSketchPos = EditCurve[29];
const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(previousCurve);
if (SegmentMode == SEGMENT_MODE_Line) {
switch (TransitionMode) {
case TRANSITION_MODE_Free:
if (geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { // 3rd mode
SegmentMode = SEGMENT_MODE_Arc;
TransitionMode = TRANSITION_MODE_Tangent;
}
else // 1st mode
TransitionMode = TRANSITION_MODE_Perpendicular_L;
break;
case TRANSITION_MODE_Perpendicular_L: // 2nd mode
if (geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId())
TransitionMode = TRANSITION_MODE_Free;
else
TransitionMode = TRANSITION_MODE_Tangent;
break;
case TRANSITION_MODE_Tangent:
if (geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) // 1st mode
TransitionMode = TRANSITION_MODE_Perpendicular_L;
else { // 3rd mode
SegmentMode = SEGMENT_MODE_Arc;
TransitionMode = TRANSITION_MODE_Tangent;
}
break;
default: // unexpected mode
TransitionMode = TRANSITION_MODE_Free;
break;
}
}
else {
Base::Vector2D onSketchPos = EditCurve[29];
LineMode = LINE_MODE_Line;
if (previousCurve != -1) {
const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(previousCurve);
if (geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId())
isTangent = true;
else
isTangent = false;
switch (TransitionMode) {
case TRANSITION_MODE_Tangent: // 4th mode
TransitionMode = TRANSITION_MODE_Perpendicular_L;
break;
case TRANSITION_MODE_Perpendicular_L: // 5th mode
TransitionMode = TRANSITION_MODE_Perpendicular_R;
break;
default: // 6th mode (Perpendicular_R) + unexpexted mode
SegmentMode = SEGMENT_MODE_Line;
if (geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId())
TransitionMode = TRANSITION_MODE_Tangent;
else
TransitionMode = TRANSITION_MODE_Free;
break;
}
EditCurve.resize(isTangent ? 3 : 2);
mouseMove(onSketchPos); // trigger an update of EditCurve
}
if (SegmentMode == SEGMENT_MODE_Line)
EditCurve.resize(TransitionMode == TRANSITION_MODE_Free ? 2 : 3);
else
EditCurve.resize(32);
mouseMove(onSketchPos); // trigger an update of EditCurve
}
}
@ -542,31 +610,59 @@ public:
virtual void mouseMove(Base::Vector2D onSketchPos)
{
setPositionText(onSketchPos);
suppressTransition = false;
if (Mode==STATUS_SEEK_First) {
setPositionText(onSketchPos);
if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) {
renderSuggestConstraintsCursor(sugConstr1);
return;
}
}
else if (Mode==STATUS_SEEK_Second){
if (LineMode == LINE_MODE_Line) {
EditCurve[isTangent ? 2 : 1] = onSketchPos;
if (isTangent) {
if (SegmentMode == SEGMENT_MODE_Line) {
EditCurve[EditCurve.size()-1] = onSketchPos;
if (TransitionMode == TRANSITION_MODE_Tangent) {
Base::Vector2D Tangent(dirVec.x,dirVec.y);
EditCurve[1].ProjToLine(EditCurve[2] - EditCurve[0], Tangent);
if (EditCurve[1] * Tangent < 0) {
EditCurve[1] = EditCurve[2];
suppressTransition = true;
}
else
EditCurve[1] = EditCurve[0] + EditCurve[1];
}
else if (TransitionMode == TRANSITION_MODE_Perpendicular_L ||
TransitionMode == TRANSITION_MODE_Perpendicular_R) {
Base::Vector2D Perpendicular(-dirVec.y,dirVec.x);
EditCurve[1].ProjToLine(EditCurve[2] - EditCurve[0], Perpendicular);
EditCurve[1] = EditCurve[0] + EditCurve[1];
}
sketchgui->drawEdit(EditCurve);
if (!isTangent) {
float length = (EditCurve[1] - EditCurve[0]).Length();
float angle = (EditCurve[1] - EditCurve[0]).GetAngle(Base::Vector2D(1.f,0.f));
SbString text;
text.sprintf(" (%.1f,%.1fdeg)", length, angle * 180 / M_PI);
setPositionText(EditCurve[1], text);
if (TransitionMode == TRANSITION_MODE_Free) {
if (seekAutoConstraint(sugConstr2, onSketchPos, onSketchPos - EditCurve[0])) {
renderSuggestConstraintsCursor(sugConstr2);
return;
}
}
}
else if (LineMode == LINE_MODE_Arc) {
Base::Vector2D Tangent(dirVec.x,dirVec.y);
else if (SegmentMode == SEGMENT_MODE_Arc) {
Base::Vector2D Tangent;
if (TransitionMode == TRANSITION_MODE_Tangent)
Tangent = Base::Vector2D(dirVec.x,dirVec.y);
else if (TransitionMode == TRANSITION_MODE_Perpendicular_L)
Tangent = Base::Vector2D(-dirVec.y,dirVec.x);
else if (TransitionMode == TRANSITION_MODE_Perpendicular_R)
Tangent = Base::Vector2D(dirVec.y,-dirVec.x);
float theta = Tangent.GetAngle(onSketchPos - EditCurve[0]);
arcRadius = (onSketchPos - EditCurve[0]).Length()/(2.0*sin(theta));
// At this point we need a unit normal vector pointing torwards
@ -580,11 +676,10 @@ public:
float y3 = onSketchPos.fY;
if ((x2*y3-x3*y2)-(x1*y3-x3*y1)+(x1*y2-x2*y1) > 0)
arcRadius *= -1;
if (boost::math::isnan(arcRadius) || boost::math::isinf(arcRadius))
arcRadius = 0.f;
Base::Vector3d centerVec = dirVec % Base::Vector3d(0.f,0.f,1.0);
centerVec.Normalize(); // this step should actually be redundant
CenterPoint = EditCurve[0] + Base::Vector2D(arcRadius * centerVec.x, arcRadius * centerVec.y);
CenterPoint = EditCurve[0] + Base::Vector2D(arcRadius * Tangent.fY, -arcRadius * Tangent.fX);
float rx = EditCurve[0].fX - CenterPoint.fX;
float ry = EditCurve[0].fY - CenterPoint.fY;
@ -594,6 +689,8 @@ public:
float rxe = onSketchPos.fX - CenterPoint.fX;
float rye = onSketchPos.fY - CenterPoint.fY;
float arcAngle = atan2(-rxe*ry + rye*rx, rxe*rx + rye*ry);
if (boost::math::isnan(arcAngle) || boost::math::isinf(arcAngle))
arcAngle = 0.f;
if (arcRadius >= 0 && arcAngle > 0)
arcAngle -= 2*M_PI;
if (arcRadius < 0 && arcAngle < 0)
@ -611,6 +708,11 @@ public:
EditCurve[31] = EditCurve[0];
sketchgui->drawEdit(EditCurve);
SbString text;
text.sprintf(" (%.1fR,%.1fdeg)", std::abs(arcRadius), arcAngle * 180 / M_PI);
setPositionText(onSketchPos, text);
if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f))) {
renderSuggestConstraintsCursor(sugConstr2);
return;
@ -622,35 +724,45 @@ public:
virtual bool pressButton(Base::Vector2D onSketchPos)
{
if (Mode==STATUS_SEEK_First) {
// remember our first point
firstVertex = getHighestVertexIndex() + 1;
firstCurve = getHighestCurveIndex() + 1;
// TODO: here we should check if there is a preselected point
// and set up a transition from the neighbouring segment.
// (peviousCurve, previousPosId, dirVec, isTangent)
// in that case we should set firstCurve and firstVertex to -1
// in order to disable closing the wire
if (LineMode == LINE_MODE_Line)
EditCurve.resize(isTangent ? 3 : 2);
else if (LineMode == LINE_MODE_Arc)
if (Mode == STATUS_SEEK_First) {
EditCurve[0] = onSketchPos; // this may be overwritten if previousCurve is found
// here we check if there is a preselected point and
// we set up a transition from the neighbouring segment.
// (peviousCurve, previousPosId, dirVec, TransitionMode)
for (int i=0; i < sugConstr1.size(); i++)
if (sugConstr1[i].Type == Sketcher::Coincident) {
const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(sugConstr1[i].GeoId);
if ((geom->getTypeId() == Part::GeomLineSegment::getClassTypeId() ||
geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) &&
(sugConstr1[i].PosId == Sketcher::start ||
sugConstr1[i].PosId == Sketcher::end)) {
previousCurve = sugConstr1[i].GeoId;
previousPosId = sugConstr1[i].PosId;
updateTransitionData(previousCurve,previousPosId); // -> dirVec, EditMode[0]
if (geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId())
TransitionMode = TRANSITION_MODE_Tangent;
sugConstr1.erase(sugConstr1.begin()+i); // actually we should clear the vector completely
break;
}
}
// in case a transition is set up, firstCurve and firstVertex should
// remain set to -1 in order to disable closing the wire
if (previousCurve == -1) {
// remember our first point
firstVertex = getHighestVertexIndex() + 1;
firstCurve = getHighestCurveIndex() + 1;
}
if (SegmentMode == SEGMENT_MODE_Line)
EditCurve.resize(TransitionMode == TRANSITION_MODE_Free ? 2 : 3);
else if (SegmentMode == SEGMENT_MODE_Arc)
EditCurve.resize(32);
EditCurve[0] = onSketchPos;
Mode = STATUS_SEEK_Second;
}
else if (Mode==STATUS_SEEK_Second) {
if (LineMode == LINE_MODE_Line) {
EditCurve[isTangent ? 2 : 1] = onSketchPos;
if (isTangent) {
Base::Vector2D Tangent(dirVec.x,dirVec.y);
EditCurve[1].ProjToLine(EditCurve[2] - EditCurve[0], Tangent);
EditCurve[1] = EditCurve[0] + EditCurve[1];
}
}
else if (LineMode == LINE_MODE_Arc)
EditCurve[29] = onSketchPos; // not so important
sketchgui->drawEdit(EditCurve);
applyCursor();
else if (Mode == STATUS_SEEK_Second) {
// exit on clicking exactly at the same position (e.g. double click)
if (onSketchPos == EditCurve[0]) {
unsetCursor();
@ -659,7 +771,7 @@ public:
sketchgui->drawEdit(EditCurve);
sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider
}
if (sketchgui->getPreselectPoint() == firstVertex)
if (sketchgui->getPreselectPoint() == firstVertex && firstVertex != -1)
Mode = STATUS_Close;
else
Mode = STATUS_Do;
@ -671,7 +783,7 @@ public:
{
if (Mode == STATUS_Do || Mode == STATUS_Close) {
if (LineMode == LINE_MODE_Line) {
if (SegmentMode == SEGMENT_MODE_Line) {
// open the transaction
Gui::Command::openCommand("Add line to sketch wire");
// issue the geometry
@ -680,7 +792,11 @@ public:
sketchgui->getObject()->getNameInDocument(),
EditCurve[0].fX,EditCurve[0].fY,EditCurve[1].fX,EditCurve[1].fY);
}
else if (LineMode == LINE_MODE_Arc) { // We're dealing with an Arc
else if (SegmentMode == SEGMENT_MODE_Arc) { // We're dealing with an Arc
if (!boost::math::isnormal(arcRadius)) {
Mode = STATUS_SEEK_Second;
return true;
}
Gui::Command::openCommand("Add arc to sketch wire");
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.addGeometry(Part.ArcOfCircle"
@ -691,15 +807,24 @@ public:
}
// issue the constraint
if (previousCurve != -1) {
int lastCurve = previousCurve+1;
int lastStartPosId = (LineMode == LINE_MODE_Arc && startAngle > endAngle) ? 2 : 1;
int lastEndPosId = (LineMode == LINE_MODE_Arc && startAngle > endAngle) ? 1 : 2;
// in case of a tangency constraint, the coincident constraint is redundant
int lastCurve = getHighestCurveIndex();
Sketcher::PointPos lastStartPosId = (SegmentMode == SEGMENT_MODE_Arc && startAngle > endAngle) ?
Sketcher::end : Sketcher::start;
Sketcher::PointPos lastEndPosId = (SegmentMode == SEGMENT_MODE_Arc && startAngle > endAngle) ?
Sketcher::start : Sketcher::end;
// in case of a tangency constraint, the coincident constraint is redundant
std::string constrType = "Coincident";
if (!suppressTransition) {
if (TransitionMode == TRANSITION_MODE_Tangent)
constrType = "Tangent";
else if (TransitionMode == TRANSITION_MODE_Perpendicular_L ||
TransitionMode == TRANSITION_MODE_Perpendicular_R)
constrType = "Perpendicular";
}
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('%s',%i,%i,%i,%i)) ",
sketchgui->getObject()->getNameInDocument(),
isTangent ? "Tangent" : "Coincident",
previousCurve, previousPosId /* == 2 */, lastCurve, lastStartPosId);
sketchgui->getObject()->getNameInDocument(), constrType.c_str(),
previousCurve, previousPosId, lastCurve, lastStartPosId);
if (Mode == STATUS_Close) {
int firstGeoId;
Sketcher::PointPos firstPosId;
@ -750,61 +875,74 @@ public:
// remember the vertex for the next rounds constraint..
previousCurve = getHighestCurveIndex();
previousPosId = (LineMode == LINE_MODE_Arc && startAngle > endAngle) ? 1 : 2;
previousPosId = (SegmentMode == SEGMENT_MODE_Arc && startAngle > endAngle) ?
Sketcher::start : Sketcher::end; // cw arcs are rendered in reverse
// setup for the next line segment
// Use updated endPoint as autoconstraints can modify the position
// Need to determine if the previous element was a line or an arc or ???
const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(getHighestCurveIndex());
if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment *>(geom);
EditCurve[0] = Base::Vector2D(lineSeg->getEndPoint().x, lineSeg->getEndPoint().y);
dirVec.Set(lineSeg->getEndPoint().x - lineSeg->getStartPoint().x,
lineSeg->getEndPoint().y - lineSeg->getStartPoint().y,
0.f);
}
else if (geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
assert(LineMode == LINE_MODE_Arc);
const Part::GeomArcOfCircle *arcSeg = dynamic_cast<const Part::GeomArcOfCircle *>(geom);
if (startAngle > endAngle) {
EditCurve[0] = Base::Vector2D(arcSeg->getStartPoint().x,arcSeg->getStartPoint().y);
dirVec = Base::Vector3d(0.f,0.f,-1.0) % (arcSeg->getStartPoint()-arcSeg->getCenter());
}
else { // cw arcs are rendered in reverse
EditCurve[0] = Base::Vector2D(arcSeg->getEndPoint().x,arcSeg->getEndPoint().y);
dirVec = Base::Vector3d(0.f,0.f,1.0) % (arcSeg->getEndPoint()-arcSeg->getCenter());
}
}
dirVec.Normalize();
// calculate dirVec and EditCurve[0]
updateTransitionData(previousCurve,previousPosId);
applyCursor();
Mode = STATUS_SEEK_Second;
isTangent = (LineMode == LINE_MODE_Arc);
LineMode = LINE_MODE_Line;
EditCurve.resize(isTangent ? 3 : 2);
EditCurve[1] = EditCurve[0];
if (isTangent)
if (SegmentMode == SEGMENT_MODE_Arc) {
TransitionMode = TRANSITION_MODE_Tangent;
EditCurve.resize(3);
EditCurve[2] = EditCurve[0];
sketchgui->drawEdit(EditCurve);
}
else {
TransitionMode = TRANSITION_MODE_Free;
EditCurve.resize(2);
}
SegmentMode = SEGMENT_MODE_Line;
EditCurve[1] = EditCurve[0];
mouseMove(onSketchPos); // trigger an update of EditCurve
}
}
return true;
}
protected:
SelectMode Mode;
SelectLineMode LineMode;
SELECT_MODE Mode;
SEGMENT_MODE SegmentMode;
TRANSITION_MODE TransitionMode;
bool suppressTransition;
std::vector<Base::Vector2D> EditCurve;
int firstVertex;
int firstCurve;
int previousPosId;
int previousCurve;
Sketcher::PointPos previousPosId;
std::vector<AutoConstraint> sugConstr1, sugConstr2;
Base::Vector2D CenterPoint;
Base::Vector3d dirVec;
bool isTangent;
float startAngle, endAngle, arcRadius;
void updateTransitionData(int GeoId, Sketcher::PointPos PosId) {
// Use updated startPoint/endPoint as autoconstraints can modify the position
const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(GeoId);
if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment *>(geom);
EditCurve[0] = Base::Vector2D(lineSeg->getEndPoint().x, lineSeg->getEndPoint().y);
dirVec.Set(lineSeg->getEndPoint().x - lineSeg->getStartPoint().x,
lineSeg->getEndPoint().y - lineSeg->getStartPoint().y,
0.f);
if (PosId == Sketcher::start)
dirVec *= -1;
}
else if (geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
const Part::GeomArcOfCircle *arcSeg = dynamic_cast<const Part::GeomArcOfCircle *>(geom);
if (PosId == Sketcher::start) {
EditCurve[0] = Base::Vector2D(arcSeg->getStartPoint().x,arcSeg->getStartPoint().y);
dirVec = Base::Vector3d(0.f,0.f,-1.0) % (arcSeg->getStartPoint()-arcSeg->getCenter());
}
else {
EditCurve[0] = Base::Vector2D(arcSeg->getEndPoint().x,arcSeg->getEndPoint().y);
dirVec = Base::Vector3d(0.f,0.f,1.0) % (arcSeg->getEndPoint()-arcSeg->getCenter());
}
}
dirVec.Normalize();
}
};
@ -916,11 +1054,10 @@ public:
// Display radius and start angle
float radius = (onSketchPos - EditCurve[0]).Length();
float angle = atan2f(dy_ , dx_) * 180 / M_PI;
float angle = atan2f(dy_ , dx_);
char buf[40];
sprintf( buf, " (R%.1f,%.1f)", radius, angle);
std::string text = buf;
SbString text;
text.sprintf(" (%.1fR,%.1fdeg)", radius, angle * 180 / M_PI);
setPositionText(onSketchPos, text);
sketchgui->drawEdit(EditCurve);
@ -941,12 +1078,11 @@ public:
EditCurve[i] = Base::Vector2D(CenterPoint.fX + dx, CenterPoint.fY + dy);
}
// Display radius and end angle
// Display radius and arc angle
float radius = (onSketchPos - EditCurve[0]).Length();
char buf[40];
sprintf( buf, " (R%.1f,%.1f)", radius, arcAngle * 180 / M_PI);
std::string text = buf;
SbString text;
text.sprintf(" (%.1fR,%.1fdeg)", radius, arcAngle * 180 / M_PI);
setPositionText(onSketchPos, text);
sketchgui->drawEdit(EditCurve);
@ -1154,9 +1290,8 @@ public:
// Display radius for user
float radius = (onSketchPos - EditCurve[0]).Length();
char buf[40];
sprintf( buf, "R%.1f", radius);
std::string text = buf;
SbString text;
text.sprintf(" (%.1fR)", radius);
setPositionText(onSketchPos, text);
sketchgui->drawEdit(EditCurve);

View File

@ -381,7 +381,7 @@ void DrawSketchHandler::renderSuggestConstraintsCursor(std::vector<AutoConstrain
applyCursor(newCursor);
}
void DrawSketchHandler::setPositionText(const Base::Vector2D &Pos, const std::string &text)
void DrawSketchHandler::setPositionText(const Base::Vector2D &Pos, const SbString &text)
{
sketchgui->setPositionText(Pos, text);
}

View File

@ -89,7 +89,7 @@ public:
void createAutoConstraints(const std::vector<AutoConstraint> &autoConstrs,
int geoId, Sketcher::PointPos pointPos=Sketcher::none);
void setPositionText(const Base::Vector2D &Pos, const std::string &text);
void setPositionText(const Base::Vector2D &Pos, const SbString &text);
void setPositionText(const Base::Vector2D &Pos);
void resetPositionText(void);
void renderSuggestConstraintsCursor(std::vector<AutoConstraint> &suggestedConstraints);

View File

@ -42,7 +42,6 @@ TaskDlgEditSketch::TaskDlgEditSketch(ViewProviderSketch *sketchView)
: TaskDialog(),sketchView(sketchView)
{
assert(sketchView);
documentName = sketchView->getObject()->getDocument()->getName();
Constraints = new TaskSketcherConstrains(sketchView);
General = new TaskSketcherGeneral(sketchView);
Messages = new TaskSketcherMessages(sketchView);
@ -77,7 +76,7 @@ bool TaskDlgEditSketch::accept()
bool TaskDlgEditSketch::reject()
{
std::string document = documentName; // needed because resetEdit() deletes this instance
std::string document = getDocumentName(); // needed because resetEdit() deletes this instance
Gui::Command::doCommand(Gui::Command::Gui,"Gui.getDocument('%s').resetEdit()", document.c_str());
Gui::Command::doCommand(Gui::Command::Doc,"App.getDocument('%s').recompute()", document.c_str());

View File

@ -1005,55 +1005,55 @@ void ViewProviderSketch::moveConstraint(int constNum, const Base::Vector2D &toPo
draw(true);
}
bool ViewProviderSketch::isConstraintAtPosition(const Base::Vector3d &constrPos, const SoNode *constraint)
Base::Vector3d ViewProviderSketch::seekConstraintPosition(const Base::Vector3d &origPos,
const Base::Vector3d &norm,
const Base::Vector3d &dir, float step,
const SoNode *constraint)
{
assert(edit);
Gui::MDIView *mdi = Gui::Application::Instance->activeDocument()->getActiveView();
Gui::View3DInventorViewer *viewer = static_cast<Gui::View3DInventor *>(mdi)->getViewer();
SoRayPickAction rp(viewer->getViewportRegion());
rp.setRadius(0.1f);
rp.setPickAll(true);
rp.setRay(SbVec3f(constrPos.x, constrPos.y, -1.f), SbVec3f(0, 0, 1) );
//problem
rp.apply(edit->constrGroup); // We could narrow it down to just the SoGroup containing the constraints
// returns a copy of the point
SoPickedPoint *pp = rp.getPickedPoint();
const SoPickedPointList ppl = rp.getPickedPointList();
float scaled_step = step * getScaleFactor();
if(ppl.getLength() > 1)
return true;
if (pp) {
SoPath *path = pp->getPath();
int length = path->getLength();
SoNode *tailFather1 = path->getNode(length-2);
SoNode *tailFather2 = path->getNode(length-3);
// checking if a constraint is the same as the one selected
if (tailFather1 == constraint || tailFather2 == constraint) {
return false;
} else {
return true;
}
} else {
return false;
}
}
Base::Vector3d ViewProviderSketch::seekConstraintPosition(const Base::Vector3d &suggestedPos,
const Base::Vector3d &dir, float step,
const SoNode *constraint)
{
int multiplier = 0;
Base::Vector3d freePos;
do {
Base::Vector3d relPos, freePos;
bool isConstraintAtPosition = true;
while (isConstraintAtPosition && multiplier < 10) {
// Calculate new position of constraint
freePos = suggestedPos + (dir * (multiplier * step));
multiplier++; // Increment the multiplier
relPos = norm * 0.5f + dir * multiplier;
freePos = origPos + relPos * scaled_step;
rp.setRadius(0.1f);
rp.setPickAll(true);
rp.setRay(SbVec3f(freePos.x, freePos.y, -1.f), SbVec3f(0, 0, 1) );
//problem
rp.apply(edit->constrGroup); // We could narrow it down to just the SoGroup containing the constraints
// returns a copy of the point
SoPickedPoint *pp = rp.getPickedPoint();
const SoPickedPointList ppl = rp.getPickedPointList();
if (ppl.getLength() <= 1 && pp) {
SoPath *path = pp->getPath();
int length = path->getLength();
SoNode *tailFather1 = path->getNode(length-2);
SoNode *tailFather2 = path->getNode(length-3);
// checking if a constraint is the same as the one selected
if (tailFather1 == constraint || tailFather2 == constraint)
isConstraintAtPosition = false;
} else
isConstraintAtPosition = false;
multiplier *= -1; // search in both sides
if (multiplier >= 0)
multiplier++; // Increment the multiplier
}
while (isConstraintAtPosition(freePos, constraint));
return freePos;
if (multiplier == 10)
relPos = norm * 0.5f; // no free position found
return relPos * step;
}
bool ViewProviderSketch::isSelectable(void) const
@ -1716,7 +1716,7 @@ void ViewProviderSketch::draw(bool temp)
Points.push_back(start);
Points.push_back(end);
}
else if ((*it)->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { // add a circle
else if ((*it)->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { // add a bspline
const Part::GeomBSplineCurve *spline = dynamic_cast<const Part::GeomBSplineCurve *>(*it);
Handle_Geom_BSplineCurve curve = Handle_Geom_BSplineCurve::DownCast(spline->handle());
@ -1842,19 +1842,12 @@ Restart:
Base::Vector3d dir = (lineSeg->getEndPoint()-lineSeg->getStartPoint()).Normalize();
Base::Vector3d norm(-dir.y,dir.x,0);
float scale = dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->getScaleFactor();
Base::Vector3d constrPos = midpos + (norm * 2.5 * scale);
constrPos = seekConstraintPosition(constrPos, dir, 2.5 * scale, edit->constrGroup->getChild(i));
// Translate the Icon based on calculated position
Base::Vector3d relPos = constrPos - midpos; // Relative Position of Icons to Midpoint
relPos = relPos / scale; // Must Divide by Scale Factor
Base::Vector3d relpos = seekConstraintPosition(midpos, norm, dir, 2.5, edit->constrGroup->getChild(i));
dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->abPos = SbVec3f(midpos.x, midpos.y, zConstr); //Absolute Reference
//Reference Position that is scaled according to zoom
dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->translation = SbVec3f(relPos.x, relPos.y, 0);
dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->translation = SbVec3f(relpos.x, relpos.y, 0);
}
break;
@ -1921,25 +1914,16 @@ Restart:
dir1 = Base::Vector3d(1,0,0);
}
// Get Current Scale Factor
float scale = dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->getScaleFactor();
Base::Vector3d constrPos1 = midpos1 + (norm1 * 2.5 * scale);
constrPos1 = seekConstraintPosition(constrPos1, dir1, scale * 2.5, edit->constrGroup->getChild(i));
// Translate the Icon based on calculated position
Base::Vector3d relPos1 = (constrPos1 - midpos1) / scale ; // Relative Position of Icons to Midpoint1
Base::Vector3d relpos1 = seekConstraintPosition(midpos1, norm1, dir1, 2.5, edit->constrGroup->getChild(i));
dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->abPos = SbVec3f(midpos1.x, midpos1.y, zConstr);
dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->translation = SbVec3f(relPos1.x, relPos1.y, 0);
dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->translation = SbVec3f(relpos1.x, relpos1.y, 0);
if (Constr->FirstPos == Sketcher::none) {
Base::Vector3d constrPos2 = midpos2 + (norm2 * 2.5 * scale);
constrPos2 = seekConstraintPosition(constrPos2, dir2, 2.5 * scale, edit->constrGroup->getChild(i));
Base::Vector3d relpos2 = seekConstraintPosition(midpos2, norm2, dir2, 2.5, edit->constrGroup->getChild(i));
Base::Vector3d relPos2 = (constrPos2 - midpos2) / scale ; // Relative Position of Icons to Midpoint2
Base::Vector3d secondPos = midpos2 - midpos1;
dynamic_cast<SoZoomTranslation *>(sep->getChild(3))->abPos = SbVec3f(secondPos.x, secondPos.y, zConstr);
dynamic_cast<SoZoomTranslation *>(sep->getChild(3))->translation = SbVec3f(relPos2.x -relPos1.x, relPos2.y -relPos1.y, 0);
dynamic_cast<SoZoomTranslation *>(sep->getChild(3))->translation = SbVec3f(relpos2.x -relpos1.x, relpos2.y -relpos1.y, 0);
}
}
@ -2012,32 +1996,19 @@ Restart:
norm2 = Base::Vector3d(-dir2.y,dir2.x,0.);
}
// Get Current Scale Factor
float scale = dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->getScaleFactor();
Base::Vector3d constrPos1 = midpos1 + (norm1 * 2.5 * scale);
constrPos1 = seekConstraintPosition(constrPos1, dir1, scale * 2.5, edit->constrGroup->getChild(i));
Base::Vector3d constrPos2 = midpos2 + (norm2 * 2.5 * scale);
constrPos2 = seekConstraintPosition(constrPos2, dir2, 2.5 * scale, edit->constrGroup->getChild(i));
// Translate the Icon based on calculated position
Base::Vector3d relPos1 = constrPos1 - midpos1 ; // Relative Position of Icons to Midpoint1
Base::Vector3d relPos2 = constrPos2 - midpos2 ; // Relative Position of Icons to Midpoint2
relPos1 = relPos1 / scale;
relPos2 = relPos2 / scale;
Base::Vector3d relpos1 = seekConstraintPosition(midpos1, norm1, dir1, 2.5, edit->constrGroup->getChild(i));
Base::Vector3d relpos2 = seekConstraintPosition(midpos2, norm2, dir2, 2.5, edit->constrGroup->getChild(i));
dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->abPos = SbVec3f(midpos1.x, midpos1.y, zConstr); //Absolute Reference
//Reference Position that is scaled according to zoom
dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->translation = SbVec3f(relPos1.x, relPos1.y, 0);
dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->translation = SbVec3f(relpos1.x, relpos1.y, 0);
Base::Vector3d secondPos = midpos2 - midpos1;
dynamic_cast<SoZoomTranslation *>(sep->getChild(3))->abPos = SbVec3f(secondPos.x, secondPos.y, zConstr); //Absolute Reference
//Reference Position that is scaled according to zoom
dynamic_cast<SoZoomTranslation *>(sep->getChild(3))->translation = SbVec3f(relPos2.x -relPos1.x, relPos2.y -relPos1.y, 0);
dynamic_cast<SoZoomTranslation *>(sep->getChild(3))->translation = SbVec3f(relpos2.x - relpos1.x, relpos2.y -relpos1.y, 0);
}
break;
@ -2148,32 +2119,19 @@ Restart:
Base::Vector3d norm1 = Base::Vector3d(-dir1.y,dir1.x,0.f);
Base::Vector3d norm2 = Base::Vector3d(-dir2.y,dir2.x,0.f);
// Get Current Scale Factor
float scale = dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->getScaleFactor();
Base::Vector3d constrPos1 = midpos1 + (norm1 * 2.5 * scale);
constrPos1 = seekConstraintPosition(constrPos1, dir1, 2.5 * scale, edit->constrGroup->getChild(i));
Base::Vector3d constrPos2 = midpos2 + (norm2 * 2.5 * scale);
constrPos2 = seekConstraintPosition(constrPos2, dir2, 2.5 * scale, edit->constrGroup->getChild(i));
// Translate the Icon based on calculated position
Base::Vector3d relPos1 = constrPos1 - midpos1 ; // Relative Position of Icons to Midpoint1
Base::Vector3d relPos2 = constrPos2 - midpos2 ; // Relative Position of Icons to Midpoint2
relPos1 = relPos1 / scale;
relPos2 = relPos2 / scale;
Base::Vector3d relpos1 = seekConstraintPosition(midpos1, norm1, dir1, 2.5, edit->constrGroup->getChild(i));
Base::Vector3d relpos2 = seekConstraintPosition(midpos2, norm2, dir2, 2.5, edit->constrGroup->getChild(i));
dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->abPos = SbVec3f(midpos1.x, midpos1.y, zConstr); //Absolute Reference
//Reference Position that is scaled according to zoom
dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->translation = SbVec3f(relPos1.x, relPos1.y, 0);
dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->translation = SbVec3f(relpos1.x, relpos1.y, 0);
Base::Vector3d secondPos = midpos2 - midpos1;
dynamic_cast<SoZoomTranslation *>(sep->getChild(3))->abPos = SbVec3f(secondPos.x, secondPos.y, zConstr); //Absolute Reference
//Reference Position that is scaled according to zoom
dynamic_cast<SoZoomTranslation *>(sep->getChild(3))->translation = SbVec3f(relPos2.x -relPos1.x, relPos2.y -relPos1.y, 0);
dynamic_cast<SoZoomTranslation *>(sep->getChild(3))->translation = SbVec3f(relpos2.x -relpos1.x, relpos2.y -relpos1.y, 0);
break;
}
@ -2777,9 +2735,14 @@ void ViewProviderSketch::createEditInventorNodes(void)
edit->EditCurveSet = new SoLineSet;
edit->EditRoot->addChild(edit->EditCurveSet);
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
float transparency;
SbColor cursorTextColor(0,0,1);
cursorTextColor.setPackedValue((uint32_t)hGrp->GetUnsigned("CursorTextColor", cursorTextColor.getPackedValue()), transparency);
// stuff for the edit coordinates ++++++++++++++++++++++++++++++++++++++
SoMaterial *EditMaterials = new SoMaterial;
EditMaterials->diffuseColor = SbColor(0,0,1);
EditMaterials->diffuseColor = cursorTextColor;
edit->EditRoot->addChild(EditMaterials);
SoSeparator *Coordsep = new SoSeparator();
@ -2867,17 +2830,17 @@ void ViewProviderSketch::unsetEditViewer(Gui::View3DInventorViewer* viewer)
static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionRole.setValue(TRUE);
}
void ViewProviderSketch::setPositionText(const Base::Vector2D &Pos, const std::string &text)
void ViewProviderSketch::setPositionText(const Base::Vector2D &Pos, const SbString &text)
{
edit->textX->string = text.c_str();
edit->textX->string = text;
edit->textPos->translation = SbVec3f(Pos.fX,Pos.fY,zText);
}
void ViewProviderSketch::setPositionText(const Base::Vector2D &Pos)
{
char buf[40];
sprintf( buf, " (%.1f,%.1f)", Pos.fX,Pos.fY );
edit->textX->string = buf;
SbString text;
text.sprintf(" (%.1f,%.1f)", Pos.fX, Pos.fY);
edit->textX->string = text;
edit->textPos->translation = SbVec3f(Pos.fX,Pos.fY,zText);
}

View File

@ -43,6 +43,7 @@ class SoMarkerSet;
class SoText2;
class SoTranslation;
class SbString;
class SbTime;
struct EditData;
@ -137,10 +138,9 @@ public:
/// moves a selected constraint
void moveConstraint(int constNum, const Base::Vector2D &toPos);
/// checks if there is a constraint object at position vector
bool isConstraintAtPosition(const Base::Vector3d &constrPos, const SoNode *constraint);
/// finds a free position for placing a constraint icon
Base::Vector3d seekConstraintPosition(const Base::Vector3d &suggestedPos,
Base::Vector3d seekConstraintPosition(const Base::Vector3d &origPos,
const Base::Vector3d &norm,
const Base::Vector3d &dir, float step,
const SoNode *constraint);
@ -200,7 +200,7 @@ protected:
/// build up the visual of the constraints
void rebuildConstraintsVisual(void);
void setPositionText(const Base::Vector2D &Pos, const std::string &txt);
void setPositionText(const Base::Vector2D &Pos, const SbString &txt);
void setPositionText(const Base::Vector2D &Pos);
void resetPositionText(void);

View File

@ -114,7 +114,7 @@ BrowserView::BrowserView(QWidget* parent)
connect(view, SIGNAL(loadProgress(int)),
this, SLOT(onLoadProgress(int)));
connect(view, SIGNAL(loadFinished(bool)),
this, SLOT(onLoadFinished()));
this, SLOT(onLoadFinished(bool)));
connect(view, SIGNAL(linkClicked(const QUrl &)),
this, SLOT(onLinkClicked(const QUrl &)));
connect(view->page(), SIGNAL(downloadRequested(const QNetworkRequest &)),
@ -242,12 +242,14 @@ void BrowserView::onLoadProgress(int step)
bar->setValue(step);
}
void BrowserView::onLoadFinished()
void BrowserView::onLoadFinished(bool ok)
{
QProgressBar* bar = Sequencer::instance()->getProgressBar();
bar->setValue(100);
bar->hide();
getMainWindow()->statusBar()->showMessage(QString());
if (ok) {
QProgressBar* bar = Sequencer::instance()->getProgressBar();
bar->setValue(100);
bar->hide();
getMainWindow()->statusBar()->showMessage(QString());
}
isLoading = false;
}

View File

@ -92,10 +92,10 @@ public:
protected Q_SLOTS:
void onLoadStarted();
void onLoadProgress(int);
void onLoadFinished();
void onLinkClicked ( const QUrl & url ) ;
void onLoadFinished(bool);
void onLinkClicked (const QUrl& url);
bool chckHostAllowed(const QString& host);
void onDownloadRequested(const QNetworkRequest & request);
void onDownloadRequested(const QNetworkRequest& request);
private:
WebView* view;