Created FEM constraint document object

This commit is contained in:
jrheinlaender 2013-02-07 11:09:43 +04:30
parent 1412805c0f
commit 918291f81f
13 changed files with 2221 additions and 11 deletions

View File

@ -41,6 +41,7 @@
#include "FemSetNodesObject.h"
#include "HypothesisPy.h"
#include "FemConstraint.h"
extern struct PyMethodDef Fem_methods[];
@ -115,6 +116,7 @@ void AppFemExport initFem()
Fem::FemSetGeometryObject ::init();
Fem::FemSetNodesObject ::init();
Fem::Constraint ::init();
}
} // extern "C"

View File

@ -64,6 +64,8 @@ SET(Fem_SRCS
FemMesh.h
FemMeshProperty.cpp
FemMeshProperty.h
FemConstraint.cpp
FemConstraint.h
${Mod_SRCS}
${Python_SRCS}
)

View File

@ -0,0 +1,70 @@
/***************************************************************************
* Copyright (c) 2013 Jan Rheinländer <jrheinlaender[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., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include "FemConstraint.h"
#include <Base/Console.h>
using namespace Fem;
const char* Constraint::TypeEnums[]= {"Force on geometry","Fixed",
"Bearing (radial free)", "Bearing (radial fixed)",
"Pulley", "Gear (straight toothed)", NULL};
PROPERTY_SOURCE(Fem::Constraint, App::DocumentObject);
Constraint::Constraint()
{
ADD_PROPERTY(Type,((long)0));
Type.setEnums(TypeEnums);
ADD_PROPERTY(Force,(0.0));
ADD_PROPERTY_TYPE(References,(0,0),"Constraint",(App::PropertyType)(App::Prop_None),"Elements where the constraint is applied");
ADD_PROPERTY_TYPE(Direction,(0),"Constraint",(App::PropertyType)(App::Prop_None),"Element giving direction of constraint");
ADD_PROPERTY(Reversed,(0));
ADD_PROPERTY(Distance,(0.0));
ADD_PROPERTY_TYPE(Location,(0),"Constraint",(App::PropertyType)(App::Prop_None),"Element giving location where constraint is applied");
ADD_PROPERTY(Diameter,(0.0));
ADD_PROPERTY(OtherDiameter,(0.0));
ADD_PROPERTY(CenterDistance,(0.0));
}
Constraint::~Constraint()
{
}
App::DocumentObjectExecReturn *Constraint::execute(void)
{
// Ensure that the constraint symbols follow the changed geometry
References.touch();
return DocumentObject::StdReturn;
}
void Constraint::onChanged(const App::Property* prop)
{
DocumentObject::onChanged(prop);
}

View File

@ -0,0 +1,71 @@
/***************************************************************************
* Copyright (c) 2013 Jan Rheinländer <jrheinlaender[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., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef FEM_CONSTRAINT_H
#define FEM_CONSTRAINT_H
#include <App/DocumentObject.h>
#include <App/PropertyLinks.h>
namespace Fem
{
class AppFemExport Constraint : public App::DocumentObject
{
PROPERTY_HEADER(Fem::Constraint);
public:
/// Constructor
Constraint(void);
virtual ~Constraint();
App::PropertyEnumeration Type;
App::PropertyLinkSubList References;
App::PropertyFloat Force;
App::PropertyLinkSub Direction;
App::PropertyBool Reversed;
App::PropertyLinkSub Location;
App::PropertyFloat Distance;
App::PropertyFloat Diameter;
App::PropertyFloat OtherDiameter;
App::PropertyFloat CenterDistance;
/// recalculate the object
virtual App::DocumentObjectExecReturn *execute(void);
/// returns the type name of the ViewProvider
const char* getViewProviderName(void) const {
return "FemGui::ViewProviderFemConstraint";
}
protected:
virtual void onChanged(const App::Property* prop);
private:
static const char* TypeEnums[];
};
} //namespace Fem
#endif // FEM_CONSTRAINT_H

View File

@ -34,6 +34,7 @@
#include "ViewProviderSetElements.h"
#include "ViewProviderSetFaces.h"
#include "ViewProviderSetGeometry.h"
#include "ViewProviderFemConstraint.h"
#include "Workbench.h"
//#include "resources/qrc_Fem.cpp"
@ -63,16 +64,17 @@ void FemGuiExport initFemGui()
(void) Py_InitModule("FemGui", FemGui_Import_methods); /* mod name, table ptr */
Base::Console().Log("Loading GUI of Fem module... done\n");
// instanciating the commands
// instantiating the commands
CreateFemCommands();
// addition objects
FemGui::Workbench ::init();
FemGui::ViewProviderFemMesh ::init();
FemGui::ViewProviderSetNodes ::init();
FemGui::ViewProviderSetElements ::init();
FemGui::ViewProviderSetFaces ::init();
FemGui::ViewProviderSetGeometry ::init();
FemGui::ViewProviderFemMesh ::init();
FemGui::ViewProviderSetNodes ::init();
FemGui::ViewProviderSetElements ::init();
FemGui::ViewProviderSetFaces ::init();
FemGui::ViewProviderSetGeometry ::init();
FemGui::ViewProviderFemConstraint ::init();
// add resources and reloads the translators
loadFemResource();

View File

@ -34,6 +34,7 @@ set(FemGui_MOC_HDRS
TaskObjectName.h
TaskCreateNodeSet.h
TaskDlgCreateNodeSet.h
TaskFemConstraint.h
)
fc_wrap_cpp(FemGui_MOC_SRCS ${FemGui_MOC_HDRS})
SOURCE_GROUP("Moc" FILES ${FemGui_MOC_SRCS})
@ -42,9 +43,21 @@ set(FemGui_UIC_SRCS
Hypothesis.ui
TaskCreateNodeSet.ui
TaskObjectName.ui
TaskFemConstraint.ui
)
qt4_wrap_ui(FemGui_UIC_HDRS ${FemGui_UIC_SRCS})
SET(FemGui_DLG_SRCS
${FemGui_UIC_HDRS}
Hypothesis.ui
Hypothesis.cpp
Hypothesis.h
TaskFemConstraint.ui
TaskFemConstraint.cpp
TaskFemConstraint.h
)
SOURCE_GROUP("Dialogs" FILES ${FemGui_DLG_SRCS})
qt4_add_resources(FemResource_SRCS Resources/Fem.qrc)
SOURCE_GROUP("Resources" FILES ${FemResource_SRCS})
@ -62,14 +75,16 @@ SET(FemGui_SRCS_ViewProvider
ViewProviderSetGeometry.h
FemSelectionGate.cpp
FemSelectionGate.h
ViewProviderFemConstraint.cpp
ViewProviderFemConstraint.h
)
SOURCE_GROUP("ViewProvider" FILES ${FemGui_SRCS_ViewProvider})
SET(FemGui_SRCS_TaskBoxes
TaskObjectName.ui
TaskObjectName.ui
TaskObjectName.cpp
TaskObjectName.h
TaskCreateNodeSet.ui
TaskCreateNodeSet.ui
TaskCreateNodeSet.cpp
TaskCreateNodeSet.h
)
@ -81,6 +96,9 @@ SET(FemGui_SRCS_TaskDlg
Hypothesis.ui
Hypothesis.cpp
Hypothesis.h
TaskFemConstraint.ui
TaskFemConstraint.cpp
TaskFemConstraint.h
)
SOURCE_GROUP("Task_Dialogs" FILES ${FemGui_SRCS_TaskDlg})

View File

@ -52,8 +52,10 @@
#include <Mod/Fem/App/FemMeshObject.h>
#include <Mod/Fem/App/FemSetNodesObject.h>
#include <strstream>
#include <Mod/Fem/App/FemConstraint.h>
#include "Hypothesis.h"
#include "TaskFemConstraint.h"
using namespace std;
@ -85,6 +87,38 @@ bool CmdFemCreateFromShape::isActive(void)
return Gui::Selection().countObjectsOfType(type) > 0;
}
DEF_STD_CMD_A(CmdFemConstraint);
CmdFemConstraint::CmdFemConstraint()
: Command("Fem_Constraint")
{
sAppModule = "Fem";
sGroup = QT_TR_NOOP("Fem");
sMenuText = QT_TR_NOOP("Create FEM constraint");
sToolTipText = QT_TR_NOOP("Create FEM constraint");
sWhatsThis = sToolTipText;
sStatusTip = sToolTipText;
sPixmap = "Fem_Constraint";
}
void CmdFemConstraint::activated(int iMsg)
{
std::string FeatName = getUniqueObjectName("FemConstraint");
openCommand("Make FEM constraint");
doCommand(Doc,"App.activeDocument().addObject(\"Fem::Constraint\",\"%s\")",FeatName.c_str());
doCommand(Doc,"App.activeDocument().%s.Force = 0.0",FeatName.c_str());
updateActive();
Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(App::GetApplication().getActiveDocument()->getActiveObject());
doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str());
}
bool CmdFemConstraint::isActive(void)
{
return hasActiveDocument();
}
// #####################################################################################################
@ -281,4 +315,5 @@ void CreateFemCommands(void)
rcCmdMgr.addCommand(new CmdFemCreateFromShape());
rcCmdMgr.addCommand(new CmdFemCreateNodesSet());
rcCmdMgr.addCommand(new CmdFemDefineNodesSet());
rcCmdMgr.addCommand(new CmdFemConstraint());
}

View File

@ -0,0 +1,752 @@
/***************************************************************************
* Copyright (c) 2013 Jan Rheinländer <jrheinlaender@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., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <sstream>
# include <QRegExp>
# include <QTextStream>
# include <QMessageBox>
# include <Precision.hxx>
# include <TopoDS.hxx>
# include <BRepAdaptor_Surface.hxx>
# include <Geom_Plane.hxx>
# include <gp_Pln.hxx>
# include <gp_Ax1.hxx>
# include <BRepAdaptor_Curve.hxx>
# include <Geom_Line.hxx>
# include <gp_Lin.hxx>
#endif
#include "ui_TaskFemConstraint.h"
#include "TaskFemConstraint.h"
#include <App/Application.h>
#include <App/Document.h>
#include <App/PropertyGeo.h>
#include <Gui/Application.h>
#include <Gui/Document.h>
#include <Gui/BitmapFactory.h>
#include <Gui/ViewProvider.h>
#include <Gui/WaitCursor.h>
#include <Gui/Selection.h>
#include <Gui/Command.h>
#include <Mod/Fem/App/FemConstraint.h>
#include <Mod/Part/App/PartFeature.h>
#include <Base/Console.h>
using namespace FemGui;
using namespace Gui;
/* TRANSLATOR FemGui::TaskFemConstraint */
const QString makeRefText(const App::DocumentObject* obj, const std::string& subName)
{
return QString::fromUtf8((std::string(obj->getNameInDocument()) + ":" + subName).c_str());
}
TaskFemConstraint::TaskFemConstraint(ViewProviderFemConstraint *ConstraintView,QWidget *parent)
: TaskBox(Gui::BitmapFactory().pixmap("Fem_Constraint"),tr("FEM constraint parameters"),true, parent),ConstraintView(ConstraintView)
{
// we need a separate container widget to add all controls to
proxy = new QWidget(this);
ui = new Ui_TaskFemConstraint();
ui->setupUi(proxy);
QMetaObject::connectSlotsByName(this);
// Create a context menu for the listview of the references
QAction* action = new QAction(tr("Delete"), ui->listReferences);
action->connect(action, SIGNAL(triggered()),
this, SLOT(onReferenceDeleted()));
ui->listReferences->addAction(action);
ui->listReferences->setContextMenuPolicy(Qt::ActionsContextMenu);
connect(ui->comboType, SIGNAL(currentIndexChanged(int)),
this, SLOT(onTypeChanged(int)));
connect(ui->spinForce, SIGNAL(valueChanged(double)),
this, SLOT(onForceChanged(double)));
connect(ui->buttonReference, SIGNAL(pressed()),
this, SLOT(onButtonReference()));
connect(ui->buttonDirection, SIGNAL(pressed()),
this, SLOT(onButtonDirection()));
connect(ui->checkReverse, SIGNAL(toggled(bool)),
this, SLOT(onCheckReverse(bool)));
connect(ui->buttonLocation, SIGNAL(pressed()),
this, SLOT(onButtonLocation()));
connect(ui->spinDistance, SIGNAL(valueChanged(double)),
this, SLOT(onDistanceChanged(double)));
connect(ui->spinDiameter, SIGNAL(valueChanged(double)),
this, SLOT(onDiameterChanged(double)));
connect(ui->spinOtherDia, SIGNAL(valueChanged(double)),
this, SLOT(onOtherDiameterChanged(double)));
connect(ui->spinCenterDistance, SIGNAL(valueChanged(double)),
this, SLOT(onCenterDistanceChanged(double)));
this->groupLayout()->addWidget(proxy);
// Temporarily prevent unnecessary feature recomputes
ui->comboType->blockSignals(true);
ui->spinForce->blockSignals(true);
ui->listReferences->blockSignals(true);
ui->buttonReference->blockSignals(true);
ui->buttonDirection->blockSignals(true);
ui->checkReverse->blockSignals(true);
ui->buttonLocation->blockSignals(true);
ui->spinDistance->blockSignals(true);
ui->spinDiameter->blockSignals(true);
ui->spinOtherDia->blockSignals(true);
ui->spinCenterDistance->blockSignals(true);
// Get the feature data
Fem::Constraint* pcConstraint = static_cast<Fem::Constraint*>(ConstraintView->getObject());
int index = pcConstraint->Type.getValue();
double f = pcConstraint->Force.getValue();
std::vector<App::DocumentObject*> Objects = pcConstraint->References.getValues();
std::vector<std::string> SubElements = pcConstraint->References.getSubValues();
std::vector<std::string> dirStrings = pcConstraint->Direction.getSubValues();
QString dir;
if (!dirStrings.empty())
dir = makeRefText(pcConstraint->Direction.getValue(), dirStrings.front());
bool reversed = pcConstraint->Reversed.getValue();
std::vector<std::string> locStrings = pcConstraint->Location.getSubValues();
QString loc;
if (!locStrings.empty())
loc = makeRefText(pcConstraint->Location.getValue(), locStrings.front());
double d = pcConstraint->Distance.getValue();
double dia = pcConstraint->Diameter.getValue();
double otherdia = pcConstraint->OtherDiameter.getValue();
double centerdist = pcConstraint->CenterDistance.getValue();
// Fill data into dialog elements
ui->comboType->clear();
ui->comboType->insertItem(0, tr("Force on geometry"));
ui->comboType->insertItem(1, tr("Fixed"));
ui->comboType->insertItem(2, tr("Bearing (axial free)"));
ui->comboType->insertItem(3, tr("Bearing (axial fixed)"));
ui->comboType->insertItem(4, tr("Pulley"));
ui->comboType->insertItem(5, tr("Gear (straight toothed)"));
ui->comboType->setCurrentIndex(index);
ui->spinForce->setMinimum(0);
ui->spinForce->setMaximum(INT_MAX);
ui->spinForce->setValue(f);
ui->listReferences->clear();
for (int i = 0; i < Objects.size(); i++)
ui->listReferences->addItem(makeRefText(Objects[i], SubElements[i]));
if (Objects.size() > 0)
ui->listReferences->setCurrentRow(0, QItemSelectionModel::ClearAndSelect);
ui->lineDirection->setText(dir.isEmpty() ? tr("") : dir);
ui->checkReverse->setChecked(reversed);
ui->lineDirection->setText(loc.isEmpty() ? tr("") : loc);
ui->spinDistance->setMinimum(INT_MIN);
ui->spinDistance->setMaximum(INT_MAX);
ui->spinDistance->setValue(d);
ui->spinDiameter->setMinimum(0);
ui->spinDiameter->setMaximum(INT_MAX);
ui->spinDiameter->setValue(dia);
ui->spinOtherDia->setMinimum(0);
ui->spinOtherDia->setMaximum(INT_MAX);
ui->spinOtherDia->setValue(otherdia);
ui->spinCenterDistance->setMinimum(0);
ui->spinCenterDistance->setMaximum(INT_MAX);
ui->spinCenterDistance->setValue(centerdist);
// activate and de-activate dialog elements as appropriate
ui->comboType->blockSignals(false);
ui->spinForce->blockSignals(false);
ui->listReferences->blockSignals(false);
ui->buttonReference->blockSignals(false);
ui->buttonDirection->blockSignals(false);
ui->checkReverse->blockSignals(false);
ui->buttonLocation->blockSignals(false);
ui->spinDistance->blockSignals(false);
ui->spinDiameter->blockSignals(false);
ui->spinOtherDia->blockSignals(false);
ui->spinCenterDistance->blockSignals(false);
selectionMode = selref;
updateUI();
}
void TaskFemConstraint::updateUI()
{
if (ui->comboType->currentIndex() == 0) {
ui->labelForce->setVisible(true);
ui->spinForce->setVisible(true);
ui->buttonDirection->setVisible(true);
ui->lineDirection->setVisible(true);
ui->checkReverse->setVisible(true);
ui->buttonLocation->setVisible(false);
ui->lineLocation->setVisible(false);
ui->labelDistance->setVisible(false);
ui->spinDistance->setVisible(false);
ui->labelDiameter->setVisible(false);
ui->spinDiameter->setVisible(false);
ui->labelOtherDia->setVisible(false);
ui->spinOtherDia->setVisible(false);
ui->labelCenterDistance->setVisible(false);
ui->spinCenterDistance->setVisible(false);
} else if (ui->comboType->currentIndex() == 1) {
ui->labelForce->setVisible(false);
ui->spinForce->setVisible(false);
ui->buttonDirection->setVisible(false);
ui->lineDirection->setVisible(false);
ui->checkReverse->setVisible(false);
ui->buttonLocation->setVisible(false);
ui->lineLocation->setVisible(false);
ui->labelDistance->setVisible(false);
ui->spinDistance->setVisible(false);
ui->labelDiameter->setVisible(false);
ui->spinDiameter->setVisible(false);
ui->labelOtherDia->setVisible(false);
ui->spinOtherDia->setVisible(false);
ui->labelCenterDistance->setVisible(false);
ui->spinCenterDistance->setVisible(false);
} else if ((ui->comboType->currentIndex() == 2) || (ui->comboType->currentIndex() == 3)) {
ui->labelForce->setVisible(false);
ui->spinForce->setVisible(false);
ui->buttonDirection->setVisible(false);
ui->lineDirection->setVisible(false);
ui->checkReverse->setVisible(false);
ui->buttonLocation->setVisible(true);
ui->lineLocation->setVisible(true);
ui->labelDistance->setVisible(true);
ui->spinDistance->setVisible(true);
ui->labelDiameter->setVisible(false);
ui->spinDiameter->setVisible(false);
ui->labelOtherDia->setVisible(false);
ui->spinOtherDia->setVisible(false);
ui->labelCenterDistance->setVisible(false);
ui->spinCenterDistance->setVisible(false);
} else if (ui->comboType->currentIndex() == 4) {
ui->labelForce->setVisible(false);
ui->spinForce->setVisible(false);
ui->buttonDirection->setVisible(false);
ui->lineDirection->setVisible(false);
ui->checkReverse->setVisible(false);
ui->buttonLocation->setVisible(true);
ui->lineLocation->setVisible(true);
ui->labelDistance->setVisible(true);
ui->spinDistance->setVisible(true);
ui->labelDiameter->setVisible(true);
ui->spinDiameter->setVisible(true);
ui->labelOtherDia->setVisible(true);
ui->spinOtherDia->setVisible(true);
ui->labelCenterDistance->setVisible(true);
ui->spinCenterDistance->setVisible(true);
} else if (ui->comboType->currentIndex() == 5) {
ui->labelForce->setVisible(false);
ui->spinForce->setVisible(false);
ui->buttonDirection->setVisible(false);
ui->lineDirection->setVisible(false);
ui->checkReverse->setVisible(false);
ui->buttonLocation->setVisible(true);
ui->lineLocation->setVisible(true);
ui->labelDistance->setVisible(true);
ui->spinDistance->setVisible(true);
ui->labelDiameter->setVisible(true);
ui->spinDiameter->setVisible(true);
ui->labelOtherDia->setVisible(true);
ui->spinOtherDia->setVisible(true);
ui->labelCenterDistance->setVisible(false);
ui->spinCenterDistance->setVisible(false);
}
if (ui->listReferences->model()->rowCount() == 0) {
// Go into reference selection mode if no reference has been selected yet
onButtonReference(true);
return;
}
if (ui->comboType->currentIndex() == 0) {
std::string ref = ui->listReferences->item(0)->text().toStdString();
int pos = ref.find_last_of(":");
if (ref.substr(pos+1, 6) == "Vertex")
ui->labelForce->setText(tr("Force [N]"));
else if (ref.substr(pos+1, 4) == "Edge")
ui->labelForce->setText(tr("Force [N/mm]"));
else if (ref.substr(pos+1, 4) == "Face")
ui->labelForce->setText(tr("Force [N/mm²]"));
}
}
void TaskFemConstraint::onSelectionChanged(const Gui::SelectionChanges& msg)
{
if (msg.Type == Gui::SelectionChanges::AddSelection) {
// Don't allow selection in other document
if (strcmp(msg.pDocName, ConstraintView->getObject()->getDocument()->getName()) != 0)
return;
if (!msg.pSubName || msg.pSubName[0] == '\0')
return;
std::string subName(msg.pSubName);
if (selectionMode == selnone)
return;
std::vector<std::string> references(1,subName);
Fem::Constraint* pcConstraint = static_cast<Fem::Constraint*>(ConstraintView->getObject());
App::DocumentObject* obj = ConstraintView->getObject()->getDocument()->getObject(msg.pObjectName);
//if (!obj->getClassTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
// return;
Part::Feature* feat = static_cast<Part::Feature*>(obj);
TopoDS_Shape ref = feat->Shape.getShape().getSubShape(subName.c_str());
if (selectionMode == selref) {
std::vector<App::DocumentObject*> Objects = pcConstraint->References.getValues();
std::vector<std::string> SubElements = pcConstraint->References.getSubValues();
if (pcConstraint->Type.getValue() == 0) {
// Force on geometry elements:
// Ensure we don't have mixed reference types
if (SubElements.size() > 0) {
if (subName.substr(0,4) != SubElements.front().substr(0,4)) {
QMessageBox::warning(this, tr("Selection error"), tr("Mixed shape types are not possible. Use a second constraint instead"));
return;
}
} else {
if ((subName.substr(0,4) != "Face") && (subName.substr(0,4) != "Edge") && (subName.substr(0,6) != "Vertex")) {
QMessageBox::warning(this, tr("Selection error"), tr("Only faces, edges and vertices can be picked"));
return;
}
}
// Avoid duplicates
int pos = 0;
for (; pos < Objects.size(); pos++)
if (obj == Objects[pos])
break;
if (pos != Objects.size())
if (subName == SubElements[pos])
return;
} else if (pcConstraint->Type.getValue() == 1) {
// Fixed
if ((subName.substr(0,4) != "Face") && (subName.substr(0,4) != "Edge") && (subName.substr(0,6) != "Vertex")) {
QMessageBox::warning(this, tr("Selection error"), tr("Mixed shape types are not possible. Use a second constraint instead"));
return;
}
// Avoid duplicates
int pos = 0;
for (; pos < Objects.size(); pos++)
if (obj == Objects[pos])
break;
if (pos != Objects.size())
if (subName == SubElements[pos])
return;
} else if ((pcConstraint->Type.getValue() >= 2) && (pcConstraint->Type.getValue() <= 5)) {
// Bearing, pulley, gear
if (Objects.size() > 0) {
QMessageBox::warning(this, tr("Selection error"), tr("Please use only a single reference for bearing constraint"));
return;
}
// Only cylindrical faces allowed
if (subName.substr(0,4) != "Face") {
QMessageBox::warning(this, tr("Selection error"), tr("Only faces can be picked"));
return;
}
BRepAdaptor_Surface surface(TopoDS::Face(ref));
if (surface.GetType() != GeomAbs_Cylinder) {
QMessageBox::warning(this, tr("Selection error"), tr("Only cylindrical faces can be picked"));
return;
}
} else {
return;
}
// add the new reference
Objects.push_back(obj);
SubElements.push_back(subName);
pcConstraint->References.setValues(Objects,SubElements);
ui->listReferences->addItem(makeRefText(obj, subName));
// Turn off reference selection mode
onButtonReference(false);
} else if ((selectionMode == seldir) || (selectionMode == selloc)) {
if (subName.substr(0,4) == "Face") {
BRepAdaptor_Surface surface(TopoDS::Face(ref));
if (surface.GetType() != GeomAbs_Plane) {
QMessageBox::warning(this, tr("Selection error"), tr("Only planar faces can be picked"));
return;
}
} else if (subName.substr(0,4) == "Edge") {
BRepAdaptor_Curve line(TopoDS::Edge(ref));
if (line.GetType() != GeomAbs_Line) {
QMessageBox::warning(this, tr("Selection error"), tr("Only linear edges can be picked"));
return;
}
} else {
QMessageBox::warning(this, tr("Selection error"), tr("Only faces and edges can be picked"));
return;
}
if (selectionMode == seldir) {
pcConstraint->Direction.setValue(obj, references);
ui->lineDirection->setText(makeRefText(obj, subName));
// Turn off direction selection mode
onButtonDirection(false);
} else {
pcConstraint->Location.setValue(obj, references);
ui->lineLocation->setText(makeRefText(obj, subName));
// Turn off direction selection mode
onButtonLocation(false);
}
}
updateUI();
}
}
void TaskFemConstraint::onTypeChanged(int index)
{
Fem::Constraint* pcConstraint = static_cast<Fem::Constraint*>(ConstraintView->getObject());
int oldType = pcConstraint->Type.getValue();
pcConstraint->Type.setValue(index);
if (((oldType == 2) && (index == 3)) || ((oldType == 3) && (index == 2))) {
pcConstraint->References.touch(); // Update visual
updateUI();
} else {
// Clear all references if the old and new type mismatch
std::vector<App::DocumentObject*> Objects = pcConstraint->References.getValues();
std::vector<std::string> SubElements = pcConstraint->References.getSubValues();
Objects.clear();
SubElements.clear();
pcConstraint->References.setValues(Objects, SubElements);
ui->listReferences->clear(); //model()->removeRows(0, ui->listReferences->model()->rowCount());
updateUI();
}
}
void TaskFemConstraint::onForceChanged(double f)
{
Fem::Constraint* pcConstraint = static_cast<Fem::Constraint*>(ConstraintView->getObject());
pcConstraint->Force.setValue((float)f);
}
void TaskFemConstraint::onDistanceChanged(double f)
{
Fem::Constraint* pcConstraint = static_cast<Fem::Constraint*>(ConstraintView->getObject());
pcConstraint->Distance.setValue((float)f);
}
void TaskFemConstraint::onDiameterChanged(double f)
{
Fem::Constraint* pcConstraint = static_cast<Fem::Constraint*>(ConstraintView->getObject());
pcConstraint->Diameter.setValue((float)f);
}
void TaskFemConstraint::onOtherDiameterChanged(double f)
{
Fem::Constraint* pcConstraint = static_cast<Fem::Constraint*>(ConstraintView->getObject());
pcConstraint->OtherDiameter.setValue((float)f);
}
void TaskFemConstraint::onCenterDistanceChanged(double d)
{
Fem::Constraint* pcConstraint = static_cast<Fem::Constraint*>(ConstraintView->getObject());
pcConstraint->CenterDistance.setValue((float)d);
}
void TaskFemConstraint::onButtonReference(const bool pressed) {
if (pressed)
selectionMode = selref;
else
selectionMode = selnone;
ui->buttonReference->setChecked(pressed);
Gui::Selection().clearSelection();
}
void TaskFemConstraint::onReferenceDeleted() {
int row = ui->listReferences->currentIndex().row();
Fem::Constraint* pcConstraint = static_cast<Fem::Constraint*>(ConstraintView->getObject());
std::vector<App::DocumentObject*> Objects = pcConstraint->References.getValues();
std::vector<std::string> SubElements = pcConstraint->References.getSubValues();
Objects.erase(Objects.begin() + row);
SubElements.erase(SubElements.begin() + row);
pcConstraint->References.setValues(Objects, SubElements);
ui->listReferences->model()->removeRow(row);
ui->listReferences->setCurrentRow(0, QItemSelectionModel::ClearAndSelect);
}
void TaskFemConstraint::onButtonDirection(const bool pressed) {
if (pressed) {
selectionMode = seldir;
} else {
selectionMode = selnone;
}
ui->buttonDirection->setChecked(pressed);
Gui::Selection().clearSelection();
}
void TaskFemConstraint::onButtonLocation(const bool pressed) {
if (pressed) {
selectionMode = selloc;
} else {
selectionMode = selnone;
}
ui->buttonLocation->setChecked(pressed);
Gui::Selection().clearSelection();
}
void TaskFemConstraint::onCheckReverse(const bool pressed)
{
Fem::Constraint* pcConstraint = static_cast<Fem::Constraint*>(ConstraintView->getObject());
pcConstraint->Reversed.setValue(pressed);
}
int TaskFemConstraint::getType(void) const
{
return ui->comboType->currentIndex();
}
double TaskFemConstraint::getForce(void) const
{
return ui->spinForce->value();
}
double TaskFemConstraint::getDistance(void) const
{
return ui->spinDistance->value();
}
double TaskFemConstraint::getDiameter(void) const
{
return ui->spinDiameter->value();
}
double TaskFemConstraint::getOtherDiameter(void) const
{
return ui->spinOtherDia->value();
}
double TaskFemConstraint::getCenterDistance(void) const
{
return ui->spinCenterDistance->value();
}
const std::string TaskFemConstraint::getReferences(void) const
{
int rows = ui->listReferences->model()->rowCount();
if (rows == 0)
return "";
std::string result;
for (int r = 0; r < rows; r++) {
std::string item = ui->listReferences->item(r)->text().toStdString();
int pos = item.find_last_of(":");
std::string objStr = "App.ActiveDocument." + item.substr(0, pos);
std::string refStr = "\"" + item.substr(pos+1) + "\"";
result = result + (r > 0 ? ", " : "") + "(" + objStr + "," + refStr + ")";
}
return result;
}
const std::string TaskFemConstraint::getDirectionName(void) const
{
std::string dir = ui->lineDirection->text().toStdString();
if (dir.empty())
return "";
int pos = dir.find_last_of(":");
return dir.substr(0, pos).c_str();
}
const std::string TaskFemConstraint::getDirectionObject(void) const
{
std::string dir = ui->lineDirection->text().toStdString();
if (dir.empty())
return "";
int pos = dir.find_last_of(":");
return dir.substr(pos+1).c_str();
}
const std::string TaskFemConstraint::getLocationName(void) const
{
std::string loc = ui->lineLocation->text().toStdString();
if (loc.empty())
return "";
int pos = loc.find_last_of(":");
return loc.substr(0, pos).c_str();
}
const std::string TaskFemConstraint::getLocationObject(void) const
{
std::string loc = ui->lineLocation->text().toStdString();
if (loc.empty())
return "";
int pos = loc.find_last_of(":");
return loc.substr(pos+1).c_str();
}
bool TaskFemConstraint::getReverse() const
{
return ui->checkReverse->isChecked();
}
TaskFemConstraint::~TaskFemConstraint()
{
delete ui;
}
void TaskFemConstraint::changeEvent(QEvent *e)
{
TaskBox::changeEvent(e);
if (e->type() == QEvent::LanguageChange) {
ui->comboType->blockSignals(true);
ui->spinForce->blockSignals(true);
ui->spinDistance->blockSignals(true);
int index = ui->comboType->currentIndex();
ui->comboType->clear();
ui->comboType->insertItem(0, tr("Force on geometry"));
ui->comboType->insertItem(1, tr("Fixed"));
ui->comboType->insertItem(2, tr("Bearing (axial free)"));
ui->comboType->insertItem(3, tr("Bearing (axial fixed)"));
ui->comboType->insertItem(4, tr("Pulley"));
ui->comboType->insertItem(5, tr("Gear (straight toothed)"));
ui->comboType->setCurrentIndex(index);
ui->retranslateUi(proxy);
ui->comboType->blockSignals(false);
ui->spinForce->blockSignals(false);
ui->spinDistance->blockSignals(false);
}
}
//**************************************************************************
//**************************************************************************
// TaskDialog
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TaskDlgFemConstraint::TaskDlgFemConstraint(ViewProviderFemConstraint *ConstraintView)
: TaskDialog(),ConstraintView(ConstraintView)
{
assert(ConstraintView);
parameter = new TaskFemConstraint(ConstraintView);
Content.push_back(parameter);
}
TaskDlgFemConstraint::~TaskDlgFemConstraint()
{
}
//==== calls from the TaskView ===============================================================
void TaskDlgFemConstraint::open()
{
}
void TaskDlgFemConstraint::clicked(int)
{
}
bool TaskDlgFemConstraint::accept()
{
std::string name = ConstraintView->getObject()->getNameInDocument();
try {
//Gui::Command::openCommand("FEM constraint changed");
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u",name.c_str(),parameter->getType());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Force = %f",name.c_str(),parameter->getForce());
std::string refs = parameter->getReferences();
if (!refs.empty()) {
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.References = [%s]", name.c_str(), refs.c_str());
} else {
QMessageBox::warning(parameter, tr("Input error"), tr("You must specify at least one reference"));
return false;
}
std::string dirname = parameter->getDirectionName().data();
std::string dirobj = parameter->getDirectionObject().data();
if (!dirname.empty()) {
QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])");
buf = buf.arg(QString::fromStdString(dirname));
buf = buf.arg(QString::fromStdString(dirobj));
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = %s", name.c_str(), buf.toStdString().c_str());
} else {
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = None", name.c_str());
}
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %s", name.c_str(), parameter->getReverse() ? "True" : "False");
std::string locname = parameter->getLocationName().data();
std::string locobj = parameter->getLocationObject().data();
if (!locname.empty()) {
QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])");
buf = buf.arg(QString::fromStdString(locname));
buf = buf.arg(QString::fromStdString(locobj));
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Location = %s", name.c_str(), buf.toStdString().c_str());
} else {
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = None", name.c_str());
}
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Distance = %f",name.c_str(),parameter->getDistance());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Diameter = %f",name.c_str(),parameter->getDiameter());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.OtherDiameter = %f",name.c_str(),parameter->getOtherDiameter());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.CenterDistance = %f",name.c_str(),parameter->getCenterDistance());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()");
if (!ConstraintView->getObject()->isValid())
throw Base::Exception(ConstraintView->getObject()->getStatusString());
Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()");
Gui::Command::commitCommand();
}
catch (const Base::Exception& e) {
QMessageBox::warning(parameter, tr("Input error"), QString::fromAscii(e.what()));
return false;
}
return true;
}
bool TaskDlgFemConstraint::reject()
{
// roll back the done things
Gui::Command::abortCommand();
Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()");
return true;
}
#include "moc_TaskFemConstraint.cpp"

View File

@ -0,0 +1,131 @@
/***************************************************************************
* Copyright (c) 2013 Jan Rheinländer <jrheinlaender@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., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef GUI_TASKVIEW_TaskFemConstraint_H
#define GUI_TASKVIEW_TaskFemConstraint_H
#include <Gui/TaskView/TaskView.h>
#include <Gui/Selection.h>
#include <Gui/TaskView/TaskDialog.h>
#include "ViewProviderFemConstraint.h"
class Ui_TaskFemConstraint;
namespace App {
class Property;
}
namespace Gui {
class ViewProvider;
}
namespace FemGui {
class TaskFemConstraint : public Gui::TaskView::TaskBox, public Gui::SelectionObserver
{
Q_OBJECT
public:
TaskFemConstraint(ViewProviderFemConstraint *ConstraintView,QWidget *parent = 0);
~TaskFemConstraint();
int getType(void) const;
double getForce(void) const;
const std::string getReferences(void) const;
const std::string getDirectionName(void) const;
const std::string getDirectionObject(void) const;
const std::string getLocationName(void) const;
const std::string getLocationObject(void) const;
double getDistance(void) const;
bool getReverse(void) const;
double getDiameter(void) const;
double getOtherDiameter(void) const;
double getCenterDistance(void) const;
private Q_SLOTS:
void onTypeChanged(int);
void onReferenceDeleted();
void onForceChanged(double);
void onButtonReference(const bool pressed = true);
void onButtonDirection(const bool pressed = true);
void onButtonLocation(const bool pressed = true);
void onDistanceChanged(double);
void onCheckReverse(bool);
void onDiameterChanged(double);
void onOtherDiameterChanged(double);
void onCenterDistanceChanged(double);
protected:
void changeEvent(QEvent *e);
private:
void onSelectionChanged(const Gui::SelectionChanges& msg);
void updateUI();
private:
QWidget* proxy;
Ui_TaskFemConstraint* ui;
ViewProviderFemConstraint *ConstraintView;
enum {seldir, selref, selloc, selnone} selectionMode;
};
/// simulation dialog for the TaskView
class TaskDlgFemConstraint : public Gui::TaskView::TaskDialog
{
Q_OBJECT
public:
TaskDlgFemConstraint(ViewProviderFemConstraint *ConstraintView);
~TaskDlgFemConstraint();
ViewProviderFemConstraint* getConstraintView() const
{ return ConstraintView; }
public:
/// is called the TaskView when the dialog is opened
virtual void open();
/// is called by the framework if an button is clicked which has no accept or reject role
virtual void clicked(int);
/// is called by the framework if the dialog is accepted (Ok)
virtual bool accept();
/// is called by the framework if the dialog is rejected (Cancel)
virtual bool reject();
/// is called by the framework if the user presses the help button
virtual bool isAllowedAlterDocument(void) const
{ return false; }
/// returns for Close and Help button
virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const
{ return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; }
protected:
ViewProviderFemConstraint *ConstraintView;
TaskFemConstraint *parameter;
};
} //namespace FemGui
#endif // GUI_TASKVIEW_TaskFemConstraint_H

View File

@ -0,0 +1,208 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TaskFemConstraint</class>
<widget class="QWidget" name="TaskFemConstraint">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>257</width>
<height>461</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QComboBox" name="comboType"/>
</item>
<item>
<widget class="QPushButton" name="buttonReference">
<property name="text">
<string>Add reference</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listReferences"/>
</item>
<item>
<layout class="QHBoxLayout" name="layoutForce">
<item>
<widget class="QLabel" name="labelForce">
<property name="text">
<string>Load [N]</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinForce">
<property name="minimum">
<double>-99999.000000000000000</double>
</property>
<property name="maximum">
<double>99999.000000000000000</double>
</property>
<property name="value">
<double>500.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="layoutDistance_2">
<item>
<widget class="QLabel" name="labelDiameter">
<property name="text">
<string>Diameter</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinDiameter">
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>-99999.000000000000000</double>
</property>
<property name="maximum">
<double>99999.000000000000000</double>
</property>
<property name="value">
<double>100.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="layoutDistance_3">
<item>
<widget class="QLabel" name="labelOtherDia">
<property name="text">
<string>Other diameter</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinOtherDia">
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>-99999.000000000000000</double>
</property>
<property name="maximum">
<double>99999.000000000000000</double>
</property>
<property name="value">
<double>200.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="layoutDistance_4">
<item>
<widget class="QLabel" name="labelCenterDistance">
<property name="text">
<string>Center distance</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinCenterDistance">
<property name="minimum">
<double>-99999.000000000000000</double>
</property>
<property name="maximum">
<double>99999.000000000000000</double>
</property>
<property name="value">
<double>500.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="layoutDirection">
<item>
<widget class="QPushButton" name="buttonDirection">
<property name="text">
<string>Direction</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineDirection"/>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkReverse">
<property name="text">
<string>Reverse direction</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="layoutLocation">
<item>
<widget class="QPushButton" name="buttonLocation">
<property name="text">
<string>Location</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineLocation"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="layoutDistance">
<item>
<widget class="QLabel" name="labelDistance">
<property name="text">
<string>Distance</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinDistance">
<property name="minimum">
<double>-99999.000000000000000</double>
</property>
<property name="maximum">
<double>99999.000000000000000</double>
</property>
<property name="value">
<double>10.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>17</width>
<height>56</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,819 @@
/***************************************************************************
* Copyright (c) 2013 Jan Rheinländer <jrheinlaender[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., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <sstream>
# include <QApplication>
# include <Inventor/SoPickedPoint.h>
# include <Inventor/events/SoMouseButtonEvent.h>
# include <Inventor/nodes/SoSeparator.h>
# include <Inventor/nodes/SoBaseColor.h>
# include <Inventor/nodes/SoFontStyle.h>
# include <Inventor/nodes/SoPickStyle.h>
# include <Inventor/nodes/SoText2.h>
# include <Inventor/nodes/SoTranslation.h>
# include <Inventor/nodes/SoCoordinate3.h>
# include <Inventor/nodes/SoIndexedLineSet.h>
# include <Inventor/nodes/SoIndexedFaceSet.h>
# include <Inventor/nodes/SoMarkerSet.h>
# include <Inventor/nodes/SoDrawStyle.h>
# include <TopoDS.hxx>
# include <TopoDS_Vertex.hxx>
# include <BRep_Tool.hxx>
# include <gp_Pnt.hxx>
# include <gp_Pln.hxx>
# include <gp_Cylinder.hxx>
# include <BRepAdaptor_Curve.hxx>
# include <GProp_GProps.hxx>
# include <BRepGProp.hxx>
# include <BRepGProp_Face.hxx>
# include <BRepAdaptor_Surface.hxx>
# include <ShapeAnalysis.hxx>
# include <BRepClass_FaceClassifier.hxx>
# include <GeomAPI_ProjectPointOnSurf.hxx>
# include <GeomAPI_IntCS.hxx>
# include <Geom_Plane.hxx>
# include <Geom_Line.hxx>
# include <Precision.hxx>
#endif
#include "ViewProviderFemConstraint.h"
#include "TaskFemConstraint.h"
#include "Gui/SoFCSelection.h"
#include "Gui/Application.h"
#include "Gui/Control.h"
#include "Gui/Command.h"
#include "Gui/Document.h"
#include "Gui/View3DInventorViewer.h"
#include "App/Document.h"
#include <App/PropertyGeo.h>
#include <App/PropertyStandard.h>
#include <Mod/Part/App/PartFeature.h>
#include <Mod/Fem/App/FemConstraint.h>
#include <Base/Console.h>
using namespace FemGui;
PROPERTY_SOURCE(FemGui::ViewProviderFemConstraint, Gui::ViewProviderDocumentObject)
ViewProviderFemConstraint::ViewProviderFemConstraint()
{
ADD_PROPERTY(TextColor,(0.0f,0.0f,0.0f));
ADD_PROPERTY(FaceColor,(1.0f,0.0f,0.2f));
ADD_PROPERTY(FontSize,(18));
ADD_PROPERTY(DistFactor,(1.0));
ADD_PROPERTY(Mirror,(false));
pFont = new SoFontStyle();
pFont->ref();
pLabel = new SoText2();
pLabel->ref();
pColor = new SoBaseColor();
pColor->ref();
pTextColor = new SoBaseColor();
pTextColor->ref();
pTranslation = new SoTranslation();
pTranslation->ref();
TextColor.touch();
FontSize.touch();
FaceColor.touch();
pCoords = new SoCoordinate3();
pCoords->ref();
pCoords->point.setNum(0);
pFaces = new SoIndexedFaceSet();
pFaces->ref();
pFaces->coordIndex.setNum(0);
sPixmap = "view-femconstraint";
normalDirection = new SbVec3f(0, 0, 1);
arrowDirection = NULL;
}
ViewProviderFemConstraint::~ViewProviderFemConstraint()
{
pFont->unref();
pLabel->unref();
pColor->unref();
pTextColor->unref();
pTranslation->unref();
pCoords->unref();
pFaces->unref();
delete arrowDirection;
delete normalDirection;
}
std::vector<App::DocumentObject*> ViewProviderFemConstraint::claimChildren(void)const
{
return std::vector<App::DocumentObject*>();
}
void ViewProviderFemConstraint::setupContextMenu(QMenu* menu, QObject* receiver, const char* member)
{
QAction* act;
act = menu->addAction(QObject::tr("Edit constraint"), receiver, member);
act->setData(QVariant((int)ViewProvider::Default));
ViewProviderDocumentObject::setupContextMenu(menu, receiver, member);
}
void ViewProviderFemConstraint::onChanged(const App::Property* prop)
{
if (this->getObject() != NULL)
Base::Console().Error("%s: onChanged: %s\n", this->getObject()->getNameInDocument(), prop->getName());
else
Base::Console().Error("Anonymous: onChanged: %s\n", prop->getName());
if (prop == &Mirror || prop == &DistFactor) {
updateData(prop);
}
else if (prop == &TextColor) {
const App::Color& c = TextColor.getValue();
pTextColor->rgb.setValue(c.r,c.g,c.b);
}
else if (prop == &FaceColor) {
const App::Color& c = FaceColor.getValue();
pColor->rgb.setValue(c.r,c.g,c.b);
}
else if (prop == &FontSize) {
pFont->size = FontSize.getValue();
}
else {
ViewProviderDocumentObject::onChanged(prop);
}
}
bool ViewProviderFemConstraint::setEdit(int ModNum)
{
if (ModNum == ViewProvider::Default ) {
// When double-clicking on the item for this constraint the
// object unsets and sets its edit mode without closing
// the task panel
Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog();
TaskDlgFemConstraint *constrDlg = qobject_cast<TaskDlgFemConstraint *>(dlg);
if (constrDlg && constrDlg->getConstraintView() != this)
constrDlg = 0; // another constraint left open its task panel
if (dlg && !constrDlg) {
QMessageBox msgBox;
msgBox.setText(QObject::tr("A dialog is already open in the task panel"));
msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?"));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::Yes);
int ret = msgBox.exec();
if (ret == QMessageBox::Yes)
Gui::Control().closeDialog();
else
return false;
}
// clear the selection (convenience)
Gui::Selection().clearSelection();
// start the edit dialog
if (constrDlg)
Gui::Control().showDialog(constrDlg);
else
Gui::Control().showDialog(new TaskDlgFemConstraint(this));
return true;
}
else {
return ViewProviderDocumentObject::setEdit(ModNum);
}
}
void ViewProviderFemConstraint::unsetEdit(int ModNum)
{
if (ModNum == ViewProvider::Default) {
// when pressing ESC make sure to close the dialog
Gui::Control().closeDialog();
}
else {
ViewProviderDocumentObject::unsetEdit(ModNum);
}
}
std::vector<std::string> ViewProviderFemConstraint::getDisplayModes(void) const
{
// add modes
std::vector<std::string> StrList;
StrList.push_back("Base");
return StrList;
}
void ViewProviderFemConstraint::setDisplayMode(const char* ModeName)
{
if (strcmp(ModeName, "Base") == 0)
setDisplayMaskMode("Base");
ViewProviderDocumentObject::setDisplayMode(ModeName);
}
void ViewProviderFemConstraint::attach(App::DocumentObject* pcObject)
{
ViewProviderDocumentObject::attach(pcObject);
SoPickStyle* ps = new SoPickStyle();
ps->style = SoPickStyle::UNPICKABLE;
SoSeparator *faceSep = new SoSeparator();
faceSep->addChild(ps);
faceSep->addChild(pColor);
faceSep->addChild(pCoords);
faceSep->addChild(pFaces);
SoSeparator* sep = new SoSeparator();
sep->addChild(faceSep);
addDisplayMaskMode(sep, "Base");
}
// Create a local coordinate system with the z-axis given in dir
void getLocalCoordinateSystem(const SbVec3f& z, SbVec3f& y, SbVec3f& x)
{
// Find the y axis in an arbitrary direction, normal to z
// Conditions:
// y1 * z1 + y2 * z2 + y3 * z3 = |y| |z| cos(90°) = 0
// |y| = sqrt(y1^2 + y2^2 + y3^2) = 1
float z1, z2, z3;
z.getValue(z1, z2, z3);
float y1, y2, y3;
if (fabs(z1) > Precision::Confusion()) {
// Choose: y3 = 0
// Solution:
// y1 * z1 + y2 * z2 = 0
// y1 = - z2/z1 y2
// sqrt(z2^2/z1^2 y2^2 + y2^2) = 1
// y2^2 ( 1 + z2^2/z1^2)) = +-1 -> choose +1 otherwise no solution
// y2 = +- sqrt(1 / (1 + z2^2/z1^2))
y3 = 0;
y2 = sqrt(1 / (1 + z2*z2 / (z1*z1)));
y1 = -z2/z1 * y2;
// Note: result might be (0, 1, 0)
} else if (fabs(z2) > Precision::Confusion()) {
// Given: z1 = 0
// Choose: y1 = 0
// Solution:
// y2 * z2 + y3 * z3 = 0
// y2 = - z3/z2 y3
// sqrt(z3^2/z2^2 y3^3 + y3^2) = 1
// y3^2 (1 + z3^2/z2^2)) = +1
// y3 = +- sqrt(1 / (1 + z3^2/z2^2))
y1 = 0;
y3 = sqrt(1 / (1 + z3*z3 / (z2*z2)));
y2 = -z3/z2 * y3;
// Note: result might be (0, 0, 1)
} else if (fabs(z3) > Precision::Confusion()) {
// Given: z1 = z2 = 0
// Choose the remaining possible axis
y1 = 1;
y2 = 0;
y3 = 0;
}
y = SbVec3f(y1, y2, y3);
x = y.cross(z);
}
#define FACETS 12
#define CONEPOINTS (FACETS + 1)
#define CONEFACETPOINTS (FACETS * 4 + FACETS + 1)
void createCone(SoMFVec3f& point, SoMFInt32& refs, const int ipoints, const int ifaces, const SbVec3f& base, const SbVec3f& dir,
const double height, const double radius, const bool update = false)
{
SbVec3f x, y;
getLocalCoordinateSystem(dir, y, x);
point.set1Value(ipoints, base); // tip
SbVec3f midpoint(base + dir * height); // centre of the circle
for (int i = 0; i < FACETS; i++) {
float angle = 2 * M_PI / FACETS * i;
point.set1Value(ipoints + i + 1, midpoint + cos(angle) * x * radius + sin(angle) * y * radius);
}
if (update)
return;
int32_t faces[CONEFACETPOINTS];
int start_index = 1;
for (int f = 0; f < FACETS; f++) {
faces[f * 4] = ipoints; // tip of arrow
int idx = start_index;
faces[f * 4 + 1] = ipoints + idx;
idx++;
if (idx > FACETS) idx = 1; // Happens in the last iteration
faces[f * 4 + 2] = ipoints + idx;
faces[f * 4 + 3] = -1;
start_index++;
}
for (int f = 0; f < FACETS; f++)
faces[FACETS * 4 + f] = ipoints + f + 1;
faces[CONEFACETPOINTS - 1] = -1;
refs.setValues(ifaces, CONEFACETPOINTS, faces);
}
#define CYLPOINTS (FACETS * 2)
#define CYLFACETPOINTS (FACETS * 5 + 2 * FACETS + 2)
void createCylinder(SoMFVec3f& point, SoMFInt32& refs, const int ipoints, const int ifaces, const SbVec3f& base, const SbVec3f& dir,
const double height, const double radius, const bool update = false)
{
SbVec3f x, y;
getLocalCoordinateSystem(dir, y, x);
for (int i = 0; i < CYLPOINTS; i+=2) {
float angle = 2 * M_PI / FACETS * i/2;
point.set1Value(ipoints + i, base + cos(angle) * x * radius + sin(angle) * y * radius);
point.set1Value(ipoints + i + 1, base + dir * height + cos(angle) * x * radius + sin(angle) * y * radius);
}
if (update)
return;
int32_t faces[CYLFACETPOINTS];
int start_index = 0;
for (int f = 0; f < FACETS; f++) {
int idx = start_index;
faces[f * 5] = ipoints + idx;
idx++;
faces[f * 5 + 1] = ipoints + idx;
idx++;
if (idx >= CYLPOINTS) idx = 0; // Happens in the last iteration
faces[f * 5 + 3] = ipoints + idx;
idx++;
faces[f * 5 + 2] = ipoints + idx;
faces[f * 5 + 4] = -1;
start_index += 2;
}
for (int f = 0; f < FACETS; f++) {
faces[FACETS * 5 + f] = ipoints + 2 * f;
faces[FACETS * 5 + FACETS + f + 1] = ipoints + 1 + 2 * f;
}
faces[FACETS * 5 + FACETS] = -1;
faces[CYLFACETPOINTS - 1] = -1;
refs.setValues(ifaces, CYLFACETPOINTS, faces);
}
#define ARROWPOINTS (CONEPOINTS + CYLPOINTS)
#define ARROWFACETPOINTS (CONEFACETPOINTS + CYLFACETPOINTS)
void createArrow(SoMFVec3f& point, SoMFInt32& refs, const int ipoints, const int ifaces, const SbVec3f& base, const SbVec3f& dir,
const double length, const double radius, const bool update = false)
{
createCone(point, refs, ipoints, ifaces, base, dir, radius, radius, update);
createCylinder(point, refs, ipoints + CONEPOINTS, ifaces + CONEFACETPOINTS, base + dir * radius, dir, length-radius, radius/3, update);
}
#define BOXPOINTS 8
#define BOXFACEPOINTS 30
void createBox(SoMFVec3f& point, SoMFInt32& refs, const int ipoints, const int ifaces, const SbVec3f& base, const SbVec3f& dir,
const double width, const double length, const double height, const bool update = false)
{
SbVec3f x, y;
getLocalCoordinateSystem(dir, y, x);
point.set1Value(ipoints, base + width/2 * y + length/2 * x);
point.set1Value(ipoints+1, base + width/2 * y - length/2 * x);
point.set1Value(ipoints+2, base - width/2 * y - length/2 * x);
point.set1Value(ipoints+3, base - width/2 * y + length/2 * x);
point.set1Value(ipoints+4, base + dir * height + width/2 * y + length/2 * x);
point.set1Value(ipoints+5, base + dir * height + width/2 * y - length/2 * x);
point.set1Value(ipoints+6, base + dir * height - width/2 * y - length/2 * x);
point.set1Value(ipoints+7, base + dir * height - width/2 * y + length/2 * x);
if (update)
return;
int32_t faces[BOXFACEPOINTS] = {
ipoints, ipoints+1, ipoints+2, ipoints+3, -1,
ipoints, ipoints+1, ipoints+5, ipoints+4, -1,
ipoints+1, ipoints+2, ipoints+6, ipoints+5, -1,
ipoints+2, ipoints+3, ipoints+7, ipoints+6, -1,
ipoints+3, ipoints, ipoints+4, ipoints+7, -1,
ipoints+4, ipoints+5, ipoints+6, ipoints+7, -1};
refs.setValues(ifaces, BOXFACEPOINTS, faces);
}
void ViewProviderFemConstraint::findCylinderData(SbVec3f& z, SbVec3f& y, SbVec3f& x, SbVec3f& p, double& radius, double& height) {
Fem::Constraint* pcConstraint = static_cast<Fem::Constraint*>(this->getObject());
std::vector<App::DocumentObject*> Objects = pcConstraint->References.getValues();
std::vector<std::string> SubElements = pcConstraint->References.getSubValues();
if (Objects.empty())
return;
App::DocumentObject* obj = Objects[0];
Part::Feature* feat = static_cast<Part::Feature*>(obj);
TopoDS_Shape sh = feat->Shape.getShape().getSubShape(SubElements[0].c_str());
TopoDS_Face face = TopoDS::Face(sh);
BRepAdaptor_Surface surface(face);
gp_Cylinder cyl = surface.Cylinder();
gp_Pnt start = surface.Value(surface.FirstUParameter(), surface.FirstVParameter());
gp_Pnt end = surface.Value(surface.FirstUParameter(), surface.LastVParameter());
height = start.Distance(end);
radius = cyl.Radius();
gp_Dir dirz = cyl.Axis().Direction();
z = SbVec3f(dirz.X(), dirz.Y(), dirz.Z());
gp_Dir diry = cyl.YAxis().Direction();
y = SbVec3f(diry.X(), diry.Y(), diry.Z());
gp_Dir dirx = cyl.XAxis().Direction();
x = SbVec3f(dirx.X(), dirx.Y(), dirx.Z());
if (pcConstraint->Location.getValue() == NULL) {
// Get a point in the middle of the cylindrical face.
gp_Pnt centre = cyl.Location();
SbVec3f base(centre.X(), centre.Y(), centre.Z());
p = base + z * height/2;
} else {
// Get the point specified by Location and Distance
App::DocumentObject* objLoc = pcConstraint->Location.getValue();
std::string subName = pcConstraint->Location.getSubValues().front();
Part::Feature* featLoc = static_cast<Part::Feature*>(objLoc);
TopoDS_Shape shloc = featLoc->Shape.getShape().getSubShape(subName.c_str());
// Get a plane from the Location reference
gp_Pln plane;
if (shloc.ShapeType() == TopAbs_FACE) {
BRepAdaptor_Surface surface(TopoDS::Face(shloc));
plane = surface.Plane();
} else {
BRepAdaptor_Curve curve(TopoDS::Edge(shloc));
gp_Lin line = curve.Line();
gp_Dir tang = line.Direction().Crossed(dirz);
gp_Dir norm = line.Direction().Crossed(tang);
plane = gp_Pln(line.Location(), norm);
}
// Translate the plane in direction of the cylinder (for positive values of Distance)
Handle_Geom_Plane pln = new Geom_Plane(plane);
GeomAPI_ProjectPointOnSurf proj(cyl.Location(), pln);
if (!proj.IsDone())
return;
gp_Pnt projPnt = proj.NearestPoint();
plane.Translate(gp_Vec(projPnt, cyl.Location()).Normalized().Multiplied(pcConstraint->Distance.getValue()));
Handle_Geom_Plane plnt = new Geom_Plane(plane);
// Intersect translated plane with cylinder axis
Handle_Geom_Curve crv = new Geom_Line(cyl.Axis());
GeomAPI_IntCS intersector(crv, plnt);
if (!intersector.IsDone())
return;
gp_Pnt inter = intersector.Point(1);
p.setValue(inter.X(), inter.Y(), inter.Z());
}
}
void ViewProviderFemConstraint::updateData(const App::Property* prop)
{
// Gets called whenever a property of the attached object changes
if (this->getObject() != NULL)
Base::Console().Error("%s: updateData: %s\n", this->getObject()->getNameInDocument(), prop->getName());
else
Base::Console().Error("Anonymous: updateData: %s\n", prop->getName());
Fem::Constraint* pcConstraint = static_cast<Fem::Constraint*>(this->getObject());
if (strcmp(prop->getName(),"References") == 0) {
const App::PropertyLinkSubList* pr = static_cast<const App::PropertyLinkSubList*>(prop);
std::vector<App::DocumentObject*> Objects = pr->getValues();
std::vector<std::string> SubElements = pr->getSubValues();
// Remove all arrows
pCoords->point.deleteValues(0, pCoords->point.getNum());
pFaces->coordIndex.deleteValues(0, pFaces->coordIndex.getNum());
if (Objects.empty()) {
Base::Console().Error(" updateData: No references\n");
Objects = pcConstraint->References.getValues();
SubElements = pcConstraint->References.getSubValues();
if (Objects.empty())
return;
}
Base::Console().Error(" updateData: Found %u references\n", Objects.size());
// Re-create all arrows
int type = pcConstraint->Type.getValue();
if ((type == 0) || (type == 1)) {
// Force on geometry
std::vector<gp_Pnt> points;
TopoDS_Shape sh;
for (int i = 0; i < Objects.size(); i++) {
App::DocumentObject* obj = Objects[i];
Part::Feature* feat = static_cast<Part::Feature*>(obj);
const Part::TopoShape& toposhape = feat->Shape.getShape();
if (toposhape.isNull()) {
Base::Console().Error(" updateData: Empty toposhape\n");
return;
}
sh = toposhape.getSubShape(SubElements[i].c_str());
if (sh.ShapeType() == TopAbs_VERTEX) {
const TopoDS_Vertex& vertex = TopoDS::Vertex(sh);
gp_Pnt p = BRep_Tool::Pnt(vertex);
points.push_back(p);
} else if (sh.ShapeType() == TopAbs_EDGE) {
BRepAdaptor_Curve curve(TopoDS::Edge(sh));
double fp = curve.FirstParameter();
double lp = curve.LastParameter();
GProp_GProps props;
BRepGProp::LinearProperties(sh, props);
double l = props.Mass();
int steps = round(l / 3); // TODO: Make number of steps depend on actual screen size of element!
double step = (lp - fp) / steps;
if (steps < 1) {
points.push_back(curve.Value(fp));
points.push_back(curve.Value(lp));
} else {
for (int i = 0; i < steps + 1; i++)
points.push_back(curve.Value(i * step));
}
} else if (sh.ShapeType() == TopAbs_FACE) {
TopoDS_Face face = TopoDS::Face(sh);
BRepAdaptor_Surface surface(face);
double ufp = surface.FirstUParameter();
double ulp = surface.LastUParameter();
double vfp = surface.FirstVParameter();
double vlp = surface.LastVParameter();
double ustep = (ulp - ufp) / 6.0;
double vstep = (vlp - vfp) / 6.0;
// TODO: How to find the distance between ufp and ulp to get the number of steps?
for (int i = 0; i < 7; i++) {
for (int j = 0; j < 7; j++) {
gp_Pnt p = surface.Value(ufp + i * ustep, vfp + j * vstep);
BRepClass_FaceClassifier classifier(face, p, Precision::Confusion());
if (classifier.State() != TopAbs_OUT)
points.push_back(p);
}
}
}
}
// Get default direction (on first call to method)
if (arrowDirection == NULL) {
if (sh.ShapeType() == TopAbs_FACE) {
// Get face normal in center point
TopoDS_Face face = TopoDS::Face(sh);
BRepGProp_Face prop(face);
gp_Vec normal;
gp_Pnt center;
double u1,u2,v1,v2;
prop.Bounds(u1,u2,v1,v2);
prop.Normal((u1+u2)/2.0,(v1+v2)/2.0,center,normal);
normal.Normalize();
normalDirection->setValue(normal.X(), normal.Y(), normal.Z());
} // else use z axis
arrowDirection = new SbVec3f(*normalDirection);
}
if (type == 0) {
// Force on geometry
pCoords->point.setNum(ARROWPOINTS * points.size());
pFaces->coordIndex.setNum(ARROWFACETPOINTS * points.size());
int index = 0;
for (std::vector<gp_Pnt>::const_iterator p = points.begin(); p != points.end(); p++) {
SbVec3f v(p->X(), p->Y(), p->Z());
if (*arrowDirection != *normalDirection) // Turn arrow around
v = v + *normalDirection * 5.0;
createArrow(pCoords->point, pFaces->coordIndex,
index * ARROWPOINTS, index * ARROWFACETPOINTS,
v, *arrowDirection, 5.0, 1.0);
index++;
}
} else if (type == 1) {
// Fixed
pCoords->point.setNum((CONEPOINTS + BOXPOINTS) * points.size());
pFaces->coordIndex.setNum((CONEFACETPOINTS + BOXFACEPOINTS) * points.size());
int index = 0;
for (std::vector<gp_Pnt>::const_iterator p = points.begin(); p != points.end(); p++) {
SbVec3f v(p->X(), p->Y(), p->Z());
createCone(pCoords->point, pFaces->coordIndex,
index * (CONEPOINTS + BOXPOINTS), index * (CONEFACETPOINTS + BOXFACEPOINTS),
v, *normalDirection, 2.0, 1.0);
createBox(pCoords->point, pFaces->coordIndex,
index * (CONEPOINTS + BOXPOINTS) + CONEPOINTS, index * (CONEFACETPOINTS + BOXFACEPOINTS) + CONEFACETPOINTS,
v + *normalDirection * 2.0, *normalDirection, 2.0, 2.0, 0.5);
index++;
}
}
} else if ((type == 2) || (type == 3)) {
// Bearing. Note that only one face is allowed for this constraint
SbVec3f z, y, x, p;
double radius, height;
findCylinderData(z, y, x, p, radius, height);
p = p + y * radius;
pCoords->point.setNum(CONEPOINTS + BOXPOINTS);
pFaces->coordIndex.setNum(CONEFACETPOINTS + BOXFACEPOINTS);
if (type == 2)
// axial free
createCone(pCoords->point, pFaces->coordIndex, 0, 0, p, y, radius/2.5, radius/4);
else
// axial fixed
createCone(pCoords->point, pFaces->coordIndex, 0, 0, p, y, radius/2, radius/4);
createBox(pCoords->point, pFaces->coordIndex, CONEPOINTS, CONEFACETPOINTS, p + y * radius/2, y, radius, radius, radius/10);
} else if ((type == 4) || (type == 5)) {
// Pulley, Gear
SbVec3f z, y, x, p;
double radius, height;
findCylinderData(z, y, x, p, radius, height);
double dia = pcConstraint->Diameter.getValue();
if (dia < Precision::Confusion())
dia = radius * 4;
double otherdia = pcConstraint->OtherDiameter.getValue();
if (otherdia < Precision::Confusion())
otherdia = radius * 2;
double centerdist = pcConstraint->CenterDistance.getValue();
if (fabs(centerdist) < Precision::Confusion())
centerdist = 500;
if (type == 4) {
// Pulley
pCoords->point.setNum(CYLPOINTS + 2 * ARROWPOINTS);
pFaces->coordIndex.setNum(CYLFACETPOINTS + 2 * ARROWFACETPOINTS);
createCylinder(pCoords->point, pFaces->coordIndex, 0, 0, p - z * height * 0.4, z, height * 0.8, dia);
double angle = asin((dia - otherdia)/2/centerdist);
SbVec3f p1 = p + y * dia * cos(angle) + x * dia * sin(angle);
SbVec3f dir1 = x - y * sin(angle);
dir1.normalize();
p1 = p1 + dir1 * 2 * radius;
dir1.negate();
SbVec3f p2 = p - y * dia * cos(angle) + x * dia * sin(angle);
SbVec3f dir2 = x + y * sin(angle);
dir2.normalize();
p2 = p2 + dir2 * 2 * radius;
dir2.negate();
createArrow(pCoords->point, pFaces->coordIndex, CYLPOINTS, CYLFACETPOINTS, p1, dir1, 2 * radius, radius/5);
createArrow(pCoords->point, pFaces->coordIndex, CYLPOINTS+ARROWPOINTS, CYLFACETPOINTS+ARROWFACETPOINTS, p2, dir2, 2 * radius, radius/5);
} else if (type == 5) {
// Gear
pCoords->point.setNum(CYLPOINTS + ARROWPOINTS);
pFaces->coordIndex.setNum(CYLFACETPOINTS + ARROWFACETPOINTS);
createCylinder(pCoords->point, pFaces->coordIndex, 0, 0, p - z * height * 0.4, z, height * 0.8, dia);
SbVec3f p1 = p + y * dia;
createArrow(pCoords->point, pFaces->coordIndex, CYLPOINTS, CYLFACETPOINTS, p1, x, radius, radius/5);
}
}
} else if (strcmp(prop->getName(),"Direction") == 0) {
if (arrowDirection == NULL)
return;
const App::PropertyLinkSub* pr = static_cast<const App::PropertyLinkSub*>(prop);
App::DocumentObject* obj = pr->getValue();
std::vector<std::string> names = pr->getSubValues();
if (names.size() == 0)
return;
std::string subName = names.front();
Part::Feature* feat = static_cast<Part::Feature*>(obj);
TopoDS_Shape sh = feat->Shape.getShape().getSubShape(subName.c_str());
if (sh.ShapeType() == TopAbs_FACE) {
BRepAdaptor_Surface surface(TopoDS::Face(sh));
if (surface.GetType() == GeomAbs_Plane) {
gp_Dir dir = surface.Plane().Axis().Direction();
arrowDirection->setValue(dir.X(), dir.Y(), dir.Z());
} else {
return; // Not a planar face
}
} else if (sh.ShapeType() == TopAbs_EDGE) {
BRepAdaptor_Curve line(TopoDS::Edge(sh));
if (line.GetType() == GeomAbs_Line) {
gp_Dir dir = line.Line().Direction();
arrowDirection->setValue(dir.X(), dir.Y(), dir.Z());
} else {
return; // Not a linear edge
}
}
// TODO: Check whether direction points inside or outside of solid? But for which reference?
arrowDirection->normalize();
*normalDirection = *arrowDirection;
bool reversed = pcConstraint->Reversed.getValue();
if (reversed)
arrowDirection->negate();
// Re-orient all arrows
int numArrows = pCoords->point.getNum()/ARROWPOINTS;
for (int i = 0; i < numArrows; i++) {
// Note: for update=true the pFaces->coordIndex is not touched
SbVec3f p = pCoords->point[i * ARROWPOINTS];
if (reversed)
p = p + *normalDirection * 5.0;
createArrow(pCoords->point, pFaces->coordIndex,
i * ARROWPOINTS, 0,
p, *arrowDirection, 5.0, 1.0, true);
}
} else if (strcmp(prop->getName(),"Reversed") == 0) {
if (arrowDirection == NULL)
return;
bool reversed = static_cast<const App::PropertyBool*>(prop)->getValue();
bool isReversed = (*arrowDirection != *normalDirection);
if (reversed == isReversed)
return;
*arrowDirection = *normalDirection;
if (reversed)
arrowDirection->negate();
// Reverse all arrows
int numArrows = pCoords->point.getNum()/ARROWPOINTS;
for (int i = 0; i < numArrows; i++) {
createArrow(pCoords->point, pFaces->coordIndex,
i * ARROWPOINTS, 0,
pCoords->point[i * ARROWPOINTS], *arrowDirection, 5.0, 1.0, true);
}
} else if ((strcmp(prop->getName(),"Location") == 0) || (strcmp(prop->getName(),"Distance") == 0)) {
// Move bearing constraint
SbVec3f z, y, x, p;
double radius, height;
findCylinderData(z, y, x, p, radius, height);
int type = pcConstraint->Type.getValue();
if (type == 2) {
// axial free
createCone(pCoords->point, pFaces->coordIndex, 0, 0, p, y, radius/2.5, radius/4, true);
createBox(pCoords->point, pFaces->coordIndex, CONEPOINTS, CONEFACETPOINTS, p + y * radius/2, y, radius, radius, radius/10, true);
} else if (type == 3) {
// axial fixed
createCone(pCoords->point, pFaces->coordIndex, 0, 0, p, y, radius/2, radius/4, true);
createBox(pCoords->point, pFaces->coordIndex, CONEPOINTS, CONEFACETPOINTS, p + y * radius/2, y, radius, radius, radius/10, true);
} else if ((type == 4) || (type == 5)) {
createCylinder(pCoords->point, pFaces->coordIndex, 0, 0, p - z * height * 0.4, z, height * 0.8, pcConstraint->Diameter.getValue(), true);
}
} else if ((strcmp(prop->getName(),"Diameter") == 0) || (strcmp(prop->getName(),"OtherDiameter") == 0) ||
(strcmp(prop->getName(),"CenterDistance") == 0)) {
// Update pulley/gear constraint
SbVec3f z, y, x, p;
double radius, height;
findCylinderData(z, y, x, p, radius, height);
double dia = pcConstraint->Diameter.getValue();
if (dia < Precision::Confusion())
dia = radius * 4;
double otherdia = pcConstraint->OtherDiameter.getValue();
if (otherdia < Precision::Confusion())
otherdia = radius * 2;
double centerdist = pcConstraint->CenterDistance.getValue();
if (fabs(centerdist) < Precision::Confusion())
centerdist = 500;
int type = pcConstraint->Type.getValue();
if (type == 4) {
// Pulley
createCylinder(pCoords->point, pFaces->coordIndex, 0, 0, p - z * height * 0.4, z, height * 0.8, dia, true);
double angle = asin((dia - otherdia)/2/centerdist);
SbVec3f p1 = p + y * dia * cos(angle) + x * dia * sin(angle);
SbVec3f dir1 = x - y * sin(angle);
dir1.normalize();
p1 = p1 + dir1 * 2 * radius;
dir1.negate();
SbVec3f p2 = p - y * dia * cos(angle) + x * dia * sin(angle);
SbVec3f dir2 = x + y * sin(angle);
dir2.normalize();
p2 = p2 + dir2 * 2 * radius;
dir2.negate();
createArrow(pCoords->point, pFaces->coordIndex, CYLPOINTS, CYLFACETPOINTS, p1, dir1, 2 * radius, radius/5, true);
createArrow(pCoords->point, pFaces->coordIndex, CYLPOINTS+ARROWPOINTS, CYLFACETPOINTS+ARROWFACETPOINTS, p2, dir2, 2 * radius, radius/5, true);
} else if (type == 5) {
// Gear
createCylinder(pCoords->point, pFaces->coordIndex, 0, 0, p - z * height * 0.4, z, height * 0.8, dia, true);
SbVec3f p1 = p + y * dia;
createArrow(pCoords->point, pFaces->coordIndex, CYLPOINTS, CYLFACETPOINTS, p1, x, 2 * radius, radius/5, true);
}
}
ViewProviderDocumentObject::updateData(prop);
}

View File

@ -0,0 +1,98 @@
/***************************************************************************
* Copyright (c) 2013 Jan Rheinländer <jrheinlaender[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., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef GUI_VIEWPROVIDERFEMCONSTRAINT_H
#define GUI_VIEWPROVIDERFEMCONSTRAINT_H
#include <TopoDS_Shape.hxx>
#include "Gui/ViewProviderGeometryObject.h"
#include <QObject>
class SoFontStyle;
class SoText2;
class SoBaseColor;
class SoTranslation;
class SoCoordinate3;
class SoIndexedLineSet;
class SoIndexedFaceSet;
class SoEventCallback;
class SoMarkerSet;
namespace Gui {
class View3DInventorViewer;
}
namespace FemGui
{
class FemGuiExport ViewProviderFemConstraint : public Gui::ViewProviderGeometryObject
{
PROPERTY_HEADER(FemGui::ViewProviderFemConstraint);
public:
/// Constructor
ViewProviderFemConstraint(void);
virtual ~ViewProviderFemConstraint();
// Display properties
App::PropertyColor TextColor;
App::PropertyColor FaceColor;
App::PropertyInteger FontSize;
App::PropertyFloat DistFactor;
App::PropertyBool Mirror;
void attach(App::DocumentObject *);
void updateData(const App::Property*);
std::vector<std::string> getDisplayModes(void) const;
void setDisplayMode(const char* ModeName);
std::vector<App::DocumentObject*> claimChildren(void)const;
void setupContextMenu(QMenu*, QObject*, const char*);
protected:
void onChanged(const App::Property* prop);
virtual bool setEdit(int ModNum);
virtual void unsetEdit(int ModNum);
private:
SoFontStyle * pFont;
SoText2 * pLabel;
SoBaseColor * pColor;
SoBaseColor * pTextColor;
SoTranslation * pTranslation;
SoCoordinate3 * pCoords;
SoIndexedFaceSet * pFaces;
/// Direction pointing outside of the solid
SbVec3f * normalDirection;
/// Direction of the force
SbVec3f * arrowDirection;
void findCylinderData(SbVec3f& z, SbVec3f& y, SbVec3f& x, SbVec3f& p, double& radius, double& height);
};
} //namespace FemGui
#endif // GUI_VIEWPROVIDERFEMCONSTRAINT_H

View File

@ -29,7 +29,7 @@
#include "Workbench.h"
#include <Gui/ToolBarManager.h>
#include <Gui/MenuManager.h>
#include <Gui/MenuManager.h>
using namespace FemGui;
@ -56,7 +56,8 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
Gui::ToolBarItem* fem = new Gui::ToolBarItem(root);
fem->setCommand("FEM");
*fem << "Fem_CreateFromShape"
<< "Fem_CreateNodesSet";
<< "Fem_CreateNodesSet"
<< "Fem_Constraint";
return root;
}
@ -68,7 +69,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const
root->insertItem(item, fem);
fem->setCommand("&FEM");
*fem << "Fem_CreateFromShape"
<< "Fem_CreateNodesSet";
<< "Fem_CreateNodesSet"
<< "Fem_Constraint";
return root;
}