Merge branch 'master' into sketcherMoveColorsToPrefs

This commit is contained in:
Chris Hennes
2021-10-11 12:31:08 -05:00
committed by GitHub
129 changed files with 7990 additions and 3614 deletions
+1 -1
View File
@@ -7,7 +7,7 @@
- [Install Xcode Command line tools](#install-xcode-cli-tools)
- [Install Conda](#install-conda)
- [Run the shell script](#run-the-shell-script)
- [Building FreeCAD on macOS using homebrew packages with & without formual file](#homebrew-build-fc-on-macos)
- [Building FreeCAD on macOS using homebrew packages with & without formula file](#homebrew-build-fc-on-macos)
- [Requirements](#homebrew-requirements)
- [Install required FreeCAD dependencies](#homebrew-install-required-deps)
- [Limitations of using freecad formula file](#homebrew-limits-of-formula-file)
@@ -56,6 +56,7 @@
#include <NCollection_Map.hxx>
#include <Standard_ErrorHandler.hxx>
#include <Standard_ProgramError.hxx>
#include <Standard_Version.hxx>
#include <TColStd_MapOfInteger.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
@@ -700,7 +701,13 @@ double NETGENPlugin_Mesher::GetDefaultMinSize(const TopoDS_Shape& geom,
BRep_Tool::Triangulation ( TopoDS::Face( fExp.Current() ), loc);
if ( triangulation.IsNull() ) continue;
const double fTol = BRep_Tool::Tolerance( TopoDS::Face( fExp.Current() ));
#if OCC_VERSION_HEX < 0x070600
const TColgp_Array1OfPnt& points = triangulation->Nodes();
#else
auto points = [&triangulation](Standard_Integer index) {
return triangulation->Node(index);
};
#endif
const Poly_Array1OfTriangle& trias = triangulation->Triangles();
for ( int iT = trias.Lower(); iT <= trias.Upper(); ++iT )
{
+1 -1
View File
@@ -64,7 +64,7 @@
#include <GEOMUtils.hxx>
#undef _Precision_HeaderFile
//#undef _Precision_HeaderFile
#include <BRepBndLib.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <Bnd_Box.hxx>
+5 -2
View File
@@ -38,10 +38,13 @@
#include <GC_MakeSegment.hxx>
#include <GeomAPI_ExtremaCurveCurve.hxx>
#include <Geom_Line.hxx>
#include <IntAna_IntConicQuad.hxx>
#include <IntAna_Quadric.hxx>
#include <gp_Cone.hxx>
#include <gp_Cylinder.hxx>
#include <gp_Lin.hxx>
#include <gp_Pln.hxx>
#include <gp_Sphere.hxx>
#include <IntAna_IntConicQuad.hxx>
#include <IntAna_Quadric.hxx>
#include <limits>
#include <numeric>
@@ -46,6 +46,7 @@
#include <Poly_Array1OfTriangle.hxx>
#include <Poly_PolygonOnTriangulation.hxx>
#include <Poly_Triangulation.hxx>
#include <Standard_Version.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
@@ -318,13 +319,26 @@ namespace // internal utils
{
myFaceTol = SMESH_MesherHelper::MaxTolerance( face );
myTree = triaTree;
#if OCC_VERSION_HEX < 0x070600
myNodes = & tr->Nodes();
#else
TColgp_Array1OfPnt* trNodes = new TColgp_Array1OfPnt( 1, tr->NbNodes() );
for (Standard_Integer i = myNodes->Lower(); i <= myNodes->Upper(); i++)
{
trNodes->SetValue(i, tr->Node(i));
}
myNodes = trNodes;
myOwnNodes = true;
#endif
myPolyTrias = & tr->Triangles();
myTriasDeflection = tr->Deflection();
if ( !loc.IsIdentity() ) // transform nodes if necessary
{
TColgp_Array1OfPnt* trsfNodes = new TColgp_Array1OfPnt( myNodes->Lower(), myNodes->Upper() );
trsfNodes->Assign( *myNodes );
#if OCC_VERSION_HEX >= 0x070600
delete myNodes; // it's already a copy
#endif
myNodes = trsfNodes;
myOwnNodes = true;
const gp_Trsf& trsf = loc;
@@ -50,7 +50,7 @@
#include <Geom_Surface.hxx>
#include <NCollection_DefineArray2.hxx>
#include <Precision.hxx>
#include <Quantity_Parameter.hxx>
#include <Standard_Real.hxx>
#include <TColStd_SequenceOfInteger.hxx>
#include <TColStd_SequenceOfReal.hxx>
#include <TColgp_SequenceOfXY.hxx>
@@ -44,7 +44,10 @@
#include "SMESH_subMeshEventListener.hxx"
#include "StdMeshers_FaceSide.hxx"
#include <Standard_Version.hxx>
#if OCC_VERSION_HEX < 0x070600
#include <Adaptor3d_HSurface.hxx>
#endif
#include <BRepAdaptor_Curve2d.hxx>
#include <BRepAdaptor_Surface.hxx>
#include <BRepLProp_SLProps.hxx>
@@ -1340,8 +1343,13 @@ namespace VISCOUS_3D
//case GeomAbs_SurfaceOfExtrusion:
case GeomAbs_OffsetSurface:
{
#if OCC_VERSION_HEX < 0x070600
Handle(Adaptor3d_HSurface) base = surface.BasisSurface();
return getRovolutionAxis( base->Surface(), axis );
#else
Handle(Adaptor3d_Surface) base = surface.BasisSurface();
return getRovolutionAxis( *base, axis );
#endif
}
default: return false;
}
+2 -2
View File
@@ -97,7 +97,7 @@ Base::Placement ComplexGeoData::getPlacement() const
Base::Rotation(mat));
}
void ComplexGeoData::getLinesFromSubelement(const Segment*,
void ComplexGeoData::getLinesFromSubElement(const Segment*,
std::vector<Base::Vector3d> &Points,
std::vector<Line> &lines) const
{
@@ -105,7 +105,7 @@ void ComplexGeoData::getLinesFromSubelement(const Segment*,
(void)lines;
}
void ComplexGeoData::getFacesFromSubelement(const Segment*,
void ComplexGeoData::getFacesFromSubElement(const Segment*,
std::vector<Base::Vector3d> &Points,
std::vector<Base::Vector3d> &PointNormals,
std::vector<Facet> &faces) const
+2 -2
View File
@@ -85,12 +85,12 @@ public:
/// get subelement by combined name
virtual Segment* getSubElementByName(const char* Name) const;
/** Get lines from segment */
virtual void getLinesFromSubelement(
virtual void getLinesFromSubElement(
const Segment*,
std::vector<Base::Vector3d> &Points,
std::vector<Line> &lines) const;
/** Get faces from segment */
virtual void getFacesFromSubelement(
virtual void getFacesFromSubElement(
const Segment*,
std::vector<Base::Vector3d> &Points,
std::vector<Base::Vector3d> &PointNormals,
+71 -26
View File
@@ -5,7 +5,7 @@
Name="ComplexGeoDataPy"
Twin="ComplexGeoData"
Include="App/ComplexGeoData.h"
TwinPointer="ComplexGeoData"
TwinPointer="ComplexGeoData"
Namespace="Data"
FatherInclude="Base/PersistencePy.h"
FatherNamespace="Base"
@@ -14,34 +14,79 @@
<Author Licence="LGPL" Name="Juergen Riegel" EMail="[email protected]" />
<UserDocu>Father of all complex geometric data types</UserDocu>
</Documentation>
<Methode Name="getFacesFromSubelement" Const="true">
<Methode Name="getElementTypes" Const="true">
<Documentation>
<UserDocu>Return a list of element types</UserDocu>
</Documentation>
</Methode>
<Methode Name="countSubElements" Const="true">
<Documentation>
<UserDocu>Return the number of elements of a type</UserDocu>
</Documentation>
</Methode>
<Methode Name="getFacesFromSubElement" Const="true">
<Documentation>
<UserDocu>Return vertexes and faces from a sub-element</UserDocu>
</Documentation>
</Methode>
<Attribute Name="BoundBox" ReadOnly="true">
<Documentation>
<UserDocu>Get the BoundBox of the object</UserDocu>
</Documentation>
<Parameter Name="BoundBox" Type="Object" />
</Attribute>
<Attribute Name="Placement" ReadOnly="false">
<Documentation>
<UserDocu>Get the current transformation of the object as placement</UserDocu>
</Documentation>
<Parameter Name="Placement" Type="Object" />
</Attribute>
<Attribute Name="Matrix" ReadOnly="false">
<Documentation>
<UserDocu>Get the current transformation of the object as matrix</UserDocu>
</Documentation>
<Parameter Name="Matrix" Type="Object" />
</Attribute>
<Attribute Name="Tag">
<Documentation>
<UserDocu>Geometry Tag</UserDocu>
</Documentation>
<Parameter Name="Tag" Type="Int"/>
</Attribute>
<Methode Name="getLinesFromSubElement" Const="true">
<Documentation>
<UserDocu>Return vertexes and lines from a sub-element</UserDocu>
</Documentation>
</Methode>
<Methode Name="getPoints" Const="true">
<Documentation>
<UserDocu>Return a tuple of points and normals with a given accuracy</UserDocu>
</Documentation>
</Methode>
<Methode Name="getLines" Const="true">
<Documentation>
<UserDocu>Return a tuple of points and lines with a given accuracy</UserDocu>
</Documentation>
</Methode>
<Methode Name="getFaces" Const="true">
<Documentation>
<UserDocu>Return a tuple of points and triangles with a given accuracy</UserDocu>
</Documentation>
</Methode>
<Methode Name="applyTranslation">
<Documentation>
<UserDocu>Apply an additional translation to the placement</UserDocu>
</Documentation>
</Methode>
<Methode Name="applyRotation">
<Documentation>
<UserDocu>Apply an additional rotation to the placement</UserDocu>
</Documentation>
</Methode>
<Methode Name="transformGeometry">
<Documentation>
<UserDocu>Apply a transformation to the underlying geometry</UserDocu>
</Documentation>
</Methode>
<Attribute Name="BoundBox" ReadOnly="true">
<Documentation>
<UserDocu>Get the BoundBox of the object</UserDocu>
</Documentation>
<Parameter Name="BoundBox" Type="Object" />
</Attribute>
<Attribute Name="CenterOfGravity" ReadOnly="true">
<Documentation>
<UserDocu>Get the center of gravity</UserDocu>
</Documentation>
<Parameter Name="CenterOfGravity" Type="Object" />
</Attribute>
<Attribute Name="Placement" ReadOnly="false">
<Documentation>
<UserDocu>Get the current transformation of the object as placement</UserDocu>
</Documentation>
<Parameter Name="Placement" Type="Object" />
</Attribute>
<Attribute Name="Tag">
<Documentation>
<UserDocu>Geometry Tag</UserDocu>
</Documentation>
<Parameter Name="Tag" Type="Int"/>
</Attribute>
</PythonExport>
</GenerateModel>
+264 -36
View File
@@ -22,6 +22,9 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <memory>
#endif
#include "ComplexGeoData.h"
@@ -38,29 +41,195 @@ using namespace Data;
using namespace Base;
// returns a string which represent the object e.g. when printed in python
std::string ComplexGeoDataPy::representation(void) const
std::string ComplexGeoDataPy::representation() const
{
return std::string("<ComplexGeoData object>");
}
PyObject* ComplexGeoDataPy::getFacesFromSubelement(PyObject *args)
PyObject* ComplexGeoDataPy::getElementTypes(PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return nullptr;
std::vector<const char*> types = getComplexGeoDataPtr()->getElementTypes();
Py::List list;
for (auto it : types) {
list.append(Py::String(it));
}
return Py::new_reference_to(list);
}
PyObject* ComplexGeoDataPy::countSubElements(PyObject *args)
{
char *type;
int index;
if (!PyArg_ParseTuple(args, "si", &type, &index))
return 0;
if (!PyArg_ParseTuple(args, "s", &type))
return nullptr;
try {
unsigned long count = getComplexGeoDataPtr()->countSubElements(type);
return Py::new_reference_to(Py::Long(count));
}
catch (...) {
PyErr_SetString(PyExc_RuntimeError, "failed to count sub-elements from object");
return nullptr;
}
}
PyObject* ComplexGeoDataPy::getFacesFromSubElement(PyObject *args)
{
char *type;
unsigned long index;
if (!PyArg_ParseTuple(args, "sk", &type, &index))
return nullptr;
std::vector<Base::Vector3d> points;
std::vector<Base::Vector3d> normals;
std::vector<Data::ComplexGeoData::Facet> facets;
try {
Data::Segment* segm = getComplexGeoDataPtr()->getSubElement(type, index);
getComplexGeoDataPtr()->getFacesFromSubelement(segm, points, normals, facets);
delete segm;
std::unique_ptr<Data::Segment> segm(getComplexGeoDataPtr()->getSubElement(type, index));
getComplexGeoDataPtr()->getFacesFromSubElement(segm.get(), points, normals, facets);
}
catch (...) {
PyErr_SetString(PyExc_RuntimeError, "failed to get sub-element from object");
return 0;
return nullptr;
}
Py::Tuple tuple(2);
Py::List vertex;
for (std::vector<Base::Vector3d>::const_iterator it = points.begin();
it != points.end(); ++it)
vertex.append(Py::asObject(new Base::VectorPy(*it)));
tuple.setItem(0, vertex);
Py::List facet;
for (std::vector<Data::ComplexGeoData::Facet>::const_iterator
it = facets.begin(); it != facets.end(); ++it) {
Py::Tuple f(3);
f.setItem(0,Py::Int(int(it->I1)));
f.setItem(1,Py::Int(int(it->I2)));
f.setItem(2,Py::Int(int(it->I3)));
facet.append(f);
}
tuple.setItem(1, facet);
return Py::new_reference_to(tuple);
}
PyObject* ComplexGeoDataPy::getLinesFromSubElement(PyObject *args)
{
char *type;
int index;
if (!PyArg_ParseTuple(args, "si", &type, &index))
return nullptr;
std::vector<Base::Vector3d> points;
std::vector<Data::ComplexGeoData::Line> lines;
try {
std::unique_ptr<Data::Segment> segm(getComplexGeoDataPtr()->getSubElement(type, index));
getComplexGeoDataPtr()->getLinesFromSubElement(segm.get(), points, lines);
}
catch (...) {
PyErr_SetString(PyExc_RuntimeError, "failed to get sub-element from object");
return nullptr;
}
Py::Tuple tuple(2);
Py::List vertex;
for (std::vector<Base::Vector3d>::const_iterator it = points.begin();
it != points.end(); ++it)
vertex.append(Py::asObject(new Base::VectorPy(*it)));
tuple.setItem(0, vertex);
Py::List line;
for (std::vector<Data::ComplexGeoData::Line>::const_iterator
it = lines.begin(); it != lines.end(); ++it) {
Py::Tuple l(2);
l.setItem(0,Py::Int((int)it->I1));
l.setItem(1,Py::Int((int)it->I2));
line.append(l);
}
tuple.setItem(1, line);
return Py::new_reference_to(tuple);
}
PyObject* ComplexGeoDataPy::getPoints(PyObject *args)
{
double accuracy = 0.05;
if (!PyArg_ParseTuple(args, "d", &accuracy))
return nullptr;
std::vector<Base::Vector3d> points;
std::vector<Base::Vector3d> normals;
try {
getComplexGeoDataPtr()->getPoints(points, normals, accuracy);
}
catch (...) {
PyErr_SetString(PyExc_RuntimeError, "failed to get sub-element from object");
return nullptr;
}
Py::Tuple tuple(2);
Py::List vertex;
for (std::vector<Base::Vector3d>::const_iterator it = points.begin();
it != points.end(); ++it) {
vertex.append(Py::asObject(new Base::VectorPy(*it)));
}
tuple.setItem(0, vertex);
Py::List normal;
for (std::vector<Base::Vector3d>::const_iterator it = normals.begin();
it != normals.end(); ++it) {
vertex.append(Py::asObject(new Base::VectorPy(*it)));
}
tuple.setItem(1, normal);
return Py::new_reference_to(tuple);
}
PyObject* ComplexGeoDataPy::getLines(PyObject *args)
{
double accuracy = 0.05;
if (!PyArg_ParseTuple(args, "d", &accuracy))
return nullptr;
std::vector<Base::Vector3d> points;
std::vector<Data::ComplexGeoData::Line> lines;
try {
getComplexGeoDataPtr()->getLines(points, lines, accuracy);
}
catch (...) {
PyErr_SetString(PyExc_RuntimeError, "failed to get sub-element from object");
return nullptr;
}
Py::Tuple tuple(2);
Py::List vertex;
for (std::vector<Base::Vector3d>::const_iterator it = points.begin();
it != points.end(); ++it)
vertex.append(Py::asObject(new Base::VectorPy(*it)));
tuple.setItem(0, vertex);
Py::List line;
for (std::vector<Data::ComplexGeoData::Line>::const_iterator
it = lines.begin(); it != lines.end(); ++it) {
Py::Tuple l(2);
l.setItem(0,Py::Int((int)it->I1));
l.setItem(1,Py::Int((int)it->I2));
line.append(l);
}
tuple.setItem(1, line);
return Py::new_reference_to(tuple);
}
PyObject* ComplexGeoDataPy::getFaces(PyObject *args)
{
double accuracy = 0.05;
if (!PyArg_ParseTuple(args, "d", &accuracy))
return nullptr;
std::vector<Base::Vector3d> points;
std::vector<Data::ComplexGeoData::Facet> facets;
try {
getComplexGeoDataPtr()->getFaces(points, facets, accuracy);
}
catch (...) {
PyErr_SetString(PyExc_RuntimeError, "failed to get sub-element from object");
return nullptr;
}
Py::Tuple tuple(2);
@@ -82,17 +251,76 @@ PyObject* ComplexGeoDataPy::getFacesFromSubelement(PyObject *args)
return Py::new_reference_to(tuple);
}
Py::Object ComplexGeoDataPy::getBoundBox(void) const
PyObject* ComplexGeoDataPy::applyTranslation(PyObject *args)
{
PyObject *obj;
if (!PyArg_ParseTuple(args, "O!", &(Base::VectorPy::Type),&obj))
return nullptr;
try {
Base::Vector3d move = static_cast<Base::VectorPy*>(obj)->value();
getComplexGeoDataPtr()->applyTranslation(move);
Py_Return;
}
catch (...) {
PyErr_SetString(PyExc_RuntimeError, "failed to apply rotation");
return nullptr;
}
}
PyObject* ComplexGeoDataPy::applyRotation(PyObject *args)
{
PyObject *obj;
if (!PyArg_ParseTuple(args, "O!", &(Base::RotationPy::Type),&obj))
return nullptr;
try {
Base::Rotation rot = static_cast<Base::RotationPy*>(obj)->value();
getComplexGeoDataPtr()->applyRotation(rot);
Py_Return;
}
catch (...) {
PyErr_SetString(PyExc_RuntimeError, "failed to apply rotation");
return nullptr;
}
}
PyObject* ComplexGeoDataPy::transformGeometry(PyObject *args)
{
PyObject *obj;
if (!PyArg_ParseTuple(args, "O!", &(Base::MatrixPy::Type),&obj))
return nullptr;
try {
Base::Matrix4D mat = static_cast<Base::MatrixPy*>(obj)->value();
getComplexGeoDataPtr()->transformGeometry(mat);
Py_Return;
}
catch (...) {
PyErr_SetString(PyExc_RuntimeError, "failed to transform geometry");
return nullptr;
}
}
Py::Object ComplexGeoDataPy::getBoundBox() const
{
return Py::BoundingBox(getComplexGeoDataPtr()->getBoundBox());
}
Py::Object ComplexGeoDataPy::getPlacement(void) const
Py::Object ComplexGeoDataPy::getCenterOfGravity() const
{
Base::Vector3d center;
if (getComplexGeoDataPtr()->getCenterOfGravity(center))
return Py::Vector(center);
throw Py::RuntimeError("Cannot get center of gravity");
}
Py::Object ComplexGeoDataPy::getPlacement() const
{
return Py::Placement(getComplexGeoDataPtr()->getPlacement());
}
void ComplexGeoDataPy::setPlacement(Py::Object arg)
void ComplexGeoDataPy::setPlacement(Py::Object arg)
{
PyObject* p = arg.ptr();
if (PyObject_TypeCheck(p, &(Base::PlacementPy::Type))) {
@@ -106,40 +334,40 @@ void ComplexGeoDataPy::setPlacement(Py::Object arg)
}
}
Py::Object ComplexGeoDataPy::getMatrix(void) const
Py::Int ComplexGeoDataPy::getTag() const
{
return Py::Matrix(getComplexGeoDataPtr()->getTransform());
}
// FIXME would be better to call it setTransform() as in all other interfaces...
void ComplexGeoDataPy::setMatrix(Py::Object arg)
{
PyObject* p = arg.ptr();
if (PyObject_TypeCheck(p, &(Base::MatrixPy::Type))) {
Base::Matrix4D mat = static_cast<Base::MatrixPy*>(p)->value();
getComplexGeoDataPtr()->setTransform(mat);
}
else {
std::string error = std::string("type must be 'Matrix', not ");
error += p->ob_type->tp_name;
throw Py::TypeError(error);
}
}
Py::Int ComplexGeoDataPy::getTag() const {
return Py::Int(getComplexGeoDataPtr()->Tag);
}
void ComplexGeoDataPy::setTag(Py::Int tag) {
void ComplexGeoDataPy::setTag(Py::Int tag)
{
getComplexGeoDataPtr()->Tag = tag;
}
PyObject *ComplexGeoDataPy::getCustomAttributes(const char* /*attr*/) const
PyObject* ComplexGeoDataPy::getCustomAttributes(const char* attr) const
{
return 0;
// Support for backward compatibility
if (strcmp(attr, "Matrix") == 0) {
Py::Matrix mat(getComplexGeoDataPtr()->getTransform());
return Py::new_reference_to(mat);
}
return nullptr;
}
int ComplexGeoDataPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
int ComplexGeoDataPy::setCustomAttributes(const char* attr, PyObject* obj)
{
// Support for backward compatibility
if (strcmp(attr, "Matrix") == 0) {
if (PyObject_TypeCheck(obj, &(Base::MatrixPy::Type))) {
Base::Matrix4D mat = static_cast<Base::MatrixPy*>(obj)->value();
getComplexGeoDataPtr()->setTransform(mat);
return 1;
}
else {
std::string error = std::string("type must be 'Matrix', not ");
error += obj->ob_type->tp_name;
throw Py::TypeError(error);
}
}
return 0;
}
+1 -1
View File
@@ -56,7 +56,7 @@ DEALINGS IN THE SOFTWARE.
<hr>
<h3><a name="_TocCoin3D"></a>Coin3D</h3>
<p>Web site: <a href="https://bitbucket.org/Coin3D/coin/">https://bitbucket.org/Coin3D/coin/</a></p>
<p>Web site: <a href="https://coin3d.github.io">https://coin3d.github.io</a></p>
<p>Copyright: Coin is copyright (C) 1998-2013 Kongsberg Oil & Gas Technologies AS</p>
<p>License: BSD-3-clause</p>
<pre>
+48 -1
View File
@@ -30,6 +30,7 @@
#include <Gui/Command.h>
#include <exception>
#include <type_traits>
#include <typeinfo>
#include <boost/format.hpp>
namespace Gui {
@@ -40,11 +41,24 @@ public:
static std::string str(const std::string& s) {
return s;
}
static std::string str(const char* s) {
return s;
}
static std::string str(const QString& s) {
return s.toStdString();
}
static std::string str(const std::stringstream& s) {
return s.str();
}
static std::string str(const std::ostringstream& s) {
return s.str();
}
static std::string str(const std::ostream& s) {
return dynamic_cast<const std::ostringstream&>(s).str();
if (typeid(s) == typeid(std::ostringstream))
return dynamic_cast<const std::ostringstream&>(s).str();
else if (typeid(s) == typeid(std::stringstream))
return dynamic_cast<const std::stringstream&>(s).str();
throw Base::TypeError("Not a std::stringstream or std::ostringstream");
}
static std::string toStr(boost::format& f) {
return f.str();
@@ -152,6 +166,39 @@ inline void cmdAppDocument(const App::DocumentObject* obj, T&& cmd) {
_cmdDocument(Gui::Command::Doc, obj, "App", std::forward<T>(cmd));
}
/** Runs a command for accessing a document's attribute or method
* @param doc: pointer to a Document
* @param cmd: command string, supporting printf like formatter
*
* Example:
* @code{.cpp}
* cmdAppDocumentArgs(obj, "addObject('%s')", "Part::Feature");
* @endcode
*
* Translates to command (assuming obj's document name is 'DocName':
* @code{.py}
* App.getDocument('DocName').addObject('Part::Feature')
* @endcode
*/
template<typename...Args>
void cmdAppDocumentArgs(const App::Document* doc, const std::string& cmd, Args&&... args) {
std::string _cmd;
try {
boost::format fmt(cmd);
_cmd = FormatString::toStr(fmt, std::forward<Args>(args)...);
Gui::Command::doCommand(Gui::Command::Doc,"App.getDocument('%s').%s",
doc->getName(), _cmd.c_str());
}
catch (const std::exception& e) {
Base::Console().Error("%s: %s\n", e.what(), cmd.c_str());
}
catch (const Base::Exception&) {
Base::Console().Error("App.getDocument('%s').%s\n",
doc->getName(), _cmd.c_str());
throw;
}
}
/** Runs a command for accessing an object's Gui::Document attribute or method
* This function is an alternative to FCMD_VOBJ_DOC_CMD
* @param obj: pointer to a DocumentObject
+1 -1
View File
@@ -2824,7 +2824,7 @@ static std::vector<std::string> getBoxSelection(
continue;
std::vector<Base::Vector3d> points;
std::vector<Data::ComplexGeoData::Line> lines;
data->getLinesFromSubelement(segment.get(),points,lines);
data->getLinesFromSubElement(segment.get(),points,lines);
if(lines.empty()) {
if(points.empty())
continue;
+13 -9
View File
@@ -633,24 +633,27 @@ bool MainWindow::closeAllDocuments (bool close)
auto docs = App::GetApplication().getDocuments();
try {
docs = App::Document::getDependentDocuments(docs, true);
}catch(Base::Exception &e) {
}
catch(Base::Exception &e) {
e.ReportException();
}
bool checkModify = true;
bool saveAll = false;
int failedSaves = 0;
for(auto doc : docs) {
for (auto doc : docs) {
auto gdoc = Application::Instance->getDocument(doc);
if(!gdoc)
if (!gdoc)
continue;
if(!gdoc->canClose(false))
if (!gdoc->canClose(false))
return false;
if(!gdoc->isModified()
if (!gdoc->isModified()
|| doc->testStatus(App::Document::PartialDoc)
|| doc->testStatus(App::Document::TempDoc))
continue;
bool save = saveAll;
if(!save && checkModify) {
if (!save && checkModify) {
int res = confirmSave(doc->Label.getStrValue().c_str(), this, docs.size()>1);
switch (res)
{
@@ -658,6 +661,7 @@ bool MainWindow::closeAllDocuments (bool close)
return false;
case ConfirmSaveResult::SaveAll:
saveAll = true;
/* FALLTHRU */
case ConfirmSaveResult::Save:
save = true;
break;
@@ -666,7 +670,7 @@ bool MainWindow::closeAllDocuments (bool close)
}
}
if(save && !gdoc->save())
if (save && !gdoc->save())
failedSaves++;
}
@@ -681,9 +685,9 @@ bool MainWindow::closeAllDocuments (bool close)
return false;
}
if(close)
if (close)
App::GetApplication().closeAllDocuments();
// d->mdiArea->closeAllSubWindows();
return true;
}
+2 -2
View File
@@ -505,14 +505,14 @@ void AboutDialog::showLibraryInformation()
// Coin3D
li.name = QLatin1String("Coin3D");
li.href = baseurl + QLatin1String("#_TocCoin3D");
li.url = QLatin1String("https://bitbucket.org/Coin3D/coin/");
li.url = QLatin1String("https://coin3d.github.io");
li.version = QLatin1String(COIN_VERSION);
libInfo << li;
// Eigen3
li.name = QLatin1String("Eigen3");
li.href = baseurl + QLatin1String("#_TocEigen3");
li.url = QLatin1String("http://eigen.tuxfamily.org/");
li.url = QLatin1String("http://eigen.tuxfamily.org");
li.version = QString::fromLatin1(FC_EIGEN3_VERSION);
libInfo << li;
+18
View File
@@ -250,6 +250,11 @@ void ToolBarManager::setup(ToolBarItem* toolBarItems)
(*it)->hide();
(*it)->toggleViewAction()->setVisible(false);
}
hPref = App::GetApplication().GetUserParameter().GetGroup("BaseApp")
->GetGroup("Preferences")->GetGroup("General");
bool lockToolBars = hPref->GetBool("LockToolBars", false);
setMovable(!lockToolBars);
}
void ToolBarManager::setup(ToolBarItem* item, QToolBar* toolbar) const
@@ -314,6 +319,12 @@ void ToolBarManager::restoreState() const
toolbar->setVisible(hPref->GetBool(toolbarName.constData(), toolbar->isVisible()));
}
}
hPref = App::GetApplication().GetUserParameter().GetGroup("BaseApp")
->GetGroup("Preferences")->GetGroup("General");
bool lockToolBars = hPref->GetBool("LockToolBars", false);
setMovable(!lockToolBars);
}
void ToolBarManager::retranslate() const
@@ -327,6 +338,13 @@ void ToolBarManager::retranslate() const
}
}
void Gui::ToolBarManager::setMovable(bool moveable) const
{
for (auto& tb : toolBars()) {
tb->setMovable(moveable);
}
}
QToolBar* ToolBarManager::findToolBar(const QList<QToolBar*>& toolbars, const QString& item) const
{
for (QList<QToolBar*>::ConstIterator it = toolbars.begin(); it != toolbars.end(); ++it) {
+2
View File
@@ -80,6 +80,8 @@ public:
void restoreState() const;
void retranslate() const;
void setMovable(bool movable) const;
protected:
void setup(ToolBarItem*, QToolBar*) const;
/** Returns a list of all currently existing toolbars. */
+29 -40
View File
@@ -26,6 +26,7 @@
# include <QAction>
# include <QColorDialog>
# include <QDesktopWidget>
# include <QDesktopServices>
# include <QDialogButtonBox>
# include <QDrag>
# include <QEventLoop>
@@ -594,6 +595,7 @@ struct ColorButtonP
bool allowChange;
bool autoChange;
bool drawFrame;
bool allowTransparency;
bool modal;
bool dirty;
@@ -602,6 +604,7 @@ struct ColorButtonP
, allowChange(true)
, autoChange(false)
, drawFrame(true)
, allowTransparency(false)
, modal(true)
, dirty(true)
{
@@ -671,6 +674,21 @@ bool ColorButton::drawFrame() const
return d->drawFrame;
}
void Gui::ColorButton::setAllowTransparency(bool allow)
{
d->allowTransparency = allow;
if (d->cd)
d->cd->setOption(QColorDialog::ColorDialogOption::ShowAlphaChannel, allow);
}
bool Gui::ColorButton::allowTransparency() const
{
if (d->cd)
return d->cd->testOption(QColorDialog::ColorDialogOption::ShowAlphaChannel);
else
return d->allowTransparency;
}
void ColorButton::setModal(bool b)
{
d->modal = b;
@@ -763,6 +781,7 @@ void ColorButton::onChooseColor()
QColor currentColor = d->col;
QColorDialog cd(d->col, this);
cd.setOptions(QColorDialog::DontUseNativeDialog);
cd.setOption(QColorDialog::ColorDialogOption::ShowAlphaChannel, d->allowTransparency);
if (d->autoChange) {
connect(&cd, SIGNAL(currentColorChanged(const QColor &)),
@@ -788,6 +807,7 @@ void ColorButton::onChooseColor()
d->old = d->col;
d->cd = new QColorDialog(d->col, this);
d->cd->setOptions(QColorDialog::DontUseNativeDialog);
d->cd->setOption(QColorDialog::ColorDialogOption::ShowAlphaChannel, d->allowTransparency);
d->cd->setAttribute(Qt::WA_DeleteOnClose);
connect(d->cd, SIGNAL(rejected()),
this, SLOT(onRejected()));
@@ -812,16 +832,15 @@ void ColorButton::onRejected()
// ------------------------------------------------------------------------------
UrlLabel::UrlLabel(QWidget * parent, Qt::WindowFlags f)
: QLabel(parent, f)
UrlLabel::UrlLabel(QWidget* parent, Qt::WindowFlags f)
: QLabel(parent, f)
, _url (QStringLiteral("http://localhost"))
, _launchExternal(true)
{
_url = QString::fromLatin1("http://localhost");
setToolTip(this->_url);
if (qApp->styleSheet().isEmpty()) {
setStyleSheet(QString::fromLatin1("Gui--UrlLabel {color: #0000FF;text-decoration: underline;}"));
}
setToolTip(this->_url);
setCursor(Qt::PointingHandCursor);
if (qApp->styleSheet().isEmpty())
setStyleSheet(QStringLiteral("Gui--UrlLabel {color: #0000FF;text-decoration: underline;}"));
}
UrlLabel::~UrlLabel()
@@ -833,40 +852,10 @@ void Gui::UrlLabel::setLaunchExternal(bool l)
_launchExternal = l;
}
void UrlLabel::enterEvent ( QEvent * )
{
setCursor(Qt::PointingHandCursor);
}
void UrlLabel::leaveEvent ( QEvent * )
{
setCursor(Qt::ArrowCursor);
}
void UrlLabel::mouseReleaseEvent (QMouseEvent *)
void UrlLabel::mouseReleaseEvent(QMouseEvent*)
{
if (_launchExternal) {
// The webbrowser Python module allows to start the system browser in an OS-independent way
Base::PyGILStateLocker lock;
PyObject* module = PyImport_ImportModule("webbrowser");
if (module) {
// get the methods dictionary and search for the 'open' method
PyObject* dict = PyModule_GetDict(module);
PyObject* func = PyDict_GetItemString(dict, "open");
if (func) {
PyObject* args = Py_BuildValue("(s)", (const char*)this->_url.toLatin1());
#if PY_VERSION_HEX < 0x03090000
PyObject* result = PyEval_CallObject(func, args);
#else
PyObject* result = PyObject_CallObject(func, args);
#endif
// decrement the args and module reference
Py_XDECREF(result);
Py_DECREF(args);
Py_DECREF(module);
}
}
}
QDesktopServices::openUrl(this->_url);
else {
// Someone else will deal with it...
Q_EMIT linkClicked(_url);
+4 -2
View File
@@ -203,6 +203,7 @@ class GuiExport ColorButton : public QPushButton
Q_PROPERTY( QColor color READ color WRITE setColor )
Q_PROPERTY( bool allowChangeColor READ allowChangeColor WRITE setAllowChangeColor )
Q_PROPERTY( bool drawFrame READ drawFrame WRITE setDrawFrame )
Q_PROPERTY( bool allowTransparency READ allowTransparency WRITE setAllowTransparency)
public:
ColorButton(QWidget* parent = 0);
@@ -217,6 +218,9 @@ public:
void setDrawFrame(bool);
bool drawFrame() const;
void setAllowTransparency(bool);
bool allowTransparency() const;
void setModal(bool);
bool isModal() const;
@@ -272,8 +276,6 @@ public Q_SLOTS:
void setLaunchExternal(bool l);
protected:
void enterEvent ( QEvent * );
void leaveEvent ( QEvent * );
void mouseReleaseEvent ( QMouseEvent * );
private:
+1 -1
View File
@@ -562,7 +562,7 @@ void StdWorkbench::setupContextMenu(const char* recipient, MenuItem* item) const
*item << "Separator" << "Std_SetAppearance" << "Std_ToggleVisibility"
<< "Std_ToggleSelectability" << "Std_TreeSelection"
<< "Std_RandomColor" << "Separator" << "Std_Delete"
<< "Std_SendToPythonConsole";
<< "Std_SendToPythonConsole" << "Std_TransformManip";
}
}
else if (strcmp(recipient,"Tree") == 0)
+5 -2
View File
@@ -200,11 +200,14 @@ class CommandAddonManager:
m.setWindowIcon(QtGui.QIcon(":/icons/AddonManager.svg"))
m.setText(translate("AddonsInstaller",
"You must restart FreeCAD for changes to take "
"effect. Press Ok to restart FreeCAD now, or "
"Cancel to restart later."))
"effect."))
m.setIcon(m.Warning)
m.setStandardButtons(m.Ok | m.Cancel)
m.setDefaultButton(m.Cancel)
okBtn = m.button(QtGui.QMessageBox.StandardButton.Ok)
cancelBtn = m.button(QtGui.QMessageBox.StandardButton.Cancel)
okBtn.setText(translate("AddonsInstaller","Restart now"))
cancelBtn.setText(translate("AddonsInstaller","Restart later"))
ret = m.exec_()
if ret == m.Ok:
shutil.rmtree(self.macro_repo_dir, onerror=self.remove_readonly)
+107 -46
View File
@@ -51,37 +51,83 @@ class ArchWorkbench(FreeCADGui.Workbench):
import Draft_rc
import DraftTools
import DraftGui
from draftguitools import gui_circulararray
from draftguitools import gui_polararray
from draftguitools import gui_orthoarray
from draftguitools import gui_arrays
import Arch_rc
import Arch
from ArchStructure import _ArchStructureGroupCommand
from ArchAxis import _ArchAxisGroupCommand
from ArchPanel import CommandPanelGroup
from ArchMaterial import _ArchMaterialToolsCommand
from ArchPipe import _ArchPipeGroupCommand
stru_group = _ArchStructureGroupCommand
axis_group = _ArchAxisGroupCommand
pan_group = CommandPanelGroup
mat_group = _ArchMaterialToolsCommand
pipe_group = _ArchPipeGroupCommand
# Set up command lists
self.archtools = ["Arch_Wall", "Arch_StructureTools", "Arch_Rebar",
"Arch_CurtainWall","Arch_BuildingPart",
"Arch_Project", "Arch_Site", "Arch_Building",
"Arch_Floor", "Arch_Reference",
"Arch_Window", "Arch_Roof", "Arch_AxisTools",
"Arch_SectionPlane", "Arch_Space", "Arch_Stairs",
"Arch_PanelTools", "Arch_Equipment",
"Arch_Frame", "Arch_Fence", "Arch_Truss",
"Arch_Profile","Arch_MaterialTools",
"Arch_Schedule", "Arch_PipeTools",
"Arch_CutPlane", "Arch_CutLine",
"Arch_Add", "Arch_Remove", "Arch_Survey"]
self.utilities = ["Arch_Component", "Arch_CloneComponent",
"Arch_SplitMesh", "Arch_MeshToShape",
"Arch_SelectNonSolidMeshes", "Arch_RemoveShape",
"Arch_CloseHoles", "Arch_MergeWalls", "Arch_Check",
"Arch_ToggleIfcBrepFlag", "Arch_3Views",
"Arch_IfcSpreadsheet", "Arch_ToggleSubs"]
self.archtools = ["Arch_Wall",
([QT_TRANSLATE_NOOP("Arch", "Structure tools")],
list(stru_group.GetCommands(stru_group))), # tuple len=2: submenu
("Arch_StructureTools", ), # tuple len=1: toolbar flyout
"Arch_Rebar_Submenu", # will be replaced or removed
"Arch_Rebar", # may be replaced
"Arch_CurtainWall",
"Arch_BuildingPart",
"Arch_Project",
"Arch_Site",
"Arch_Building",
"Arch_Floor",
"Arch_Reference",
"Arch_Window",
"Arch_Roof",
([QT_TRANSLATE_NOOP("Arch", "Axis tools")],
list(axis_group.GetCommands(axis_group))),
("Arch_AxisTools", ),
"Arch_SectionPlane",
"Arch_Space",
"Arch_Stairs",
([QT_TRANSLATE_NOOP("Arch", "Panel tools")],
list(pan_group.GetCommands(pan_group))),
("Arch_PanelTools", ),
"Arch_Equipment",
"Arch_Frame",
"Arch_Fence",
"Arch_Truss",
"Arch_Profile",
([QT_TRANSLATE_NOOP("Arch", "Material tools")],
list(mat_group.GetCommands(mat_group))),
("Arch_MaterialTools", ),
"Arch_Schedule",
([QT_TRANSLATE_NOOP("Arch", "Pipe tools")],
list(pipe_group.GetCommands(pipe_group))),
("Arch_PipeTools", ),
"Arch_CutPlane",
"Arch_CutLine",
"Arch_Add",
"Arch_Remove",
"Arch_Survey"]
self.utilities = ["Arch_Component",
"Arch_CloneComponent",
"Arch_SplitMesh",
"Arch_MeshToShape",
"Arch_SelectNonSolidMeshes",
"Arch_RemoveShape",
"Arch_CloseHoles",
"Arch_MergeWalls",
"Arch_Check",
"Arch_ToggleIfcBrepFlag",
"Arch_3Views",
"Arch_IfcSpreadsheet",
"Arch_ToggleSubs"]
# Add the rebar tools from the Reinforcement addon, if available
try:
import RebarTools
except Exception:
del self.archtools[3] # remove "Arch_Rebar_Submenu"
pass
else:
class RebarGroupCommand:
@@ -97,42 +143,57 @@ class ArchWorkbench(FreeCADGui.Workbench):
def IsActive(self):
return not FreeCAD.ActiveDocument is None
FreeCADGui.addCommand('Arch_RebarTools', RebarGroupCommand())
self.archtools[2] = "Arch_RebarTools"
self.archtools[3] = ([QT_TRANSLATE_NOOP("Arch", "Rebar tools")],
RebarTools.RebarCommands + ["Arch_Rebar"])
self.archtools[4] = ("Arch_RebarTools", )
# Set up Draft command lists
import draftutils.init_tools as it
self.draft_drawing_commands = it.get_draft_drawing_commands()
self.draft_annotation_commands = it.get_draft_annotation_commands()
self.draft_modification_commands = it.get_draft_modification_commands()
self.draft_utility_commands = it.get_draft_utility_commands_menu()
self.draft_context_commands = it.get_draft_context_commands()
self.draft_line_commands = it.get_draft_line_commands()
self.draft_utility_commands = it.get_draft_utility_commands()
# Set up toolbars
self.appendToolbar(QT_TRANSLATE_NOOP("Workbench", "Arch tools"), self.archtools)
self.appendToolbar(QT_TRANSLATE_NOOP("Draft", "Draft creation tools"), self.draft_drawing_commands)
self.appendToolbar(QT_TRANSLATE_NOOP("Draft", "Draft annotation tools"), self.draft_annotation_commands)
self.appendToolbar(QT_TRANSLATE_NOOP("Draft", "Draft modification tools"), self.draft_modification_commands)
it.init_toolbar(self,
QT_TRANSLATE_NOOP("Workbench", "Arch tools"),
self.archtools)
it.init_toolbar(self,
QT_TRANSLATE_NOOP("Draft", "Draft creation tools"),
self.draft_drawing_commands)
it.init_toolbar(self,
QT_TRANSLATE_NOOP("Draft", "Draft annotation tools"),
self.draft_annotation_commands)
it.init_toolbar(self,
QT_TRANSLATE_NOOP("Draft", "Draft modification tools"),
self.draft_modification_commands)
# Set up menus
self.appendMenu([QT_TRANSLATE_NOOP("arch", "&Arch"),
QT_TRANSLATE_NOOP("arch", "Utilities")],
self.utilities)
self.appendMenu(QT_TRANSLATE_NOOP("arch", "&Arch"), self.archtools)
it.init_menu(self,
[QT_TRANSLATE_NOOP("Arch", "&Arch"),
QT_TRANSLATE_NOOP("Arch", "Utilities")],
self.utilities)
it.init_menu(self,
[QT_TRANSLATE_NOOP("Arch", "&Arch")],
self.archtools)
it.init_menu(self,
[QT_TRANSLATE_NOOP("Arch", "&Draft"),
QT_TRANSLATE_NOOP("Arch", "Creation")],
self.draft_drawing_commands)
it.init_menu(self,
[QT_TRANSLATE_NOOP("Arch", "&Draft"),
QT_TRANSLATE_NOOP("Arch", "Annotation")],
self.draft_annotation_commands)
it.init_menu(self,
[QT_TRANSLATE_NOOP("Arch", "&Draft"),
QT_TRANSLATE_NOOP("Arch", "Modification")],
self.draft_modification_commands)
it.init_menu(self,
[QT_TRANSLATE_NOOP("Arch", "&Draft"),
QT_TRANSLATE_NOOP("Arch", "Utilities")],
self.draft_utility_commands)
self.appendMenu([QT_TRANSLATE_NOOP("arch", "&Draft"),
QT_TRANSLATE_NOOP("arch", "Creation")],
self.draft_drawing_commands)
self.appendMenu([QT_TRANSLATE_NOOP("arch", "&Draft"),
QT_TRANSLATE_NOOP("arch", "Annotation")],
self.draft_annotation_commands)
self.appendMenu([QT_TRANSLATE_NOOP("arch", "&Draft"),
QT_TRANSLATE_NOOP("arch", "Modification")],
self.draft_modification_commands)
self.appendMenu([QT_TRANSLATE_NOOP("arch", "&Draft"),
QT_TRANSLATE_NOOP("arch", "Utilities")],
self.draft_utility_commands
+ self.draft_context_commands)
FreeCADGui.addIconPath(":/icons")
FreeCADGui.addLanguagePath(":/translations")
@@ -110,7 +110,7 @@ namespace dcm {
* @{ */
/**
* @brief Exeption for property errors
* @brief Exception for property errors
*
* This exception is thrown when a property related error is detected, for example if a objects is ask for a
* property which it does not own. This exceptions own the error-code range from 300-399.
+3 -3
View File
@@ -422,9 +422,9 @@ if App.GuiUp:
from draftviewproviders.view_text import (ViewProviderText,
ViewProviderDraftText)
from draftobjects.hatch import (Draft_Hatch_Object)
from draftmake.make_hatch import (make_hatch, makeHatch)
from draftobjects.hatch import (Hatch)
from draftmake.make_hatch import (make_hatch)
if App.GuiUp:
from draftviewproviders.view_hatch import (Draft_Hatch_ViewProvider)
from draftviewproviders.view_hatch import (ViewProviderDraftHatch)
## @}
+26 -10
View File
@@ -95,22 +95,38 @@ class DraftWorkbench(FreeCADGui.Workbench):
self.drawing_commands = it.get_draft_drawing_commands()
self.annotation_commands = it.get_draft_annotation_commands()
self.modification_commands = it.get_draft_modification_commands()
self.utility_commands_menu = it.get_draft_utility_commands_menu()
self.utility_commands_toolbar = it.get_draft_utility_commands_toolbar()
self.context_commands = it.get_draft_context_commands()
self.line_commands = it.get_draft_line_commands()
self.utility_commands = it.get_draft_utility_commands()
self.utility_small = it.get_draft_small_commands()
# Set up toolbars
self.appendToolbar(QT_TRANSLATE_NOOP("Draft", "Draft creation tools"), self.drawing_commands)
self.appendToolbar(QT_TRANSLATE_NOOP("Draft", "Draft annotation tools"), self.annotation_commands)
self.appendToolbar(QT_TRANSLATE_NOOP("Draft", "Draft modification tools"), self.modification_commands)
self.appendToolbar(QT_TRANSLATE_NOOP("Draft", "Draft utility tools"), self.utility_small)
it.init_toolbar(self,
QT_TRANSLATE_NOOP("Draft", "Draft creation tools"),
self.drawing_commands)
it.init_toolbar(self,
QT_TRANSLATE_NOOP("Draft", "Draft annotation tools"),
self.annotation_commands)
it.init_toolbar(self,
QT_TRANSLATE_NOOP("Draft", "Draft modification tools"),
self.modification_commands)
it.init_toolbar(self,
QT_TRANSLATE_NOOP("Draft", "Draft utility tools"),
self.utility_commands_toolbar)
# Set up menus
self.appendMenu(QT_TRANSLATE_NOOP("Draft", "&Drafting"), self.drawing_commands)
self.appendMenu(QT_TRANSLATE_NOOP("Draft", "&Annotation"), self.annotation_commands)
self.appendMenu(QT_TRANSLATE_NOOP("Draft", "&Modification"), self.modification_commands)
self.appendMenu(QT_TRANSLATE_NOOP("Draft", "&Utilities"), self.utility_commands + self.context_commands)
it.init_menu(self,
[QT_TRANSLATE_NOOP("Draft", "&Drafting")],
self.drawing_commands)
it.init_menu(self,
[QT_TRANSLATE_NOOP("Draft", "&Annotation")],
self.annotation_commands)
it.init_menu(self,
[QT_TRANSLATE_NOOP("Draft", "&Modification")],
self.modification_commands)
it.init_menu(self,
[QT_TRANSLATE_NOOP("Draft", "&Utilities")],
self.utility_commands_menu)
# Set up preferences pages
if hasattr(FreeCADGui, "draftToolBar"):
@@ -17,7 +17,16 @@
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item>
@@ -252,9 +261,9 @@
</layout>
</item>
</layout>
<zorder/>
<zorder/>
<zorder/>
<zorder></zorder>
<zorder></zorder>
<zorder></zorder>
</widget>
</item>
<item>
@@ -323,6 +332,25 @@
</property>
</widget>
</item>
<item>
<widget class="Gui::PrefCheckBox" name="checkBox_3">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If checked, the outline of a human figure is displayed at the bottom left corner of the grid. This option is only effective if the BIM workbench is installed and if &amp;quot;Show grid border&amp;quot; option is enabled.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Show human figure</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>gridShowHuman</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Draft</cstring>
</property>
</widget>
</item>
<item>
<widget class="Gui::PrefCheckBox" name="checkBox_2">
<property name="toolTip">
@@ -525,7 +553,7 @@
<property name="toolTip">
<string>The color of the grid</string>
</property>
<property name="color">
<property name="color" stdset="0">
<color>
<red>50</red>
<green>50</green>
@@ -572,7 +600,16 @@
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_16" stretch="0,0,0">
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -618,22 +655,31 @@
<property name="value">
<number>5</number>
</property>
<property name="displayIntegerBase">
<number>10</number>
</property>
<property name="prefEntry" stdset="0">
<cstring>DraftEditMaxObjects</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Draft</cstring>
</property>
<property name="displayIntegerBase" stdset="0">
<number>10</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,0,0">
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
+5 -4
View File
@@ -25,10 +25,11 @@
import os
import FreeCAD
import draftguitools.gui_base as gui_base
from draftutils.translate import translate, QT_TRANSLATE_NOOP
class Draft_Hatch:
class Draft_Hatch(gui_base.GuiCommandSimplest):
def GetResources(self):
@@ -36,7 +37,7 @@ class Draft_Hatch:
return {'Pixmap' : "Draft_Hatch",
'MenuText': QT_TRANSLATE_NOOP("Draft_Hatch", "Hatch"),
'Accel': "H, A",
'ToolTip' : QT_TRANSLATE_NOOP("Draft_Hatch", "Create hatches on selected faces")}
'ToolTip' : QT_TRANSLATE_NOOP("Draft_Hatch", "Creates hatches on the faces of a selected object")}
def Activated(self):
@@ -89,7 +90,7 @@ class Draft_Hatch_TaskPanel:
# create new hatch object
FreeCAD.ActiveDocument.openTransaction("Create Hatch")
FreeCADGui.addModule("Draft")
cmd = "Draft.makeHatch("
cmd = "Draft.make_hatch("
cmd += "baseobject=FreeCAD.ActiveDocument.getObject(\""+self.baseobj.Name
cmd += "\"),filename=\""+self.form.File.property("fileName")
cmd += "\",pattern=\""+self.form.Pattern.currentText()
@@ -125,7 +125,7 @@ class Rectangle(gui_base_original.Creator):
self.commit(translate("draft", "Create Plane"),
_cmd_list)
else:
_cmd = 'Draft.makeRectangle'
_cmd = 'Draft.make_rectangle'
_cmd += '('
_cmd += 'length=' + str(length) + ', '
_cmd += 'height=' + str(height) + ', '
+8 -2
View File
@@ -85,6 +85,9 @@ class Text(gui_base_original.Creator):
def createObject(self):
"""Create the actual object in the current document."""
rot, sup, pts, fil = self.getStrings()
base = pts[1:-1]
text_list = self.text
text_list = [text.replace("\"","\\\"") for text in text_list]
@@ -108,9 +111,12 @@ class Text(gui_base_original.Creator):
_cmd = 'Draft.make_text'
_cmd += '('
_cmd += string + ', '
_cmd += 'placement=' + DraftVecUtils.toString(self.node[0])
_cmd += 'placement=pl'
_cmd += ')'
_cmd_list = ['_text_ = ' + _cmd,
_cmd_list = ['pl = FreeCAD.Placement()',
'pl.Rotation.Q = ' + rot,
'pl.Base = ' + base,
'_text_ = ' + _cmd,
'Draft.autogroup(_text_)',
'FreeCAD.ActiveDocument.recompute()']
self.commit(translate("draft", "Create Text"),
+39 -11
View File
@@ -1009,6 +1009,13 @@ class gridTracker(Tracker):
self.coords2 = coin.SoCoordinate3()
self.lines2 = coin.SoLineSet() # big squares
# human figure
mat_human = coin.SoMaterial()
mat_human.transparency.setValue(0.3*(1-gtrans))
mat_human.diffuseColor.setValue(col)
self.coords_human = coin.SoCoordinate3()
self.human = coin.SoLineSet()
# axes
mat3 = coin.SoMaterial()
mat3.transparency.setValue(gtrans)
@@ -1030,6 +1037,9 @@ class gridTracker(Tracker):
s.addChild(mat2)
s.addChild(self.coords2)
s.addChild(self.lines2)
s.addChild(mat_human)
s.addChild(self.coords_human)
s.addChild(self.human)
s.addChild(mbind3)
s.addChild(mat3)
s.addChild(self.coords3)
@@ -1105,17 +1115,6 @@ class gridTracker(Tracker):
self.text2.string = txt
self.textpos1.translation.setValue((-bound+self.space,-border+self.space,z))
self.textpos2.translation.setValue((-bound-self.space,-bound+self.space,z))
# human from BIM workbench
loc = FreeCAD.Vector(-bound+self.space/2,-bound+self.space/2,0)
try:
import BimProject
hpts = BimProject.getHuman(loc)
except Exception:
# BIM not installed
pass
else:
mpts.extend([tuple(p) for p in hpts])
midx.append(len(hpts))
else:
self.text1.string = " "
self.text2.string = " "
@@ -1130,8 +1129,36 @@ class gridTracker(Tracker):
self.coords3.point.setValues(apts)
#self.lines3.numVertices.setValues(aidx)
self.pts = pts
self.displayHumanFigure()
self.setAxesColor()
def displayHumanFigure(self):
""" Display the human figure at the grid corner.
The silhouette is displayed only if:
- BIM Workbench is available;
- preference BaseApp/Preferences/Mod/Draft/gridShowHuman is True;
- the working plane normal is vertical.
"""
numlines = self.numlines // self.mainlines // 2 * 2 * self.mainlines
bound = (numlines // 2) * self.space
pts = []
pidx = []
param = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
if param.GetBool("gridShowHuman", True) and \
FreeCAD.DraftWorkingPlane.axis.getAngle(FreeCAD.Vector(0,0,1)) < 0.001:
try:
import BimProject
loc = FreeCAD.Vector(-bound+self.space/2,-bound+self.space/2,0)
hpts = BimProject.getHuman(loc)
pts.extend([tuple(p) for p in hpts])
pidx.append(len(hpts))
except Exception:
# BIM not installed
return
self.human.numVertices.deleteValues(0)
self.coords_human.point.setValues(pts)
self.human.numVertices.setValues(pidx)
def setAxesColor(self):
"""set axes color"""
cols = [0,0]
@@ -1180,6 +1207,7 @@ class gridTracker(Tracker):
P = FreeCAD.DraftWorkingPlane.position
self.trans.rotation.setValue([Q[0], Q[1], Q[2], Q[3]])
self.trans.translation.setValue([P.x, P.y, P.z])
self.displayHumanFigure()
self.setAxesColor()
self.on()
+1 -1
View File
@@ -36,7 +36,7 @@ if App.GuiUp:
from draftviewproviders.view_base import ViewProviderDraft
def make_ellipse(majradius, minradius, placement=None, face=True, support=None):
def make_ellipse(majradius, minradius, placement=None, face=None, support=None):
"""make_ellipse(majradius, minradius, [placement], [face], [support])
Makes an ellipse with the given major and minor radius, and optionally
+6 -8
View File
@@ -23,12 +23,12 @@
"""This module contains FreeCAD commands for the Draft workbench"""
import FreeCAD
from draftobjects.hatch import Draft_Hatch_Object
from draftviewproviders.view_hatch import Draft_Hatch_ViewProvider
from draftobjects.hatch import Hatch
from draftviewproviders.view_hatch import ViewProviderDraftHatch
def makeHatch(baseobject, filename, pattern, scale, rotation):
def make_hatch(baseobject, filename, pattern, scale, rotation):
"""makeHatch(baseobject, filename, pattern, scale, rotation): Creates and returns a
"""make_hatch(baseobject, filename, pattern, scale, rotation): Creates and returns a
hatch object made by applying the given pattern of the given PAT file to the faces of
the given base object. Given scale and rotation factors are applied to the hatch object.
The result is a Part-based object created in the active document."""
@@ -36,13 +36,11 @@ def makeHatch(baseobject, filename, pattern, scale, rotation):
if not FreeCAD.ActiveDocument:
return
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Hatch")
Draft_Hatch_Object(obj)
Hatch(obj)
obj.Base = baseobject
obj.File = filename
obj.Pattern = pattern
obj.Scale = scale
obj.Rotation = rotation
if FreeCAD.GuiUp:
Draft_Hatch_ViewProvider(obj.ViewObject)
make_hatch = makeHatch
ViewProviderDraftHatch(obj.ViewObject)
+23 -22
View File
@@ -30,7 +30,7 @@ from draftutils.translate import translate, QT_TRANSLATE_NOOP
class Draft_Hatch_Object:
class Hatch:
def __init__(self,obj):
@@ -41,12 +41,6 @@ class Draft_Hatch_Object:
def setProperties(self,obj):
pl = obj.PropertiesList
if not "Placement" in pl:
obj.addProperty("App::PropertyPlacement","Placement","Hatch",
QT_TRANSLATE_NOOP("App::Property","The placement of this object"))
if not "Shape" in pl:
obj.addProperty("Part::PropertyPartShape","Shape","Hatch",
QT_TRANSLATE_NOOP("App::Property","The shape of this object"))
if not "Base" in pl:
obj.addProperty("App::PropertyLink","Base","Hatch",
QT_TRANSLATE_NOOP("App::Property","The base object used by this object"))
@@ -103,23 +97,30 @@ class Draft_Hatch_Object:
pla = obj.Placement
shapes = []
for face in obj.Base.Shape.Faces:
face = face.copy()
if obj.Translate:
bpoint = face.CenterOfMass
norm = face.normalAt(0,0)
fpla = FreeCAD.Placement(bpoint,FreeCAD.Rotation(FreeCAD.Vector(0,0,1),norm))
face.Placement = face.Placement.multiply(fpla.inverse())
if obj.Rotation:
face.rotate(FreeCAD.Vector(),FreeCAD.Vector(0,0,1),obj.Rotation)
shape = TechDraw.makeGeomHatch(face,obj.Scale,obj.Pattern,obj.File)
if obj.Rotation:
shape.rotate(FreeCAD.Vector(),FreeCAD.Vector(0,0,1),-obj.Rotation)
if obj.Translate:
shape.Placement = shape.Placement.multiply(fpla)
shapes.append(shape)
if face.findPlane(): # Only planar faces.
face = face.copy()
if obj.Translate:
e = face.Edges[0] # Todo: check for almost zero-length edge.
sta = e.firstVertex().Point
end = e.lastVertex().Point
u = end.sub(sta).normalize()
w = face.normalAt(0, 0)
v = w.cross(u)
m = FreeCAD.Matrix(u.x, v.x, w.x, sta.x,
u.y, v.y, w.y, sta.y,
u.z, v.z, w.z, sta.z,
0.0, 0.0, 0.0, 1.0)
face = face.transformGeometry(m.inverse()).Faces[0]
if obj.Rotation.Value:
face.rotate(FreeCAD.Vector(), FreeCAD.Vector(0,0,1), -obj.Rotation)
shape = TechDraw.makeGeomHatch(face, obj.Scale, obj.Pattern, obj.File)
if obj.Rotation.Value:
shape.rotate(FreeCAD.Vector(), FreeCAD.Vector(0,0,1), obj.Rotation)
if obj.Translate:
shape = shape.transformGeometry(m)
shapes.append(shape)
if shapes:
obj.Shape = Part.makeCompound(shapes)
obj.Placement = pla
def getPatterns(self,filename):
+152 -104
View File
@@ -1,5 +1,6 @@
# ***************************************************************************
# * (c) 2020 Eliud Cabrera Castillo <[email protected]> *
# * Copyright (c) 2020 Eliud Cabrera Castillo <[email protected]> *
# * Copyright (c) 2021 FreeCAD Developers *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
@@ -20,13 +21,9 @@
# * USA *
# * *
# ***************************************************************************
"""Provides lists of commands in order to set up toolbars of the workbench.
This module returns lists of commands, so that the toolbars
can be initialized by Draft, and by other workbenches.
These commands should be defined in `DraftTools`, and in the individual
modules in `draftguitools`.
"""
"""Provides functions and lists of commands to set up Draft menus and toolbars."""
## @package init_tools
# \ingroup draftutils
# \brief Provides lists of commands to set up toolbars of the workbench.
@@ -40,137 +37,188 @@ from PySide.QtCore import QT_TRANSLATE_NOOP
def get_draft_drawing_commands():
"""Return the drawing commands list."""
return ["Draft_Line", "Draft_Wire", "Draft_Fillet",
"Draft_ArcTools",
"Draft_Circle", "Draft_Ellipse", "Draft_Rectangle",
"Draft_Polygon", "Draft_BSpline", "Draft_BezierTools",
"Draft_Point", "Draft_Facebinder",
"Draft_ShapeString","Draft_Hatch"]
from draftguitools import gui_arcs
from draftguitools import gui_beziers
arc_group = gui_arcs.ArcGroup
bez_group = gui_beziers.BezierGroup
return ["Draft_Line",
"Draft_Wire",
"Draft_Fillet",
([QT_TRANSLATE_NOOP("Draft", "Arc tools")],
list(arc_group.GetCommands(arc_group))), # tuple len=2: submenu
("Draft_ArcTools", ), # tuple len=1: toolbar flyout
"Draft_Circle",
"Draft_Ellipse",
"Draft_Rectangle",
"Draft_Polygon",
"Draft_BSpline",
([QT_TRANSLATE_NOOP("Draft", "Bezier tools")],
list(bez_group.GetCommands(bez_group))),
("Draft_BezierTools", ),
"Draft_Point",
"Draft_Facebinder",
"Draft_ShapeString",
"Draft_Hatch"]
def get_draft_annotation_commands():
"""Return the annotation commands list."""
return ["Draft_Text", "Draft_Dimension",
"Draft_Label", "Draft_AnnotationStyleEditor"]
def get_draft_array_commands():
"""Return the array commands list."""
return ["Draft_ArrayTools"]
def get_draft_small_commands():
"""Return a list with only some utilities."""
return ["Draft_Layer",
"Draft_WorkingPlaneProxy",
"Draft_ToggleDisplayMode",
"Draft_AddNamedGroup",
"Draft_AddToGroup",
"Draft_SelectGroup",
"Draft_AddConstruction"]
return ["Draft_Text",
"Draft_Dimension",
"Draft_Label",
"Draft_AnnotationStyleEditor"]
def get_draft_modification_commands():
"""Return the modification commands list."""
lst = ["Draft_Move", "Draft_Rotate",
"Draft_Scale", "Draft_Mirror",
"Draft_Offset", "Draft_Trimex",
"Draft_Stretch",
"Separator",
"Draft_Clone"]
lst += get_draft_array_commands()
lst += ["Separator",
"Draft_Edit", "Draft_SubelementHighlight",
from draftguitools import gui_arrays
arr_group = gui_arrays.ArrayGroup
return ["Draft_Move",
"Draft_Rotate",
"Draft_Scale",
"Draft_Mirror",
"Draft_Offset",
"Draft_Trimex",
"Draft_Stretch",
"Separator",
"Draft_Join", "Draft_Split",
"Draft_Upgrade", "Draft_Downgrade",
"Draft_Clone",
([QT_TRANSLATE_NOOP("Draft", "Array tools")],
list(arr_group.GetCommands(arr_group))), # tuple len=2: submenu
("Draft_ArrayTools", ), # tuple len=1: toolbar flyout
"Separator",
"Draft_WireToBSpline", "Draft_Draft2Sketch",
"Draft_Slope", "Draft_FlipDimension",
"Draft_Edit",
"Draft_SubelementHighlight",
"Separator",
"Draft_Join",
"Draft_Split",
"Draft_Upgrade",
"Draft_Downgrade",
"Separator",
"Draft_WireToBSpline",
"Draft_Draft2Sketch",
"Draft_Slope",
"Draft_FlipDimension",
"Separator",
"Draft_Shape2DView"]
return lst
def get_draft_context_commands():
"""Return the context menu commands list."""
return ["Draft_ApplyStyle", "Draft_ToggleDisplayMode",
"Draft_AddNamedGroup", "Draft_AddToGroup", "Draft_SelectGroup",
"Draft_SelectPlane", "Draft_ShowSnapBar",
"Draft_ToggleGrid", "Draft_SetStyle"]
def get_draft_line_commands():
"""Return the line commands list."""
return ["Draft_UndoLine", "Draft_FinishLine",
"Draft_CloseLine"]
def get_draft_utility_commands():
"""Return the utility commands list."""
return ["Draft_Layer",
"Draft_Heal",
def get_draft_utility_commands_menu():
"""Return the utility commands list for the menu."""
return ["Draft_SetStyle",
"Draft_ApplyStyle",
"Separator",
"Draft_Layer",
"Draft_AddNamedGroup",
"Draft_AddToGroup",
"Draft_SelectGroup",
"Draft_ToggleConstructionMode",
"Draft_ToggleContinueMode",
"Draft_AddConstruction",
"Separator",
"Draft_ToggleDisplayMode",
"Draft_ToggleGrid",
"Draft_SelectPlane",
"Draft_WorkingPlaneProxy",
"Draft_AddConstruction"]
"Separator",
"Draft_Heal",
"Draft_ToggleContinueMode",
"Draft_ShowSnapBar"]
def get_draft_utility_commands_toolbar():
"""Return the utility commands list for the toolbar."""
return ["Draft_Layer",
"Draft_AddNamedGroup",
"Draft_AddToGroup",
"Draft_SelectGroup",
"Draft_AddConstruction",
"Draft_ToggleDisplayMode",
"Draft_WorkingPlaneProxy"]
def get_draft_snap_commands():
"""Return the snapping commands list."""
return ['Draft_Snap_Lock',
'Draft_Snap_Endpoint', 'Draft_Snap_Midpoint',
'Draft_Snap_Center', 'Draft_Snap_Angle',
'Draft_Snap_Intersection', 'Draft_Snap_Perpendicular',
'Draft_Snap_Extension', 'Draft_Snap_Parallel',
'Draft_Snap_Special', 'Draft_Snap_Near',
'Draft_Snap_Ortho', 'Draft_Snap_Grid',
'Draft_Snap_WorkingPlane', 'Draft_Snap_Dimensions',
'Separator', 'Draft_ToggleGrid'
]
'Draft_Snap_Endpoint',
'Draft_Snap_Midpoint',
'Draft_Snap_Center',
'Draft_Snap_Angle',
'Draft_Snap_Intersection',
'Draft_Snap_Perpendicular',
'Draft_Snap_Extension',
'Draft_Snap_Parallel',
'Draft_Snap_Special',
'Draft_Snap_Near',
'Draft_Snap_Ortho',
'Draft_Snap_Grid',
'Draft_Snap_WorkingPlane',
'Draft_Snap_Dimensions',
'Separator', 'Draft_ToggleGrid']
def init_draft_toolbars(workbench):
"""Initialize the Draft toolbars.
def get_draft_context_commands():
"""Return the context menu commands list."""
return ["Draft_ApplyStyle",
"Draft_ToggleDisplayMode",
"Draft_AddNamedGroup",
"Draft_AddToGroup",
"Draft_SelectGroup",
"Draft_SelectPlane",
"Draft_ShowSnapBar",
"Draft_ToggleGrid",
"Draft_SetStyle"]
def get_draft_line_commands():
"""Return the line commands list."""
return ["Draft_UndoLine",
"Draft_FinishLine",
"Draft_CloseLine"]
def init_toolbar(workbench, toolbar, cmd_list):
"""Initialize a toolbar.
Parameters
----------
workbench: Gui.Workbench
The workbench class on which the commands have to be available.
If called from within the `Initialize` method
of a workbench class defined inside `InitGui.py`,
it can be used as `setup_draft_toolbars(self)`.
The workbench. The commands from cmd_list must be available.
toolbar: string
The name of the toolbar.
cmd_list: list of strings or list of strings and tuples
See f.e. the return value of get_draft_drawing_commands.
"""
workbench.appendToolbar(QT_TRANSLATE_NOOP("Draft",
"Draft creation tools"),
get_draft_drawing_commands())
workbench.appendToolbar(QT_TRANSLATE_NOOP("Draft",
"Draft annotation tools"),
get_draft_annotation_commands())
workbench.appendToolbar(QT_TRANSLATE_NOOP("Draft",
"Draft modification tools"),
get_draft_modification_commands())
for cmd in cmd_list:
if isinstance(cmd, tuple):
if len(cmd) == 1:
workbench.appendToolbar(toolbar, [cmd[0]])
else:
workbench.appendToolbar(toolbar, [cmd])
def init_draft_menus(workbench):
"""Initialize the Draft menus.
def init_menu(workbench, menu_list, cmd_list):
"""Initialize a menu.
Parameters
----------
workbench: Gui.Workbench
The workbench class on which the commands have to be available.
If called from within the `Initialize` method
of a workbench class defined inside `InitGui.py`,
it can be used as `setup_draft_menus(self)`.
The workbench. The commands from cmd_list must be available.
menu_list: list of strings
The main and optional submenu(s). The commands, and additional
submenus (if any), are added to the last (sub)menu in the list.
cmd_list: list of strings or list of strings and tuples
See f.e. the return value of get_draft_drawing_commands.
"""
workbench.appendMenu(QT_TRANSLATE_NOOP("Draft", "&Drafting"),
get_draft_drawing_commands())
workbench.appendMenu(QT_TRANSLATE_NOOP("Draft", "&Annotation"),
get_draft_annotation_commands())
workbench.appendMenu(QT_TRANSLATE_NOOP("Draft", "&Modification"),
get_draft_modification_commands())
workbench.appendMenu(QT_TRANSLATE_NOOP("Draft", "&Utilities"),
get_draft_utility_commands()
+ get_draft_context_commands())
for cmd in cmd_list:
if isinstance(cmd, tuple):
if len(cmd) == 2:
workbench.appendMenu(menu_list + cmd[0], cmd[1])
else:
workbench.appendMenu(menu_list, [cmd])
## @}
@@ -27,7 +27,7 @@ import os
import FreeCAD
from draftguitools.gui_hatch import Draft_Hatch_TaskPanel
class Draft_Hatch_ViewProvider:
class ViewProviderDraftHatch:
def __init__(self,vobj):
+8 -3
View File
@@ -64,10 +64,7 @@
#include <BRep_Tool.hxx>
#include <BRepAdaptor_CompCurve.hxx>
#include <BRepAdaptor_HCompCurve.hxx>
#include <Approx_Curve3d.hxx>
#include <BRepAdaptor_HCurve.hxx>
#include <BRepAdaptor_HCurve.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Geom_BezierCurve.hxx>
#include <GeomConvert_BSplineCurveToBezierCurve.hxx>
@@ -75,11 +72,19 @@
#include <Geom2d_BSplineCurve.hxx>
#include <BRepLProp_CLProps.hxx>
#include <Standard_Failure.hxx>
#include <Standard_Version.hxx>
#if OCC_VERSION_HEX < 0x070600
#include <BRepAdaptor_HCurve.hxx>
#endif
#include "DrawingExport.h"
#include <Base/Tools.h>
#include <Base/Vector3D.h>
#if OCC_VERSION_HEX >= 0x070600
using BRepAdaptor_HCurve = BRepAdaptor_Curve;
#endif
using namespace Drawing;
using namespace std;
-3
View File
@@ -61,10 +61,7 @@
#include <BRepMesh_IncrementalMesh.hxx>
#include <BRepLib.hxx>
#include <BRepAdaptor_CompCurve.hxx>
#include <BRepAdaptor_HCompCurve.hxx>
#include <Approx_Curve3d.hxx>
#include <BRepAdaptor_HCurve.hxx>
#include <BRepAdaptor_HCurve.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Geom_BezierCurve.hxx>
#include <GeomConvert_BSplineCurveToBezierCurve.hxx>
+10 -2
View File
@@ -36,8 +36,6 @@
# include <BRepAdaptor_Curve.hxx>
# include <GCPnts_AbscissaPoint.hxx>
# include <Adaptor3d_IsoCurve.hxx>
# include <Adaptor3d_HSurface.hxx>
# include <BRepAdaptor_HSurface.hxx>
# include <BRepAdaptor_Surface.hxx>
# include <GProp_GProps.hxx>
# include <BRepGProp.hxx>
@@ -51,6 +49,11 @@
# include <Geom_Plane.hxx>
# include <Geom_Line.hxx>
# include <Precision.hxx>
# include <Standard_Version.hxx>
# if OCC_VERSION_HEX < 0x070600
# include <Adaptor3d_HSurface.hxx>
# include <BRepAdaptor_HSurface.hxx>
# endif
#endif
#include "FemConstraint.h"
@@ -74,6 +77,11 @@ double round(double r) {
}
#endif
#if OCC_VERSION_HEX >= 0x070600
using Adaptor3d_HSurface = Adaptor3d_Surface;
using BRepAdaptor_HSurface = BRepAdaptor_Surface;
#endif
PROPERTY_SOURCE(Fem::Constraint, App::DocumentObject)
Constraint::Constraint()
-2
View File
@@ -32,8 +32,6 @@
#include <BRepAdaptor_Surface.hxx>
#include <GCPnts_AbscissaPoint.hxx>
#include <Adaptor3d_IsoCurve.hxx>
#include <Adaptor3d_HSurface.hxx>
#include <BRepAdaptor_HSurface.hxx>
#include <GProp_GProps.hxx>
#include <BRepGProp.hxx>
#include <TopoDS_Vertex.hxx>
File diff suppressed because it is too large Load Diff
+46 -46
View File
@@ -49,7 +49,7 @@ class _Analysis(CommandManager):
def __init__(self):
super(_Analysis, self).__init__()
self.menuetext = "Analysis container"
self.menutext = "Analysis container"
self.accel = "S, A"
self.tooltip = "Creates an analysis container with standard solver CalculiX"
self.is_active = "with_document"
@@ -74,7 +74,7 @@ class _ClippingPlaneAdd(CommandManager):
def __init__(self):
super(_ClippingPlaneAdd, self).__init__()
self.menuetext = "Clipping plane on face"
self.menutext = "Clipping plane on face"
self.tooltip = "Add a clipping plane on a selected face"
self.is_active = "with_document"
@@ -119,11 +119,11 @@ class _ClippingPlaneAdd(CommandManager):
class _ClippingPlaneRemoveAll(CommandManager):
"The FEM_ClippingPlaneemoveAll command definition"
"The FEM_ClippingPlaneRemoveAll command definition"
def __init__(self):
super(_ClippingPlaneRemoveAll, self).__init__()
self.menuetext = "Remove all clipping planes"
self.menutext = "Remove all clipping planes"
self.tooltip = "Remove all clipping planes"
self.is_active = "with_document"
@@ -143,7 +143,7 @@ class _ConstantVacuumPermittivity(CommandManager):
def __init__(self):
super(_ConstantVacuumPermittivity, self).__init__()
self.pixmap = "fem-solver-analysis-thermomechanical.svg"
self.menuetext = "Constant vacuum permittivity"
self.menutext = "Constant vacuum permittivity"
self.tooltip = "Creates a FEM constant vacuum permittivity to overwrite standard value"
self.is_active = "with_document"
self.is_active = "with_analysis"
@@ -156,7 +156,7 @@ class _ConstraintBodyHeatSource(CommandManager):
def __init__(self):
super(_ConstraintBodyHeatSource, self).__init__()
self.pixmap = "FEM_ConstraintHeatflux" # the heatflux icon is used
self.menuetext = "Constraint body heat source"
self.menutext = "Constraint body heat source"
self.tooltip = "Creates a FEM constraint body heat source"
self.is_active = "with_analysis"
self.do_activated = "add_obj_on_gui_noset_edit"
@@ -167,7 +167,7 @@ class _ConstraintCentrif(CommandManager):
def __init__(self):
super(_ConstraintCentrif, self).__init__()
self.menuetext = "Constraint centrif"
self.menutext = "Constraint centrif"
self.tooltip = "Creates a FEM constraint centrif"
self.is_active = "with_analysis"
self.do_activated = "add_obj_on_gui_set_edit"
@@ -178,7 +178,7 @@ class _ConstraintElectrostaticPotential(CommandManager):
def __init__(self):
super(_ConstraintElectrostaticPotential, self).__init__()
self.menuetext = "Constraint electrostatic potential"
self.menutext = "Constraint electrostatic potential"
self.tooltip = "Creates a FEM constraint electrostatic potential"
self.is_active = "with_analysis"
self.do_activated = "add_obj_on_gui_set_edit"
@@ -189,7 +189,7 @@ class _ConstraintFlowVelocity(CommandManager):
def __init__(self):
super(_ConstraintFlowVelocity, self).__init__()
self.menuetext = "Constraint flow velocity"
self.menutext = "Constraint flow velocity"
self.tooltip = "Creates a FEM constraint flow velocity"
self.is_active = "with_analysis"
self.do_activated = "add_obj_on_gui_set_edit"
@@ -200,7 +200,7 @@ class _ConstraintInitialFlowVelocity(CommandManager):
def __init__(self):
super(_ConstraintInitialFlowVelocity, self).__init__()
self.menuetext = "Constraint initial flow velocity"
self.menutext = "Constraint initial flow velocity"
self.tooltip = "Creates a FEM constraint initial flow velocity"
self.is_active = "with_analysis"
self.do_activated = "add_obj_on_gui_set_edit"
@@ -211,7 +211,7 @@ class _ConstraintSectionPrint(CommandManager):
def __init__(self):
super(_ConstraintSectionPrint, self).__init__()
self.menuetext = "Constraint sectionprint"
self.menutext = "Constraint sectionprint"
self.tooltip = "Creates a FEM constraint sectionprint"
self.is_active = "with_analysis"
self.do_activated = "add_obj_on_gui_set_edit"
@@ -222,7 +222,7 @@ class _ConstraintSelfWeight(CommandManager):
def __init__(self):
super(_ConstraintSelfWeight, self).__init__()
self.menuetext = "Constraint self weight"
self.menutext = "Constraint self weight"
self.tooltip = "Creates a FEM constraint self weight"
self.is_active = "with_analysis"
self.do_activated = "add_obj_on_gui_noset_edit"
@@ -233,7 +233,7 @@ class _ConstraintTie(CommandManager):
def __init__(self):
super(_ConstraintTie, self).__init__()
self.menuetext = "Constraint tie"
self.menutext = "Constraint tie"
self.tooltip = "Creates a FEM constraint tie"
self.is_active = "with_analysis"
self.do_activated = "add_obj_on_gui_set_edit"
@@ -244,7 +244,7 @@ class _ElementFluid1D(CommandManager):
def __init__(self):
super(_ElementFluid1D, self).__init__()
self.menuetext = "Fluid section for 1D flow"
self.menutext = "Fluid section for 1D flow"
self.tooltip = "Creates a FEM fluid section for 1D flow"
self.is_active = "with_analysis"
self.do_activated = "add_obj_on_gui_set_edit"
@@ -255,7 +255,7 @@ class _ElementGeometry1D(CommandManager):
def __init__(self):
super(_ElementGeometry1D, self).__init__()
self.menuetext = "Beam cross section"
self.menutext = "Beam cross section"
self.tooltip = "Creates a FEM beam cross section"
self.is_active = "with_analysis"
self.do_activated = "add_obj_on_gui_set_edit"
@@ -266,7 +266,7 @@ class _ElementGeometry2D(CommandManager):
def __init__(self):
super(_ElementGeometry2D, self).__init__()
self.menuetext = "Shell plate thickness"
self.menutext = "Shell plate thickness"
self.tooltip = "Creates a FEM shell plate thickness"
self.is_active = "with_analysis"
self.do_activated = "add_obj_on_gui_set_edit"
@@ -277,7 +277,7 @@ class _ElementRotation1D(CommandManager):
def __init__(self):
super(_ElementRotation1D, self).__init__()
self.menuetext = "Beam rotation"
self.menutext = "Beam rotation"
self.tooltip = "Creates a FEM beam rotation"
self.is_active = "with_analysis"
self.do_activated = "add_obj_on_gui_noset_edit"
@@ -288,7 +288,7 @@ class _EquationElectrostatic(CommandManager):
def __init__(self):
super(_EquationElectrostatic, self).__init__()
self.menuetext = "Electrostatic equation"
self.menutext = "Electrostatic equation"
self.tooltip = "Creates a FEM equation for electrostatic"
self.is_active = "with_solver_elmer"
self.do_activated = "add_obj_on_gui_selobj_noset_edit"
@@ -299,7 +299,7 @@ class _EquationElasticity(CommandManager):
def __init__(self):
super(_EquationElasticity, self).__init__()
self.menuetext = "Elasticity equation"
self.menutext = "Elasticity equation"
self.tooltip = "Creates a FEM equation for elasticity"
self.is_active = "with_solver_elmer"
self.do_activated = "add_obj_on_gui_selobj_noset_edit"
@@ -310,7 +310,7 @@ class _EquationFlow(CommandManager):
def __init__(self):
super(_EquationFlow, self).__init__()
self.menuetext = "Flow equation"
self.menutext = "Flow equation"
self.tooltip = "Creates a FEM equation for flow"
self.is_active = "with_solver_elmer"
self.do_activated = "add_obj_on_gui_selobj_noset_edit"
@@ -321,7 +321,7 @@ class _EquationFlux(CommandManager):
def __init__(self):
super(_EquationFlux, self).__init__()
self.menuetext = "Flux equation"
self.menutext = "Flux equation"
self.tooltip = "Creates a FEM equation for flux"
self.is_active = "with_solver_elmer"
self.do_activated = "add_obj_on_gui_selobj_noset_edit"
@@ -332,7 +332,7 @@ class _EquationElectricforce(CommandManager):
def __init__(self):
super(_EquationElectricforce, self).__init__()
self.menuetext = "Electricforce equation"
self.menutext = "Electricforce equation"
self.tooltip = "Creates a FEM equation for electric forces"
self.is_active = "with_solver_elmer"
self.do_activated = "add_obj_on_gui_selobj_noset_edit"
@@ -343,7 +343,7 @@ class _EquationHeat(CommandManager):
def __init__(self):
super(_EquationHeat, self).__init__()
self.menuetext = "Heat equation"
self.menutext = "Heat equation"
self.tooltip = "Creates a FEM equation for heat"
self.is_active = "with_solver_elmer"
self.do_activated = "add_obj_on_gui_selobj_noset_edit"
@@ -355,7 +355,7 @@ class _Examples(CommandManager):
def __init__(self):
super(_Examples, self).__init__()
self.pixmap = "FemWorkbench"
self.menuetext = "Open FEM examples"
self.menutext = "Open FEM examples"
self.tooltip = "Open FEM examples"
self.is_active = "always"
@@ -370,7 +370,7 @@ class _MaterialEditor(CommandManager):
def __init__(self):
super(_MaterialEditor, self).__init__()
self.pixmap = "Arch_Material_Group"
self.menuetext = "Material editor"
self.menutext = "Material editor"
self.tooltip = "Opens the FreeCAD material editor"
self.is_active = "always"
@@ -384,7 +384,7 @@ class _MaterialFluid(CommandManager):
def __init__(self):
super(_MaterialFluid, self).__init__()
self.menuetext = "Material for fluid"
self.menutext = "Material for fluid"
self.tooltip = "Creates a FEM material for fluid"
self.is_active = "with_analysis"
self.do_activated = "add_obj_on_gui_set_edit"
@@ -395,7 +395,7 @@ class _MaterialMechanicalNonlinear(CommandManager):
def __init__(self):
super(_MaterialMechanicalNonlinear, self).__init__()
self.menuetext = "Nonlinear mechanical material"
self.menutext = "Nonlinear mechanical material"
self.tooltip = "Creates a nonlinear mechanical material"
self.is_active = "with_material_solid"
@@ -459,7 +459,7 @@ class _MaterialReinforced(CommandManager):
def __init__(self):
super(_MaterialReinforced, self).__init__()
self.menuetext = "Reinforced material (concrete)"
self.menutext = "Reinforced material (concrete)"
self.tooltip = "Creates a material for reinforced matrix material such as concrete"
self.is_active = "with_analysis"
self.do_activated = "add_obj_on_gui_set_edit"
@@ -470,7 +470,7 @@ class _MaterialSolid(CommandManager):
def __init__(self):
super(_MaterialSolid, self).__init__()
self.menuetext = "Material for solid"
self.menutext = "Material for solid"
self.accel = "M, S"
self.tooltip = "Creates a FEM material for solid"
self.is_active = "with_analysis"
@@ -482,7 +482,7 @@ class _FEMMesh2Mesh(CommandManager):
def __init__(self):
super(_FEMMesh2Mesh, self).__init__()
self.menuetext = "FEM mesh to mesh"
self.menutext = "FEM mesh to mesh"
self.tooltip = "Convert the surface of a FEM mesh to a mesh"
self.is_active = "with_femmesh_andor_res"
@@ -523,7 +523,7 @@ class _MeshBoundaryLayer(CommandManager):
def __init__(self):
super(_MeshBoundaryLayer, self).__init__()
self.menuetext = "FEM mesh boundary layer"
self.menutext = "FEM mesh boundary layer"
self.tooltip = "Creates a FEM mesh boundary layer"
self.is_active = "with_gmsh_femmesh"
self.do_activated = "add_obj_on_gui_selobj_set_edit"
@@ -534,7 +534,7 @@ class _MeshClear(CommandManager):
def __init__(self):
super(_MeshClear, self).__init__()
self.menuetext = "Clear FEM mesh"
self.menutext = "Clear FEM mesh"
self.tooltip = "Clear the Mesh of a FEM mesh object"
self.is_active = "with_femmesh"
@@ -553,7 +553,7 @@ class _MeshDisplayInfo(CommandManager):
def __init__(self):
super(_MeshDisplayInfo, self).__init__()
self.menuetext = "Display FEM mesh info"
self.menutext = "Display FEM mesh info"
self.tooltip = "Display FEM mesh info"
self.is_active = "with_femmesh"
@@ -576,7 +576,7 @@ class _MeshGmshFromShape(CommandManager):
def __init__(self):
super(_MeshGmshFromShape, self).__init__()
self.menuetext = "FEM mesh from shape by Gmsh"
self.menutext = "FEM mesh from shape by Gmsh"
self.tooltip = "Create a FEM mesh from a shape by Gmsh mesher"
self.is_active = "with_part_feature"
@@ -615,7 +615,7 @@ class _MeshGroup(CommandManager):
def __init__(self):
super(_MeshGroup, self).__init__()
self.menuetext = "FEM mesh group"
self.menutext = "FEM mesh group"
self.tooltip = "Creates a FEM mesh group"
self.is_active = "with_gmsh_femmesh"
self.do_activated = "add_obj_on_gui_selobj_set_edit"
@@ -626,7 +626,7 @@ class _MeshNetgenFromShape(CommandManager):
def __init__(self):
super(_MeshNetgenFromShape, self).__init__()
self.menuetext = "FEM mesh from shape by Netgen"
self.menutext = "FEM mesh from shape by Netgen"
self.tooltip = "Create a FEM mesh from a solid or face shape by Netgen internal mesher"
self.is_active = "with_part_feature"
@@ -665,7 +665,7 @@ class _MeshRegion(CommandManager):
def __init__(self):
super(_MeshRegion, self).__init__()
self.menuetext = "FEM mesh region"
self.menutext = "FEM mesh region"
self.tooltip = "Creates a FEM mesh region"
self.is_active = "with_gmsh_femmesh"
self.do_activated = "add_obj_on_gui_selobj_set_edit"
@@ -676,7 +676,7 @@ class _ResultShow(CommandManager):
def __init__(self):
super(_ResultShow, self).__init__()
self.menuetext = "Show result"
self.menutext = "Show result"
self.accel = "R, S"
self.tooltip = "Shows and visualizes selected result data"
self.is_active = "with_selresult"
@@ -690,7 +690,7 @@ class _ResultsPurge(CommandManager):
def __init__(self):
super(_ResultsPurge, self).__init__()
self.menuetext = "Purge results"
self.menutext = "Purge results"
self.accel = "R, P"
self.tooltip = "Purges all results from active analysis"
self.is_active = "with_results"
@@ -706,7 +706,7 @@ class _SolverCxxtools(CommandManager):
def __init__(self):
super(_SolverCxxtools, self).__init__()
self.pixmap = "FEM_SolverStandard"
self.menuetext = "Solver CalculiX Standard"
self.menutext = "Solver CalculiX Standard"
self.accel = "S, X"
self.tooltip = "Creates a standard FEM solver CalculiX with ccx tools"
self.is_active = "with_analysis"
@@ -741,7 +741,7 @@ class _SolverCalculix(CommandManager):
def __init__(self):
super(_SolverCalculix, self).__init__()
self.pixmap = "FEM_SolverStandard"
self.menuetext = "Solver CalculiX (new framework)"
self.menutext = "Solver CalculiX (new framework)"
self.accel = "S, C"
self.tooltip = "Creates a FEM solver CalculiX new framework (less result error handling)"
self.is_active = "with_analysis"
@@ -754,7 +754,7 @@ class _SolverControl(CommandManager):
def __init__(self):
super(_SolverControl, self).__init__()
self.menuetext = "Solver job control"
self.menutext = "Solver job control"
self.accel = "S, T"
self.tooltip = "Changes solver attributes and runs the calculations for the selected solver"
self.is_active = "with_solver"
@@ -768,7 +768,7 @@ class _SolverElmer(CommandManager):
def __init__(self):
super(_SolverElmer, self).__init__()
self.menuetext = "Solver Elmer"
self.menutext = "Solver Elmer"
self.accel = "S, E"
self.tooltip = "Creates a FEM solver Elmer"
self.is_active = "with_analysis"
@@ -781,7 +781,7 @@ class _SolverMystran(CommandManager):
def __init__(self):
super(_SolverMystran, self).__init__()
self.pixmap = "FEM_SolverStandard"
self.menuetext = "Solver Mystran"
self.menutext = "Solver Mystran"
self.accel = "S, M"
self.tooltip = "Creates a FEM solver Mystran"
self.is_active = "with_analysis"
@@ -793,7 +793,7 @@ class _SolverRun(CommandManager):
def __init__(self):
super(_SolverRun, self).__init__()
self.menuetext = "Run solver calculations"
self.menutext = "Run solver calculations"
self.accel = "S, R"
self.tooltip = "Runs the calculations for the selected solver"
self.is_active = "with_solver"
@@ -810,7 +810,7 @@ class _SolverZ88(CommandManager):
def __init__(self):
super(_SolverZ88, self).__init__()
self.menuetext = "Solver Z88"
self.menutext = "Solver Z88"
self.accel = "S, Z"
self.tooltip = "Creates a FEM solver Z88"
self.is_active = "with_analysis"
+3 -3
View File
@@ -46,9 +46,9 @@ class CommandManager(object):
self.command = "FEM" + self.__class__.__name__
self.pixmap = self.command
self.menuetext = self.__class__.__name__.lstrip("_")
self.menutext = self.__class__.__name__.lstrip("_")
self.accel = ""
self.tooltip = "Creates a {}".format(self.menuetext)
self.tooltip = "Creates a {}".format(self.menutext)
self.resources = None
self.is_active = None
@@ -61,7 +61,7 @@ class CommandManager(object):
if self.resources is None:
self.resources = {
"Pixmap": self.pixmap,
"MenuText": QtCore.QT_TRANSLATE_NOOP(self.command, self.menuetext),
"MenuText": QtCore.QT_TRANSLATE_NOOP(self.command, self.menutext),
"Accel": self.accel,
"ToolTip": QtCore.QT_TRANSLATE_NOOP(self.command, self.tooltip)
}
+1 -1
View File
@@ -91,7 +91,7 @@ def write(
mesh_pynas_code += missing_code_pnynasmesh
# pynas file
basefilename = filename[:len(filename) - 4] # TODO basename is more failsave
basefilename = filename[:len(filename) - 4] # TODO basename is more failsafe
pynasf = open(basefilename + ".py", "w")
pynasf.write("# written by FreeCAD\n\n\n")
pynasf.write("from pyNastran.bdf.bdf import BDF\n")
+1 -1
View File
@@ -195,7 +195,7 @@ class _SolverDlg(object):
# set the binary path to the FreeCAD defaults
# ATM pure unix shell commands without path names are used as standard
# TODO the binaries provieded with the FreeCAD distribution should be found
# TODO the binaries provided with the FreeCAD distribution should be found
# without any additional user input
# see ccxttols, it works for Windows and Linux there
binary = self.default
+20 -9
View File
@@ -55,19 +55,30 @@ class FemInputWriter():
self.analysis_type = self.solver_obj.AnalysisType
self.document = self.analysis.Document
# working dir
self.dir_name = dir_name
# if dir_name was not given or if it exists but is not empty: create a temporary dir
# Purpose: makes sure the analysis can be run even on wired situation
if not dir_name:
make_tmp_dir = False
if dir_name is None:
FreeCAD.Console.PrintWarning(
"Error: FemInputWriter has no working_dir --> "
"we are going to make a temporary one!\n"
"Error: The working_dir in base input file writer class was not set. "
"A temporary directory is used.\n"
)
self.dir_name = self.document.TransientDir.replace(
"\\", "/"
) + "/FemAnl_" + analysis_obj.Uid[-4:]
if not os.path.isdir(self.dir_name):
os.mkdir(self.dir_name)
make_tmp_dir = True
elif not os.path.isdir(dir_name):
FreeCAD.Console.PrintWarning(
"Error: The working_dir: '{}' given to "
"base input file writer class does not exist. "
"A temporary directory is used.\n".format(dir_name)
)
make_tmp_dir = True
if make_tmp_dir is True:
from tempfile import mkdtemp
dir_name = mkdtemp(prefix="fcfem_")
FreeCAD.Console.PrintWarning(
"The working directory '{}' was created and will be used."
.format(dir_name)
)
self.dir_name = dir_name
# new class attributes
self.fc_ver = FreeCAD.Version()
+18 -23
View File
@@ -58,7 +58,7 @@
# include <TDF_LabelSequence.hxx>
# include <TDF_ChildIterator.hxx>
# include <TDataStd_Name.hxx>
# include <Quantity_Color.hxx>
# include <Quantity_ColorRGBA.hxx>
# include <STEPCAFControl_Reader.hxx>
# include <STEPControl_Writer.hxx>
# include <IGESCAFControl_Reader.hxx>
@@ -95,6 +95,17 @@
#include <App/DocumentObject.h>
#include <App/DocumentObjectGroup.h>
#if OCC_VERSION_HEX >= 0x070500
// See https://dev.opencascade.org/content/occt-3d-viewer-becomes-srgb-aware
# define OCC_COLOR_SPACE Quantity_TOC_sRGB
#else
# define OCC_COLOR_SPACE Quantity_TOC_RGB
#endif
static inline Quantity_ColorRGBA convertColor(const App::Color &c)
{
return Quantity_ColorRGBA(Quantity_Color(c.r, c.g, c.b, OCC_COLOR_SPACE), 1.0 - c.a);
}
using namespace Import;
@@ -284,7 +295,7 @@ int ExportOCAF::saveShape(Part::Feature* part, const std::vector<App::Color>& co
*/
// Add color information
Quantity_Color col;
Quantity_ColorRGBA col;
std::set<int> face_index;
TopTools_IndexedMapOfShape faces;
@@ -317,11 +328,7 @@ int ExportOCAF::saveShape(Part::Feature* part, const std::vector<App::Color>& co
if (!faceLabel.IsNull()) {
const App::Color& color = colors[index-1];
Standard_Real mat[3];
mat[0] = color.r;
mat[1] = color.g;
mat[2] = color.b;
col.SetValues(mat[0],mat[1],mat[2],Quantity_TOC_RGB);
col = convertColor(color);
aColorTool->SetColor(faceLabel, col, XCAFDoc_ColorSurf);
}
}
@@ -330,11 +337,7 @@ int ExportOCAF::saveShape(Part::Feature* part, const std::vector<App::Color>& co
}
else if (!colors.empty()) {
App::Color color = colors.front();
Standard_Real mat[3];
mat[0] = color.r;
mat[1] = color.g;
mat[2] = color.b;
col.SetValues(mat[0],mat[1],mat[2],Quantity_TOC_RGB);
col = convertColor(color);
aColorTool->SetColor(shapeLabel, col, XCAFDoc_ColorGen);
}
@@ -400,7 +403,7 @@ void ExportOCAF::reallocateFreeShape(std::vector <App::DocumentObject*> hierarch
TopoDS_Shape baseShape = part->Shape.getValue();
// Add color information
Quantity_Color col;
Quantity_ColorRGBA col;
std::set<int> face_index;
TopTools_IndexedMapOfShape faces;
@@ -433,11 +436,7 @@ void ExportOCAF::reallocateFreeShape(std::vector <App::DocumentObject*> hierarch
if (!faceLabel.IsNull()) {
const App::Color& color = colors[index-1];
Standard_Real mat[3];
mat[0] = color.r;
mat[1] = color.g;
mat[2] = color.b;
col.SetValues(mat[0],mat[1],mat[2],Quantity_TOC_RGB);
col = convertColor(color);
aColorTool->SetColor(faceLabel, col, XCAFDoc_ColorSurf);
}
}
@@ -447,11 +446,7 @@ void ExportOCAF::reallocateFreeShape(std::vector <App::DocumentObject*> hierarch
}
else if (!colors.empty()) {
App::Color color = colors.front();
Standard_Real mat[3];
mat[0] = color.r;
mat[1] = color.g;
mat[2] = color.b;
col.SetValues(mat[0],mat[1],mat[2],Quantity_TOC_RGB);
col = convertColor(color);
aColorTool->SetColor(label, col, XCAFDoc_ColorGen);
}
}
+8 -1
View File
@@ -29,7 +29,6 @@
#include <Approx_Curve3d.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BRepAdaptor_HCurve.hxx>
#include <BRep_Builder.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
@@ -47,6 +46,7 @@
#include <gp_Pnt.hxx>
#include <gp_Dir.hxx>
#include <gp_Vec.hxx>
#include <Standard_Version.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Vertex.hxx>
@@ -55,6 +55,9 @@
#include <TopExp_Explorer.hxx>
#include <TopoDS_Edge.hxx>
#include <TColgp_Array1OfPnt.hxx>
#if OCC_VERSION_HEX < 0x070600
#include <BRepAdaptor_HCurve.hxx>
#endif
#include <Base/Console.h>
#include <Base/Parameter.h>
@@ -68,6 +71,10 @@
using namespace Import;
#if OCC_VERSION_HEX >= 0x070600
using BRepAdaptor_HCurve = BRepAdaptor_Curve;
#endif
//******************************************************************************
// reading
+24 -15
View File
@@ -60,7 +60,7 @@
# include <TDF_LabelSequence.hxx>
# include <TDF_ChildIterator.hxx>
# include <TDataStd_Name.hxx>
# include <Quantity_Color.hxx>
# include <Quantity_ColorRGBA.hxx>
# include <STEPCAFControl_Reader.hxx>
# include <STEPControl_Writer.hxx>
# include <IGESCAFControl_Reader.hxx>
@@ -108,6 +108,23 @@
using namespace Import;
#if OCC_VERSION_HEX >= 0x070500
// See https://dev.opencascade.org/content/occt-3d-viewer-becomes-srgb-aware
# define OCC_COLOR_SPACE Quantity_TOC_sRGB
#else
# define OCC_COLOR_SPACE Quantity_TOC_RGB
#endif
static inline App::Color convertColor(const Quantity_ColorRGBA &c)
{
Standard_Real r, g, b;
c.GetRGB().Values(r, g, b, OCC_COLOR_SPACE);
return App::Color(static_cast<float>(r),
static_cast<float>(g),
static_cast<float>(b),
1.0f - static_cast<float>(c.Alpha()));
}
#define OCAF_KEEP_PLACEMENT
ImportOCAF::ImportOCAF(Handle(TDocStd_Document) h, App::Document* d, const std::string& name)
@@ -439,14 +456,12 @@ void ImportOCAF::createShape(const TopoDS_Shape& aShape, const TopLoc_Location&
void ImportOCAF::loadColors(Part::Feature* part, const TopoDS_Shape& aShape)
{
Quantity_Color aColor;
Quantity_ColorRGBA aColor;
App::Color color(0.8f,0.8f,0.8f);
if (aColorTool->GetColor(aShape, XCAFDoc_ColorGen, aColor) ||
aColorTool->GetColor(aShape, XCAFDoc_ColorSurf, aColor) ||
aColorTool->GetColor(aShape, XCAFDoc_ColorCurv, aColor)) {
color.r = (float)aColor.Red();
color.g = (float)aColor.Green();
color.b = (float)aColor.Blue();
color = convertColor(aColor);
std::vector<App::Color> colors;
colors.push_back(color);
applyColors(part, colors);
@@ -468,9 +483,7 @@ void ImportOCAF::loadColors(Part::Feature* part, const TopoDS_Shape& aShape)
aColorTool->GetColor(xp.Current(), XCAFDoc_ColorSurf, aColor) ||
aColorTool->GetColor(xp.Current(), XCAFDoc_ColorCurv, aColor)) {
int index = faces.FindIndex(xp.Current());
color.r = (float)aColor.Red();
color.g = (float)aColor.Green();
color.b = (float)aColor.Blue();
color = convertColor(aColor);
faceColors[index-1] = color;
found_face_color = true;
}
@@ -551,7 +564,7 @@ void ImportXCAF::createShape(const TopoDS_Shape& shape, bool perface, bool setna
part = static_cast<Part::Feature*>(doc->addObject("Part::Feature", default_name.c_str()));
part->Label.setValue(default_name);
part->Shape.setValue(shape);
std::map<Standard_Integer, Quantity_Color>::const_iterator jt;
std::map<Standard_Integer, Quantity_ColorRGBA>::const_iterator jt;
jt = myColorMap.find(shape.HashCode(INT_MAX));
App::Color partColor(0.8f,0.8f,0.8f);
@@ -596,11 +609,7 @@ void ImportXCAF::createShape(const TopoDS_Shape& shape, bool perface, bool setna
jt = myColorMap.find(xp.Current().HashCode(INT_MAX));
if (jt != myColorMap.end()) {
int index = faces.FindIndex(xp.Current());
App::Color color;
color.r = (float)jt->second.Red();
color.g = (float)jt->second.Green();
color.b = (float)jt->second.Blue();
faceColors[index-1] = color;
faceColors[index-1] = convertColor(jt->second);
found_face_color = true;
}
xp.Next();
@@ -653,7 +662,7 @@ void ImportXCAF::loadShapes(const TDF_Label& label)
}
// getting color
Quantity_Color col;
Quantity_ColorRGBA col;
if (hColors->GetColor(label, XCAFDoc_ColorGen, col) ||
hColors->GetColor(label, XCAFDoc_ColorSurf, col) ||
hColors->GetColor(label, XCAFDoc_ColorCurv, col)) {
+2 -2
View File
@@ -27,7 +27,7 @@
#include <TDocStd_Document.hxx>
#include <XCAFDoc_ColorTool.hxx>
#include <XCAFDoc_ShapeTool.hxx>
#include <Quantity_Color.hxx>
#include <Quantity_ColorRGBA.hxx>
#include <TopoDS_Shape.hxx>
#include <TDF_LabelMapHasher.hxx>
#include <climits>
@@ -117,7 +117,7 @@ private:
std::map<Standard_Integer, TopoDS_Shape> myShells;
std::map<Standard_Integer, TopoDS_Shape> myCompds;
std::map<Standard_Integer, TopoDS_Shape> myShapes;
std::map<Standard_Integer, Quantity_Color> myColorMap;
std::map<Standard_Integer, Quantity_ColorRGBA> myColorMap;
std::map<Standard_Integer, std::string> myNameMap;
};
+59 -25
View File
@@ -41,7 +41,7 @@
# include <TDF_LabelSequence.hxx>
# include <TDF_ChildIterator.hxx>
# include <TDataStd_Name.hxx>
# include <Quantity_Color.hxx>
# include <Quantity_ColorRGBA.hxx>
# include <TopoDS_Iterator.hxx>
# include <Interface_Static.hxx>
# include <TDF_AttributeSequence.hxx>
@@ -50,6 +50,7 @@
#include <XCAFDoc_ShapeMapTool.hxx>
#include <boost/format.hpp>
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#include <Base/Parameter.h>
@@ -71,12 +72,40 @@
#include <App/DocumentObject.h>
#include <App/DocumentObjectGroup.h>
#if OCC_VERSION_HEX >= 0x070500
// See https://dev.opencascade.org/content/occt-3d-viewer-becomes-srgb-aware
# define OCC_COLOR_SPACE Quantity_TOC_sRGB
#else
# define OCC_COLOR_SPACE Quantity_TOC_RGB
#endif
FC_LOG_LEVEL_INIT("Import",true,true)
using namespace Import;
/////////////////////////////////////////////////////////////////////
static inline App::Color convertColor(const Quantity_ColorRGBA &c)
{
Standard_Real r, g, b;
c.GetRGB().Values(r, g, b, OCC_COLOR_SPACE);
return App::Color(static_cast<float>(r),
static_cast<float>(g),
static_cast<float>(b),
1.0f - static_cast<float>(c.Alpha()));
}
static inline Quantity_ColorRGBA convertColor(const App::Color &c)
{
return Quantity_ColorRGBA(Quantity_Color(c.r, c.g, c.b, OCC_COLOR_SPACE), 1.0f - c.a);
}
static inline std::ostream& operator<<(std::ostream& os, const Quantity_ColorRGBA &c) {
App::Color color = convertColor(c);
auto toHex = [](float v) {return boost::format("%02X") % static_cast<int>(v*255);};
return os << "#" << toHex(color.r) << toHex(color.g) << toHex(color.b) << toHex(color.a);
}
static std::string labelName(TDF_Label label) {
std::string txt;
Handle(TDataStd_Name) name;
@@ -116,13 +145,13 @@ static void printLabel(TDF_Label label, Handle(XCAFDoc_ShapeTool) aShapeTool,
ss << ", " << Part::TopoShape::shapeName(shape.ShapeType(),true);
}
if(aShapeTool->IsShape(label)) {
Quantity_Color c;
Quantity_ColorRGBA c;
if(aColorTool->GetColor(label,XCAFDoc_ColorGen,c))
ss << ", gc: " << c.StringName(c.Name());
ss << ", gc: " << c;
if(aColorTool->GetColor(label,XCAFDoc_ColorSurf,c))
ss << ", sc: " << c.StringName(c.Name());
ss << ", sc: " << c;
if(aColorTool->GetColor(label,XCAFDoc_ColorCurv,c))
ss << ", cc: " << c.StringName(c.Name());
ss << ", cc: " << c;
}
ss << std::endl;
@@ -229,12 +258,11 @@ void ImportOCAF2::setObjectName(Info &info, TDF_Label label) {
}
}
bool ImportOCAF2::getColor(const TopoDS_Shape &shape, Info &info, bool check, bool noDefault) {
bool ret = false;
Quantity_Color aColor;
Quantity_ColorRGBA aColor;
if(aColorTool->GetColor(shape, XCAFDoc_ColorSurf, aColor)) {
App::Color c(aColor.Red(),aColor.Green(),aColor.Blue());
App::Color c = convertColor(aColor);
if(!check || info.faceColor!=c) {
info.faceColor = c;
info.hasFaceColor = true;
@@ -242,7 +270,7 @@ bool ImportOCAF2::getColor(const TopoDS_Shape &shape, Info &info, bool check, bo
}
}
if(!noDefault && !info.hasFaceColor && aColorTool->GetColor(shape, XCAFDoc_ColorGen, aColor)) {
App::Color c(aColor.Red(),aColor.Green(),aColor.Blue());
App::Color c = convertColor(aColor);
if(!check || info.faceColor!=c) {
info.faceColor = c;
info.hasFaceColor = true;
@@ -250,7 +278,7 @@ bool ImportOCAF2::getColor(const TopoDS_Shape &shape, Info &info, bool check, bo
}
}
if(aColorTool->GetColor(shape, XCAFDoc_ColorCurv, aColor)) {
App::Color c(aColor.Red(),aColor.Green(),aColor.Blue());
App::Color c = convertColor(aColor);
// Some STEP include a curve color with the same value of the face
// color. And this will look weird in FC. So for shape with face
// we'll ignore the curve color, if it is the same as the face color.
@@ -365,15 +393,15 @@ bool ImportOCAF2::createObject(App::Document *doc, TDF_Label label,
bool foundFaceColor=false,foundEdgeColor=false;
App::Color faceColor,edgeColor;
Quantity_Color aColor;
Quantity_ColorRGBA aColor;
if(aColorTool->GetColor(l, XCAFDoc_ColorSurf, aColor) ||
aColorTool->GetColor(l, XCAFDoc_ColorGen, aColor))
{
faceColor = App::Color(aColor.Red(),aColor.Green(),aColor.Blue());
faceColor = convertColor(aColor);
foundFaceColor = true;
}
if(aColorTool->GetColor(l, XCAFDoc_ColorCurv, aColor)) {
edgeColor = App::Color(aColor.Red(),aColor.Green(),aColor.Blue());
edgeColor = convertColor(aColor);
foundEdgeColor = true;
if(j==0 && foundFaceColor && faceColors.size() && edgeColor==faceColor) {
// Do not set edge the same color as face
@@ -648,11 +676,11 @@ void ImportOCAF2::getSHUOColors(TDF_Label label,
subname += App::DocumentObject::hiddenMarker();
colors.emplace(subname,App::Color());
} else {
Quantity_Color aColor;
Quantity_ColorRGBA aColor;
if(aColorTool->GetColor(slabel, XCAFDoc_ColorSurf, aColor) ||
aColorTool->GetColor(slabel, XCAFDoc_ColorGen, aColor))
{
colors.emplace(subname,App::Color(aColor.Red(),aColor.Green(),aColor.Blue()));
colors.emplace(subname,convertColor(aColor));
}
}
}
@@ -782,12 +810,9 @@ bool ImportOCAF2::createAssembly(App::Document *_doc,
childInfo.vis.push_back(vis);
childInfo.labels.push_back(childLabel);
childInfo.plas.emplace_back(Part::TopoShape::convert(childShape.Location().Transformation()));
Quantity_Color aColor;
Quantity_ColorRGBA aColor;
if (aColorTool->GetColor(childShape, XCAFDoc_ColorSurf, aColor)) {
auto &color = childInfo.colors[childInfo.plas.size()-1];
color.r = (float)aColor.Red();
color.g = (float)aColor.Green();
color.b = (float)aColor.Blue();
childInfo.colors[childInfo.plas.size()-1] = convertColor(aColor);
}
}
assert(visibilities.size() == children.size());
@@ -1036,7 +1061,7 @@ void ExportOCAF2::setupObject(TDF_Label label, App::DocumentObject *obj,
continue;
}
const App::Color& c = vv.second;
Quantity_Color color(c.r,c.g,c.b,Quantity_TOC_RGB);
Quantity_ColorRGBA color = convertColor(c);
auto colorType = vv.first[0]=='F'?XCAFDoc_ColorSurf:XCAFDoc_ColorCurv;
if(vv.first=="Face" || vv.first=="Edge") {
aColorTool->SetColor(nodeLabel, color, colorType);
@@ -1219,8 +1244,17 @@ TDF_Label ExportOCAF2::exportObject(App::DocumentObject* parentObj,
// not call setupObject() on a non-located baseshape like above,
// because OCCT does not respect shape style sharing when not
// exporting assembly
if(!keepPlacement)
if(!keepPlacement || shape.getPlacement() == Base::Placement())
shape.setShape(shape.getShape().Located(TopLoc_Location()));
else {
Base::Matrix4D mat = shape.getTransform();
shape.setShape(shape.getShape().Located(TopLoc_Location()));
// Transform with copy to conceal the transformation
shape.transformShape(mat, true);
// Even if the shape has no transformation, TopoShape still sets
// a TopLoc_Location, so we need to clear it again.
shape.setShape(shape.getShape().Located(TopLoc_Location()));
}
label = aShapeTool->AddShape(shape.getShape(),Standard_False, Standard_False);
auto o = name?parentObj:obj;
if(o!=linked)
@@ -1277,7 +1311,7 @@ TDF_Label ExportOCAF2::exportObject(App::DocumentObject* parentObj,
// Work around OCCT bug. If no color setting here, it will crash.
// The culprit is at STEPCAFControl_Writer::1093 as shown below
//
// surfColor = Styles.EncodeColor(Quantity_Color(1,1,1,Quantity_TOC_RGB),DPDCs,ColRGBs);
// surfColor = Styles.EncodeColor(Quantity_Color(1,1,1,OCC_COLOR_SPACE),DPDCs,ColRGBs);
// PSA = Styles.MakeColorPSA ( item, surfColor, curvColor, isComponent );
// if ( isComponent )
// setDefaultInstanceColor( override, PSA);
@@ -1287,13 +1321,13 @@ TDF_Label ExportOCAF2::exportObject(App::DocumentObject* parentObj,
// setDefaultInstanceColor( override, PSA);
//
auto childShape = aShapeTool->GetShape(childLabel);
Quantity_Color col;
Quantity_ColorRGBA col;
if(!aColorTool->GetInstanceColor(childShape,XCAFDoc_ColorGen,col) &&
!aColorTool->GetInstanceColor(childShape,XCAFDoc_ColorSurf,col) &&
!aColorTool->GetInstanceColor(childShape,XCAFDoc_ColorCurv,col))
{
auto &c = defaultColor;
aColorTool->SetColor(childLabel, Quantity_Color(c.r,c.g,c.b,Quantity_TOC_RGB), XCAFDoc_ColorGen);
aColorTool->SetColor(childLabel, convertColor(c), XCAFDoc_ColorGen);
FC_WARN(labelName(childLabel) << " set default color");
}
aColorTool->SetVisibility(childLabel,Standard_False);
+3 -2
View File
@@ -322,9 +322,10 @@ private:
return;
}
// vp->MapFaceColor.setValue(false);
if(colors.size() == 1)
if(colors.size() == 1) {
vp->ShapeColor.setValue(colors.front());
else
vp->Transparency.setValue(100 * colors.front().a);
} else
vp->DiffuseColor.setValues(colors);
}
virtual void applyEdgeColors(Part::Feature* part, const std::vector<App::Color>& colors) override {
+1
View File
@@ -76,6 +76,7 @@ PyMOD_INIT_FUNC(Mesh)
Mesh::PropertyMeshKernel ::init();
Mesh::MeshObject ::init();
Mesh::MeshSegment ::init();
Mesh::Feature ::init();
Mesh::FeatureCustom ::init();
+2
View File
@@ -399,6 +399,8 @@ endif ()
add_library(Mesh SHARED ${Core_SRCS} ${WildMagic4_SRCS} ${Mesh_SRCS})
target_link_libraries(Mesh ${Mesh_LIBS})
set_target_properties(Mesh PROPERTIES CXX_STANDARD_REQUIRED ON)
set_target_properties(Mesh PROPERTIES CXX_STANDARD 17)
SET_BIN_DIR(Mesh Mesh /Mod/Mesh)
+1
View File
@@ -46,6 +46,7 @@
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <string_view>
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
+38 -13
View File
@@ -62,6 +62,7 @@ using namespace Mesh;
float MeshObject::Epsilon = 1.0e-5f;
TYPESYSTEM_SOURCE(Mesh::MeshObject, Data::ComplexGeoData)
TYPESYSTEM_SOURCE(Mesh::MeshSegment, Data::Segment)
MeshObject::MeshObject()
{
@@ -93,7 +94,7 @@ MeshObject::~MeshObject()
std::vector<const char*> MeshObject::getElementTypes() const
{
std::vector<const char*> temp;
temp.push_back("Face"); // that's the mesh itself
temp.push_back("Mesh");
temp.push_back("Segment");
return temp;
@@ -102,31 +103,47 @@ std::vector<const char*> MeshObject::getElementTypes() const
unsigned long MeshObject::countSubElements(const char* Type) const
{
std::string element(Type);
if (element == "Face")
if (element == "Mesh")
return 1;
else if (element == "Segment")
return countSegments();
return 0;
}
Data::Segment* MeshObject::getSubElement(const char* Type, unsigned long /*n*/) const
Data::Segment* MeshObject::getSubElement(const char* Type, unsigned long n) const
{
//TODO
std::string element(Type);
if (element == "Face")
return nullptr;
else if (element == "Segment")
return nullptr;
if (element == "Mesh" && n == 0) {
MeshSegment* segm = new MeshSegment();
segm->mesh = new MeshObject(*this);
return segm;
}
else if (element == "Segment" && n < countSegments()) {
MeshSegment* segm = new MeshSegment();
segm->mesh = new MeshObject(*this);
const Segment& faces = getSegment(n);
segm->segment.reset(new Segment(static_cast<MeshObject*>(segm->mesh), faces.getIndices(), false));
return segm;
}
return nullptr;
}
void MeshObject::getFacesFromSubelement(const Data::Segment* /*segm*/,
std::vector<Base::Vector3d> &Points,
std::vector<Base::Vector3d> &/*PointNormals*/,
void MeshObject::getFacesFromSubElement(const Data::Segment* element,
std::vector<Base::Vector3d> &points,
std::vector<Base::Vector3d> &/*pointNormals*/,
std::vector<Facet> &faces) const
{
//TODO
this->getFaces(Points, faces, 0.0f);
if (element && element->getTypeId() == MeshSegment::getClassTypeId()) {
const MeshSegment* segm = static_cast<const MeshSegment*>(element);
if (segm->segment) {
Base::Reference<MeshObject> submesh(segm->mesh->meshFromSegment(segm->segment->getIndices()));
submesh->getFaces(points, faces, 0.0f);
}
else {
segm->mesh->getFaces(points, faces, 0.0f);
}
}
}
void MeshObject::transformGeometry(const Base::Matrix4D &rclMat)
@@ -161,6 +178,14 @@ Base::BoundBox3d MeshObject::getBoundBox()const
return Bnd2;
}
bool MeshObject::getCenterOfGravity(Base::Vector3d& center) const
{
MeshCore::MeshAlgorithm alg(_kernel);
Base::Vector3f pnt = alg.GetGravityPoint();
center = transformToOutside(pnt);
return true;
}
void MeshObject::copySegments(const MeshObject& mesh)
{
// After copying the segments the mesh pointers must be adjusted
+18 -2
View File
@@ -60,6 +60,21 @@ class AbstractPolygonTriangulator;
namespace Mesh
{
class MeshObject;
class MeshExport MeshSegment : public Data::Segment
{
TYPESYSTEM_HEADER();
public:
virtual std::string getName() const {
return "MeshSegment";
}
Base::Reference<MeshObject> mesh;
std::unique_ptr<Mesh::Segment> segment;
};
/**
* The MeshObject class provides an interface for the underlying MeshKernel class and
* most of its algorithm on it.
@@ -97,7 +112,7 @@ public:
/// get the subelement by type and number
virtual Data::Segment* getSubElement(const char* Type, unsigned long) const;
/** Get faces from segment */
virtual void getFacesFromSubelement(
virtual void getFacesFromSubElement(
const Data::Segment*,
std::vector<Base::Vector3d> &Points,
std::vector<Base::Vector3d> &PointNormals,
@@ -142,7 +157,8 @@ public:
const MeshCore::MeshKernel& getKernel() const
{ return _kernel; }
virtual Base::BoundBox3d getBoundBox()const;
virtual Base::BoundBox3d getBoundBox() const;
virtual bool getCenterOfGravity(Base::Vector3d& center) const;
/** @name I/O */
//@{
+6 -1
View File
@@ -184,7 +184,12 @@ lines = mesh.section(mesh2, [ConnectLines=True, MinDist=0.0001])
</UserDocu>
</Documentation>
</Methode>
<Methode Name="countSegments" Const="true">
<Methode Name="addSegment">
<Documentation>
<UserDocu>Add a list of facet indices that describes a segment to the mesh</UserDocu>
</Documentation>
</Methode>
<Methode Name="countSegments" Const="true">
<Documentation>
<UserDocu>Get the number of segments which may also be 0</UserDocu>
</Documentation>
+21
View File
@@ -845,6 +845,27 @@ PyObject* MeshPy::getPointNormals(PyObject *args)
} PY_CATCH;
}
PyObject* MeshPy::addSegment(PyObject *args)
{
PyObject* pylist;
if (!PyArg_ParseTuple(args, "O", &pylist))
return nullptr;
Py::Sequence list(pylist);
std::vector<Mesh::FacetIndex> segment;
unsigned long numFacets = getMeshObjectPtr()->countFacets();
segment.reserve(list.size());
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
Py::Long value(*it);
Mesh::FacetIndex index = static_cast<unsigned long>(value);
if (index < numFacets)
segment.push_back(index);
}
getMeshObjectPtr()->addSegment(segment);
Py_Return;
}
PyObject* MeshPy::countSegments(PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
+78
View File
@@ -5,6 +5,7 @@
# LGPL
import FreeCAD, os, sys, unittest, Mesh
from FreeCAD import Base
import time, tempfile, math
# http://python-kurs.eu/threads.php
try:
@@ -46,6 +47,43 @@ class MeshTopoTestCases(unittest.TestCase):
planarMeshObject = Mesh.Mesh(self.planarMesh)
planarMeshObject.collapseFacets(range(18))
def testCorruptedFacet(self):
v = FreeCAD.Vector
mesh = Mesh.Mesh()
mesh.addFacet(
v(1.0e1, -1.0e1, 1.0e1),
v(1.0e1, +1.0e1, 1.0e1),
v(0.0e0, 0.0e0, 1.0e1))
mesh.addFacet(
v(-1.0e1, -1.0e1, 1.0e1),
v(-1.0e1, +1.0e1, 1.0e1),
v(0e0, 0.0e0, 1.0e1))
mesh.addFacet(
v(+1.0e1, +1.0e1, 1.0e1),
v(-1.0e1, +1.0e1, 1.0e1),
v(.0e0, 0.0e0, 1.0e1))
mesh.addFacet(
v(+1.0e1, -1.0e1, 1.0e1),
v(-1.0e1, -1.0e1, 1.0e1),
v(.0e0, 0.0e0, 1.0e1))
mesh.addFacet(
v(-1.0e1, +1.0e1, 1.0e1),
v(+1.0e1, +1.0e1, 1.0e1),
v(+1.0e1, +1.0e1, 1.0e1))
mesh.addFacet(
v(+1.0e1, +1.0e1, 1.0e1),
v(+1.0e1, 00.0e1, 1.0e1),
v(+1.0e1, -1.0e1, 1.0e1))
self.assertEqual(mesh.CountFacets, 6)
mesh.fixIndices()
self.assertEqual(mesh.CountFacets, 5)
class MeshSplitTestCases(unittest.TestCase):
def setUp(self):
@@ -363,3 +401,43 @@ class NastranReader(unittest.TestCase):
def tearDown(self):
pass
class MeshSubElement(unittest.TestCase):
def setUp(self):
self.mesh = Mesh.createBox(1.0, 1.0, 1.0)
def testCenterOfGravity(self):
c = self.mesh.CenterOfGravity
self.assertEqual(c, Base.Vector(0.0, 0.0, 0.0))
def testSubElements(self):
types = self.mesh.getElementTypes()
self.assertIn("Mesh", types)
self.assertIn("Segment", types)
def testCountSubElements(self):
self.assertEqual(self.mesh.countSubElements("Mesh"), 1)
self.assertEqual(self.mesh.countSubElements("Segment"), 0)
def testFacesFromSubElement(self):
element = self.mesh.getFacesFromSubElement("Mesh", 0)
self.assertIsInstance(element, tuple)
self.assertEqual(len(element), 2)
self.assertEqual(len(element[0]), 8)
self.assertEqual(len(element[1]), 12)
def testSegmentSubElement(self):
self.mesh.addSegment([0, 2, 4, 6, 8])
self.assertEqual(self.mesh.countSegments(), 1)
self.assertEqual(self.mesh.countSubElements("Segment"), 1)
element = self.mesh.getFacesFromSubElement("Segment", 0)
self.assertIsInstance(element, tuple)
self.assertEqual(len(element), 2)
self.assertEqual(len(element[0]), 7)
self.assertEqual(len(element[1]), 5)
segment = self.mesh.meshFromSegment(self.mesh.getSegment(0))
self.assertEqual(segment.CountPoints, 7)
self.assertEqual(segment.CountFacets, 5)
def tearDown(self):
pass
+1 -1
View File
@@ -569,7 +569,7 @@ int System::Write8be (FILE* pkFile, int iQuantity, const void* pvData)
const char* System::GetPath (const char* acDirectory, const char* acFilename)
{
// #0000656: WildMagic4 doesn't build on 64-bit Mac OS
#if defined(__APPLE__) && !defined(__x86_64__)
#if defined(__APPLE__) && !defined(__aarch64__) && !defined(__x86_64__)
// An application-relative path is needed for the applications to be able
// to find the input data sets. Unfortunately, there is no exact way to
// predict which directory the application is run from, since this depends
@@ -237,7 +237,7 @@
</size>
</property>
<property name="toolTip">
<string>The path to the directory for transfering files to and from OpenSCAD</string>
<string>The path to the directory for transferring files to and from OpenSCAD</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>transferdirectory</cstring>
+13 -21
View File
@@ -134,6 +134,7 @@
#include "PartFeature.h"
#include "PartPyCXX.h"
#include "modelRefine.h"
#include "Tools.h"
#ifdef FCUseFreeType
# include "FT2FC.h"
@@ -804,33 +805,24 @@ private:
auto theShape = static_cast<Part::TopoShapePy*>(shape)->getTopoShapePtr()->getShape();
for (TopExp_Explorer ex(theShape, TopAbs_FACE); ex.More(); ex.Next()) {
TopoDS_Face currentFace = TopoDS::Face(ex.Current());
TopLoc_Location loc;
Handle(Poly_Triangulation) facets = BRep_Tool::Triangulation(currentFace, loc);
const TopAbs_Orientation anOrientation = currentFace.Orientation();
bool flip = (anOrientation == TopAbs_REVERSED);
if (!facets.IsNull()) {
const TColgp_Array1OfPnt& nodes = facets->Nodes();
const Poly_Array1OfTriangle& triangles = facets->Triangles();
for (int i = 1; i <= triangles.Length(); i++) {
std::vector<gp_Pnt> points;
std::vector<Poly_Triangle> facets;
if (Tools::getTriangulation(currentFace, points, facets)) {
for (const auto& it : facets) {
Standard_Integer n1,n2,n3;
triangles(i).Get(n1, n2, n3);
gp_Pnt p1 = nodes(n1);
gp_Pnt p2 = nodes(n2);
gp_Pnt p3 = nodes(n3);
p1.Transform(loc.Transformation());
p2.Transform(loc.Transformation());
p3.Transform(loc.Transformation());
it.Get(n1, n2, n3);
gp_Pnt p1 = points[n1];
gp_Pnt p2 = points[n2];
gp_Pnt p3 = points[n3];
// TODO: verify if tolerance should be hard coded
if (!p1.IsEqual(p2, 0.01) && !p2.IsEqual(p3, 0.01) && !p3.IsEqual(p1, 0.01)) {
PyObject *t1 = PyTuple_Pack(3, PyFloat_FromDouble(p1.X()), PyFloat_FromDouble(p1.Y()), PyFloat_FromDouble(p1.Z()));
PyObject *t2 = PyTuple_Pack(3, PyFloat_FromDouble(p2.X()), PyFloat_FromDouble(p2.Y()), PyFloat_FromDouble(p2.Z()));
PyObject *t3 = PyTuple_Pack(3, PyFloat_FromDouble(p3.X()), PyFloat_FromDouble(p3.Y()), PyFloat_FromDouble(p3.Z()));
if (flip) {
list.append(Py::asObject(PyTuple_Pack(3, t2, t1, t3)));
}
else {
list.append(Py::asObject(PyTuple_Pack(3, t1, t2, t3)));
}
list.append(Py::asObject(PyTuple_Pack(3, t1, t2, t3)));
}
}
}
@@ -24,10 +24,13 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <GeomAdaptor_Curve.hxx>
# include <GeomAdaptor_HCurve.hxx>
# include <Geom2dAdaptor_Curve.hxx>
# include <Geom2dAdaptor_HCurve.hxx>
# include <Standard_Failure.hxx>
# include <Standard_Version.hxx>
# if OCC_VERSION_HEX < 0x070600
# include <GeomAdaptor_HCurve.hxx>
# include <Geom2dAdaptor_HCurve.hxx>
# endif
#endif
#include "GeomPlate/CurveConstraintPy.h"
@@ -76,6 +79,16 @@ int CurveConstraintPy::PyInit(PyObject* args, PyObject* kwds)
return -1;
}
#if OCC_VERSION_HEX >= 0x070600
Handle(Adaptor3d_Curve) hCurve;
if (curve->getTypeId().isDerivedFrom(GeomTrimmedCurve::getClassTypeId())) {
GeomTrimmedCurve* trim = static_cast<GeomTrimmedCurve*>(curve);
hCurve = new GeomAdaptor_Curve(handle, trim->getFirstParameter(), trim->getLastParameter());
}
else {
hCurve = new GeomAdaptor_Curve(handle);
}
#else
Handle(Adaptor3d_HCurve) hCurve;
if (curve->getTypeId().isDerivedFrom(GeomTrimmedCurve::getClassTypeId())) {
GeomTrimmedCurve* trim = static_cast<GeomTrimmedCurve*>(curve);
@@ -86,6 +99,7 @@ int CurveConstraintPy::PyInit(PyObject* args, PyObject* kwds)
GeomAdaptor_Curve adapt(handle);
hCurve = new GeomAdaptor_HCurve(adapt);
}
#endif
ptr.reset(new GeomPlate_CurveConstraint(hCurve, order, nbPts, tolDist, tolAng, tolCurv));
}
@@ -212,11 +226,15 @@ PyObject* CurveConstraintPy::curve3d(PyObject *args)
return nullptr;
try {
Handle(Adaptor3d_HCurve) hAdapt = getGeomPlate_CurveConstraintPtr()->Curve3d();
auto hAdapt = getGeomPlate_CurveConstraintPtr()->Curve3d();
if (hAdapt.IsNull())
Py_Return;
#if OCC_VERSION_HEX >= 0x070600
const Adaptor3d_Curve& a3d = *hAdapt;
#else
const Adaptor3d_Curve& a3d = hAdapt->Curve();
#endif
std::unique_ptr<GeomCurve> ptr(Part::makeFromCurveAdaptor(a3d));
return ptr->getPyObject();
}
@@ -282,6 +300,16 @@ PyObject* CurveConstraintPy::setProjectedCurve(PyObject *args)
return nullptr;
}
#if OCC_VERSION_HEX >= 0x070600
Handle(Adaptor2d_Curve2d) hCurve;
if (handle->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) {
Handle(Geom2d_TrimmedCurve) aTC (Handle(Geom2d_TrimmedCurve)::DownCast (handle));
hCurve = new Geom2dAdaptor_Curve(handle, aTC->FirstParameter(), aTC->LastParameter());
}
else {
hCurve = new Geom2dAdaptor_Curve(handle);
}
#else
Handle(Adaptor2d_HCurve2d) hCurve;
if (handle->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) {
Handle(Geom2d_TrimmedCurve) aTC (Handle(Geom2d_TrimmedCurve)::DownCast (handle));
@@ -292,6 +320,7 @@ PyObject* CurveConstraintPy::setProjectedCurve(PyObject *args)
Geom2dAdaptor_Curve adapt(handle);
hCurve = new Geom2dAdaptor_HCurve(adapt);
}
#endif
getGeomPlate_CurveConstraintPtr()->SetProjectedCurve(hCurve, tolU, tolV);
Py_Return;
@@ -308,11 +337,15 @@ PyObject* CurveConstraintPy::projectedCurve(PyObject *args)
return nullptr;
try {
Handle(Adaptor2d_HCurve2d) hAdapt = getGeomPlate_CurveConstraintPtr()->ProjectedCurve();
auto hAdapt = getGeomPlate_CurveConstraintPtr()->ProjectedCurve();
if (hAdapt.IsNull())
Py_Return;
#if OCC_VERSION_HEX >= 0x070600
const Adaptor2d_Curve2d& a2d = *hAdapt;
#else
const Adaptor2d_Curve2d& a2d = hAdapt->Curve2d();
#endif
std::unique_ptr<Geom2dCurve> ptr(Part::makeFromCurveAdaptor2d(a2d));
return ptr->getPyObject();
}
+6 -1
View File
@@ -51,7 +51,6 @@
# include <Geom_RectangularTrimmedSurface.hxx>
# include <Geom_SurfaceOfRevolution.hxx>
# include <Geom_SurfaceOfLinearExtrusion.hxx>
# include <GeomAdaptor_HCurve.hxx>
# include <GeomAPI_Interpolate.hxx>
# include <GeomConvert.hxx>
# include <GeomConvert_CompCurveToBSplineCurve.hxx>
@@ -101,6 +100,9 @@
# include <GeomAPI_ExtremaCurveCurve.hxx>
# include <ShapeConstruct_Curve.hxx>
# include <LProp_NotDefined.hxx>
# if OCC_VERSION_HEX < 0x070600
# include <GeomAdaptor_HCurve.hxx>
# endif
# include <ctime>
# include <cmath>
@@ -144,6 +146,9 @@
#include "Geometry.h"
#if OCC_VERSION_HEX >= 0x070600
using GeomAdaptor_HCurve = GeomAdaptor_Curve;
#endif
using namespace Part;
+5
View File
@@ -22,6 +22,11 @@
<UserDocu>Return the shape for the geometry.</UserDocu>
</Documentation>
</Methode>
<Methode Name="toShell" Const="true" Keyword="true">
<Documentation>
<UserDocu>Make a shell of the surface.</UserDocu>
</Documentation>
</Methode>
<Methode Name="getD0" Const="true">
<Documentation>
<UserDocu>Returns the point of given parameter</UserDocu>
+48
View File
@@ -25,6 +25,7 @@
#ifndef _PreComp_
# include <BRepBuilderAPI_MakeFace.hxx>
# include <BRepBuilderAPI_MakeShell.hxx>
# include <gp_Circ.hxx>
# include <gp_Dir.hxx>
# include <gp_Elips.hxx>
@@ -74,6 +75,7 @@
#include <Mod/Part/App/TopoShape.h>
#include <Mod/Part/App/TopoShapePy.h>
#include <Mod/Part/App/TopoShapeFacePy.h>
#include <Mod/Part/App/TopoShapeShellPy.h>
namespace Part {
const Py::Object makeTrimmedCurvePy(const Handle(Geom_Curve)& c, double f, double l)
@@ -153,6 +155,52 @@ PyObject* GeometrySurfacePy::toShape(PyObject *args)
return 0;
}
PyObject* GeometrySurfacePy::toShell(PyObject *args, PyObject* kwds)
{
PyObject* bound = nullptr;
PyObject* segm = nullptr;
static char *kwlist[] = {"Bounds", "Segment", nullptr};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!O!", kwlist,
&PyTuple_Type, &bound, &PyBool_Type, &segm))
return nullptr;
Handle(Geom_Geometry) g = getGeometryPtr()->handle();
Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(g);
try {
if (!s.IsNull()) {
if (segm) {
Standard_Boolean segment = PyObject_IsTrue(segm) ? Standard_True : Standard_False;
BRepBuilderAPI_MakeShell mkBuilder(s, segment);
TopoDS_Shape sh = mkBuilder.Shape();
return new TopoShapeShellPy(new TopoShape(sh));
}
else {
double u1,u2,v1,v2;
s->Bounds(u1,u2,v1,v2);
if (bound) {
Py::Tuple tuple(bound);
u1 = double(Py::Float(tuple[0]));
u2 = double(Py::Float(tuple[1]));
v1 = double(Py::Float(tuple[2]));
v2 = double(Py::Float(tuple[3]));
}
BRepBuilderAPI_MakeShell mkBuilder(s, u1, u2, v1, v2);
TopoDS_Shape sh = mkBuilder.Shape();
return new TopoShapeShellPy(new TopoShape(sh));
}
}
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
PyErr_SetString(PartExceptionOCCError, "Geometry is not a surface");
return nullptr;
}
PyObject* GeometrySurfacePy::getD0(PyObject *args)
{
Handle(Geom_Geometry) g = getGeometryPtr()->handle();
+1
View File
@@ -216,6 +216,7 @@
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRepBuilderAPI_MakePolygon.hxx>
#include <BRepBuilderAPI_MakeShell.hxx>
#include <BRepBuilderAPI_MakeSolid.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
#include <BRepBuilderAPI_Sewing.hxx>
+8 -14
View File
@@ -25,9 +25,7 @@
#ifndef _PreComp_
# include <BRepFill.hxx>
# include <BRepAdaptor_Curve.hxx>
# include <BRepAdaptor_HCurve.hxx>
# include <BRepAdaptor_CompCurve.hxx>
# include <BRepAdaptor_HCompCurve.hxx>
# include <BRepLib_MakeWire.hxx>
# include <Geom_BSplineSurface.hxx>
# include <TopoDS.hxx>
@@ -43,7 +41,7 @@
# include <TopExp_Explorer.hxx>
# include <TopoDS.hxx>
# include <Precision.hxx>
# include <Adaptor3d_HCurve.hxx>
# include <memory>
#endif
@@ -170,22 +168,18 @@ App::DocumentObjectExecReturn *RuledSurface::execute(void)
if (Orientation.getValue() == 0) {
// Automatic
Handle(Adaptor3d_HCurve) a1;
Handle(Adaptor3d_HCurve) a2;
std::unique_ptr<Adaptor3d_Curve> a1;
std::unique_ptr<Adaptor3d_Curve> a2;
if (!isWire) {
BRepAdaptor_Curve adapt1(TopoDS::Edge(S1));
BRepAdaptor_Curve adapt2(TopoDS::Edge(S2));
a1 = new BRepAdaptor_HCurve(adapt1);
a2 = new BRepAdaptor_HCurve(adapt2);
a1 = std::make_unique<BRepAdaptor_Curve>(TopoDS::Edge(S1));
a2 = std::make_unique<BRepAdaptor_Curve>(TopoDS::Edge(S2));
}
else {
BRepAdaptor_CompCurve adapt1(TopoDS::Wire(S1));
BRepAdaptor_CompCurve adapt2(TopoDS::Wire(S2));
a1 = new BRepAdaptor_HCompCurve(adapt1);
a2 = new BRepAdaptor_HCompCurve(adapt2);
a1 = std::make_unique<BRepAdaptor_CompCurve>(TopoDS::Wire(S1));
a2 = std::make_unique<BRepAdaptor_CompCurve>(TopoDS::Wire(S2));
}
if (!a1.IsNull() && !a2.IsNull()) {
if (a1 && a2) {
// get end points of 1st curve
Standard_Real first, last;
first = a1->FirstParameter();
+1
View File
@@ -94,6 +94,7 @@
#include "OpenCascadeAll.h"
#include <math_Gauss.hxx>
#include <math_Matrix.hxx>
#include <Poly_Connect.hxx>
#elif defined(FC_OS_WIN32)
#define WIN32_LEAN_AND_MEAN
+402 -2
View File
@@ -25,25 +25,35 @@
# include <cassert>
# include <gp_Pln.hxx>
# include <gp_Lin.hxx>
# include <Adaptor3d_HCurveOnSurface.hxx>
# include <BRep_Tool.hxx>
# include <Geom_BSplineSurface.hxx>
# include <Geom_Plane.hxx>
# include <GeomAdaptor_HCurve.hxx>
# include <GeomAPI_IntSS.hxx>
# include <GeomAPI_ProjectPointOnSurf.hxx>
# include <Geom_Line.hxx>
# include <Geom_Point.hxx>
# include <GeomAdaptor_Curve.hxx>
# include <GeomLib.hxx>
# include <GeomPlate_BuildPlateSurface.hxx>
# include <GeomPlate_CurveConstraint.hxx>
# include <GeomPlate_MakeApprox.hxx>
# include <GeomPlate_PlateG0Criterion.hxx>
# include <GeomPlate_PointConstraint.hxx>
# include <Poly_Connect.hxx>
# include <Poly_Triangulation.hxx>
# include <Precision.hxx>
# include <Standard_Mutex.hxx>
# include <Standard_TypeMismatch.hxx>
# include <Standard_Version.hxx>
# include <TColStd_ListOfTransient.hxx>
# include <TColStd_ListIteratorOfListOfTransient.hxx>
# include <TColgp_SequenceOfXY.hxx>
# include <TColgp_SequenceOfXYZ.hxx>
# include <TopoDS.hxx>
# if OCC_VERSION_HEX < 0x070600
# include <Adaptor3d_HCurveOnSurface.hxx>
# include <GeomAdaptor_HCurve.hxx>
# endif
#endif
#include <Base/Vector3D.h>
@@ -138,6 +148,20 @@ Part::Tools::makeSurface(const TColStd_ListOfTransient &theBoundaries,
assert (0);
Standard_ConstructionError::Raise ("Tools::makeSurface()");
}
#if OCC_VERSION_HEX >= 0x070600
else if (aCur->IsKind (STANDARD_TYPE (Adaptor3d_CurveOnSurface))) {
//G1 constraint
Handle(Adaptor3d_CurveOnSurface) aHCOS (Handle(Adaptor3d_CurveOnSurface)::DownCast (aCur));
Handle (GeomPlate_CurveConstraint) aConst = new GeomPlate_CurveConstraint (aHCOS, 1 /*GeomAbs_G1*/,aNbPnts, aTol3d, anAngTol, aCurvTol);
aPlateBuilder.Add (aConst);
}
else if (aCur->IsKind (STANDARD_TYPE (GeomAdaptor_Curve))) {
//G0 constraint
Handle(GeomAdaptor_Curve) aHC (Handle(GeomAdaptor_Curve)::DownCast (aCur));
Handle (GeomPlate_CurveConstraint) aConst = new GeomPlate_CurveConstraint (aHC, 0 /*GeomAbs_G0*/, aNbPnts, aTol3d);
aPlateBuilder.Add (aConst);
}
#else
else if (aCur->IsKind (STANDARD_TYPE (Adaptor3d_HCurveOnSurface))) {
//G1 constraint
Handle(Adaptor3d_HCurveOnSurface) aHCOS (Handle(Adaptor3d_HCurveOnSurface)::DownCast (aCur));
@@ -150,6 +174,7 @@ Part::Tools::makeSurface(const TColStd_ListOfTransient &theBoundaries,
Handle (GeomPlate_CurveConstraint) aConst = new GeomPlate_CurveConstraint (aHC, 0 /*GeomAbs_G0*/, aNbPnts, aTol3d);
aPlateBuilder.Add (aConst);
}
#endif
else if (aCur->IsKind (STANDARD_TYPE (Geom_Point))) {
//Point constraint
Handle(Geom_Point) aGP (Handle(Geom_Point)::DownCast (aCur));
@@ -190,3 +215,378 @@ Part::Tools::makeSurface(const TColStd_ListOfTransient &theBoundaries,
return aRes;
}
bool Part::Tools::getTriangulation(const TopoDS_Face& face, std::vector<gp_Pnt>& points, std::vector<Poly_Triangle>& facets)
{
TopLoc_Location loc;
Handle(Poly_Triangulation) hTria = BRep_Tool::Triangulation(face, loc);
if (hTria.IsNull())
return false;
// getting the transformation of the face
gp_Trsf transf;
bool identity = true;
if (!loc.IsIdentity()) {
identity = false;
transf = loc.Transformation();
}
// check orientation
TopAbs_Orientation orient = face.Orientation();
Standard_Integer nbNodes = hTria->NbNodes();
Standard_Integer nbTriangles = hTria->NbTriangles();
#if OCC_VERSION_HEX < 0x070600
const TColgp_Array1OfPnt& nodes = hTria->Nodes();
const Poly_Array1OfTriangle& triangles = hTria->Triangles();
#endif
points.reserve(nbNodes);
facets.reserve(nbTriangles);
// cycling through the poly mesh
//
for (int i = 1; i <= nbNodes; i++) {
#if OCC_VERSION_HEX < 0x070600
gp_Pnt p = nodes(i);
#else
gp_Pnt p = hTria->Node(i);
#endif
// transform the vertices to the location of the face
if (!identity) {
p.Transform(transf);
}
points.push_back(p);
}
for (int i = 1; i <= nbTriangles; i++) {
// Get the triangle
Standard_Integer n1,n2,n3;
#if OCC_VERSION_HEX < 0x070600
triangles(i).Get(n1, n2, n3);
#else
hTria->Triangle(i).Get(n1, n2, n3);
#endif
--n1; --n2; --n3;
// change orientation of the triangles
if (orient != TopAbs_FORWARD) {
std::swap(n1, n2);
}
facets.emplace_back(n1, n2, n3);
}
return true;
}
bool Part::Tools::getPolygonOnTriangulation(const TopoDS_Edge& edge, const TopoDS_Face& face, std::vector<gp_Pnt>& points)
{
TopLoc_Location loc;
Handle(Poly_Triangulation) hTria = BRep_Tool::Triangulation(face, loc);
if (hTria.IsNull())
return false;
// this holds the indices of the edge's triangulation to the actual points
Handle(Poly_PolygonOnTriangulation) hPoly = BRep_Tool::PolygonOnTriangulation(edge, hTria, loc);
if (hPoly.IsNull())
return false;
// getting the transformation of the edge
gp_Trsf transf;
bool identity = true;
if (!loc.IsIdentity()) {
identity = false;
transf = loc.Transformation();
}
// getting size and create the array
Standard_Integer nbNodes = hPoly->NbNodes();
points.reserve(nbNodes);
const TColStd_Array1OfInteger& indices = hPoly->Nodes();
#if OCC_VERSION_HEX < 0x070600
const TColgp_Array1OfPnt& Nodes = hTria->Nodes();
#endif
// go through the index array
for (Standard_Integer i = indices.Lower(); i <= indices.Upper(); i++) {
#if OCC_VERSION_HEX < 0x070600
gp_Pnt p = Nodes(indices(i));
#else
gp_Pnt p = hTria->Node(indices(i));
#endif
if (!identity) {
p.Transform(transf);
}
points.push_back(p);
}
return true;
}
bool Part::Tools::getPolygon3D(const TopoDS_Edge& edge, std::vector<gp_Pnt>& points)
{
TopLoc_Location loc;
Handle(Poly_Polygon3D) hPoly = BRep_Tool::Polygon3D(edge, loc);
if (hPoly.IsNull())
return false;
// getting the transformation of the edge
gp_Trsf transf;
bool identity = true;
if (!loc.IsIdentity()) {
identity = false;
transf = loc.Transformation();
}
// getting size and create the array
Standard_Integer nbNodes = hPoly->NbNodes();
points.reserve(nbNodes);
const TColgp_Array1OfPnt& nodes = hPoly->Nodes();
for (int i = 1; i <= nbNodes; i++) {
gp_Pnt p = nodes(i);
// transform the vertices to the location of the face
if (!identity) {
p.Transform(transf);
}
points.push_back(p);
}
return true;
}
void Part::Tools::getPointNormals(const std::vector<gp_Pnt>& points, const std::vector<Poly_Triangle>& facets, std::vector<gp_Vec>& vertexnormals)
{
vertexnormals.resize(points.size());
for (const auto& it : facets) {
// Get the triangle
Standard_Integer n1,n2,n3;
it.Get(n1,n2,n3);
// Calculate triangle normal
gp_Vec v1(points[n1].XYZ());
gp_Vec v2(points[n2].XYZ());
gp_Vec v3(points[n3].XYZ());
gp_Vec n = (v2 - v1) ^ (v3 - v1);
// add the triangle normal to the vertex normal for all points of this triangle
vertexnormals[n1] += n;
vertexnormals[n2] += n;
vertexnormals[n3] += n;
}
for (auto& it : vertexnormals)
it.Normalize();
}
void Part::Tools::getPointNormals(const std::vector<gp_Pnt>& points, const TopoDS_Face& face, std::vector<gp_Vec>& vertexnormals)
{
if (points.size() != vertexnormals.size())
return;
Handle(Geom_Surface) hSurface = BRep_Tool::Surface(face);
if (hSurface.IsNull())
return;
// normalize all vertex normals
for (std::size_t i = 0; i < points.size(); i++) {
try {
GeomAPI_ProjectPointOnSurf ProPntSrf(points[i], hSurface);
Standard_Real u, v;
ProPntSrf.Parameters(1, u, v);
GeomLProp_SLProps propOfFace(hSurface, u, v, 2, gp::Resolution());
gp_Dir normal = propOfFace.Normal();
gp_Vec temp = normal;
if (temp * vertexnormals[i] < 0.0)
temp = -temp;
vertexnormals[i] = temp;
}
catch (...) {
}
vertexnormals[i].Normalize();
}
}
void Part::Tools::getPointNormals(const TopoDS_Face& theFace, Handle(Poly_Triangulation) aPolyTri, TColgp_Array1OfDir& theNormals)
{
#if OCC_VERSION_HEX < 0x070600
const TColgp_Array1OfPnt& aNodes = aPolyTri->Nodes();
if(aPolyTri->HasNormals())
{
// normals pre-computed in triangulation structure
const TShort_Array1OfShortReal& aNormals = aPolyTri->Normals();
const Standard_ShortReal* aNormArr = &(aNormals.Value(aNormals.Lower()));
for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
{
const Standard_Integer anId = 3 * (aNodeIter - aNodes.Lower());
const gp_Dir aNorm(aNormArr[anId + 0],
aNormArr[anId + 1],
aNormArr[anId + 2]);
theNormals(aNodeIter) = aNorm;
}
if(theFace.Orientation() == TopAbs_REVERSED)
{
for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
{
theNormals.ChangeValue(aNodeIter).Reverse();
}
}
}
else {
// take in face the surface location
Poly_Connect thePolyConnect(aPolyTri);
const TopoDS_Face aZeroFace = TopoDS::Face(theFace.Located(TopLoc_Location()));
Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aZeroFace);
const Standard_Real aTol = Precision::Confusion();
Handle(TShort_HArray1OfShortReal) aNormals = new TShort_HArray1OfShortReal(1, aPolyTri->NbNodes() * 3);
const Poly_Array1OfTriangle& aTriangles = aPolyTri->Triangles();
const TColgp_Array1OfPnt2d* aNodesUV = aPolyTri->HasUVNodes() && !aSurf.IsNull()
? &aPolyTri->UVNodes()
: nullptr;
Standard_Integer aTri[3];
for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
{
// try to retrieve normal from real surface first, when UV coordinates are available
if (!aNodesUV || GeomLib::NormEstim(aSurf, aNodesUV->Value(aNodeIter), aTol, theNormals(aNodeIter)) > 1)
{
// compute flat normals
gp_XYZ eqPlan(0.0, 0.0, 0.0);
for(thePolyConnect.Initialize(aNodeIter); thePolyConnect.More(); thePolyConnect.Next())
{
aTriangles(thePolyConnect.Value()).Get(aTri[0], aTri[1], aTri[2]);
const gp_XYZ v1(aNodes(aTri[1]).Coord() - aNodes(aTri[0]).Coord());
const gp_XYZ v2(aNodes(aTri[2]).Coord() - aNodes(aTri[1]).Coord());
const gp_XYZ vv = v1 ^ v2;
const Standard_Real aMod = vv.Modulus();
if(aMod >= aTol)
{
eqPlan += vv / aMod;
}
}
const Standard_Real aModMax = eqPlan.Modulus();
theNormals(aNodeIter) = (aModMax > aTol) ? gp_Dir(eqPlan) : gp::DZ();
}
const Standard_Integer anId = (aNodeIter - aNodes.Lower()) * 3;
aNormals->SetValue(anId + 1, (Standard_ShortReal)theNormals(aNodeIter).X());
aNormals->SetValue(anId + 2, (Standard_ShortReal)theNormals(aNodeIter).Y());
aNormals->SetValue(anId + 3, (Standard_ShortReal)theNormals(aNodeIter).Z());
}
aPolyTri->SetNormals(aNormals);
if(theFace.Orientation() == TopAbs_REVERSED)
{
for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
{
theNormals.ChangeValue(aNodeIter).Reverse();
}
}
}
#else
Standard_Integer numNodes = aPolyTri->NbNodes();
if(aPolyTri->HasNormals())
{
for(Standard_Integer aNodeIter = 1; aNodeIter <= numNodes; ++aNodeIter)
{
theNormals(aNodeIter) = aPolyTri->Normal(aNodeIter);
}
if(theFace.Orientation() == TopAbs_REVERSED)
{
for(Standard_Integer aNodeIter = 1; aNodeIter <= numNodes; ++aNodeIter)
{
theNormals.ChangeValue(aNodeIter).Reverse();
}
}
}
else {
// take in face the surface location
Poly_Connect thePolyConnect(aPolyTri);
const TopoDS_Face aZeroFace = TopoDS::Face(theFace.Located(TopLoc_Location()));
Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aZeroFace);
const Standard_Real aTol = Precision::Confusion();
Standard_Boolean hasNodesUV = aPolyTri->HasUVNodes() && !aSurf.IsNull();
Standard_Integer aTri[3];
aPolyTri->AddNormals();
for(Standard_Integer aNodeIter = 1; aNodeIter <= numNodes; ++aNodeIter)
{
// try to retrieve normal from real surface first, when UV coordinates are available
if (!hasNodesUV || GeomLib::NormEstim(aSurf, aPolyTri->UVNode(aNodeIter), aTol, theNormals(aNodeIter)) > 1)
{
// compute flat normals
gp_XYZ eqPlan(0.0, 0.0, 0.0);
for(thePolyConnect.Initialize(aNodeIter); thePolyConnect.More(); thePolyConnect.Next())
{
aPolyTri->Triangle(thePolyConnect.Value()).Get(aTri[0], aTri[1], aTri[2]);
const gp_XYZ v1(aPolyTri->Node(aTri[1]).Coord() - aPolyTri->Node(aTri[0]).Coord());
const gp_XYZ v2(aPolyTri->Node(aTri[2]).Coord() - aPolyTri->Node(aTri[1]).Coord());
const gp_XYZ vv = v1 ^ v2;
const Standard_Real aMod = vv.Modulus();
if(aMod >= aTol)
{
eqPlan += vv / aMod;
}
}
const Standard_Real aModMax = eqPlan.Modulus();
theNormals(aNodeIter) = (aModMax > aTol) ? gp_Dir(eqPlan) : gp::DZ();
}
aPolyTri->SetNormal(aNodeIter, theNormals(aNodeIter));
}
if(theFace.Orientation() == TopAbs_REVERSED)
{
for(Standard_Integer aNodeIter = 1; aNodeIter <= numNodes; ++aNodeIter)
{
theNormals.ChangeValue(aNodeIter).Reverse();
}
}
}
#endif
}
void Part::Tools::getPointNormals(const TopoDS_Face& face, Handle(Poly_Triangulation) aPoly, std::vector<gp_Vec>& normals)
{
TColgp_Array1OfDir dirs (1, aPoly->NbNodes());
getPointNormals(face, aPoly, dirs);
normals.reserve(aPoly->NbNodes());
for (int i = dirs.Lower(); i <= dirs.Upper(); ++i) {
normals.emplace_back(dirs(i).XYZ());
}
}
void Part::Tools::applyTransformationOnNormals(const TopLoc_Location& loc, std::vector<gp_Vec>& normals)
{
if (!loc.IsIdentity()) {
gp_Trsf myTransf = loc.Transformation();
for (auto& it : normals) {
it.Transform(myTransf);
}
}
}
+73 -1
View File
@@ -30,7 +30,14 @@
#include <gp_Dir.hxx>
#include <gp_XYZ.hxx>
#include <Geom_Surface.hxx>
#include <Poly_Triangle.hxx>
#include <Poly_Triangulation.hxx>
#include <TColStd_ListOfTransient.hxx>
#include <TColgp_Array1OfDir.hxx>
#include <TopLoc_Location.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <vector>
class gp_Lin;
class gp_Pln;
@@ -104,7 +111,72 @@ public:
const Standard_Integer theNbPnts,
const Standard_Integer theNbIter,
const Standard_Integer theMaxDeg);
/*!
* @brief getTriangulation
* The indexes of the triangles are adjusted to the points vector.
* @param face
* @param points
* @param facets
* @return true if a triangulation exists or false otherwise
*/
static bool getTriangulation(const TopoDS_Face& face, std::vector<gp_Pnt>& points, std::vector<Poly_Triangle>& facets);
/*!
* \brief getPolygonOnTriangulation
* Get the polygon of edge.
* \note \a edge must belong to face.
* \param edge
* \param face
* \param points
* \return true if a triangulation exists or false otherwise
*/
static bool getPolygonOnTriangulation(const TopoDS_Edge& edge, const TopoDS_Face& face, std::vector<gp_Pnt>& points);
/*!
* \brief getPolygon3D
* \param edge
* \param points
* \return true if a polygon exists or false otherwise
*/
static bool getPolygon3D(const TopoDS_Edge& edge, std::vector<gp_Pnt>& points);
/*!
* \brief getPointNormals
* Calculate the point normals of the given triangulation.
* \param points
* \param facets
* \param normals
*/
static void getPointNormals(const std::vector<gp_Pnt>& points, const std::vector<Poly_Triangle>& facets, std::vector<gp_Vec>& vertexnormals);
/*!
* \brief getPointNormals
* Computes the more accurate surface normals for the points. If the calculation for a point fails then the precomputed
* point normal of the triangulation is used.
* \param points
* \param face
* \param vertexnormals
*/
static void getPointNormals(const std::vector<gp_Pnt>& points, const TopoDS_Face& face, std::vector<gp_Vec>& vertexnormals);
/*!
* \brief getPointNormals
* Computes the exact surface normals for the points by using the UV coordinates of the mesh vertexes.
* \param face
* \param aPoly
* \param vertexnormals
*/
static void getPointNormals(const TopoDS_Face& face, Handle(Poly_Triangulation) aPoly, TColgp_Array1OfDir& normals);
/*!
* \brief getPointNormals
* Computes the exact surface normals for the points by using the UV coordinates of the mesh vertexes.
* \param face
* \param aPoly
* \param vertexnormals
*/
static void getPointNormals(const TopoDS_Face& face, Handle(Poly_Triangulation) aPoly, std::vector<gp_Vec>& normals);
/*!
* \brief applyTransformationOnNormals
* Apply the transformation to the vectors
* \param loc
* \param normals
*/
static void applyTransformationOnNormals(const TopLoc_Location& loc, std::vector<gp_Vec>& normals);
};
} //namespace Part
+84 -201
View File
@@ -38,8 +38,6 @@
# include <BRep_Tool.hxx>
# include <BRepAdaptor_Curve.hxx>
# include <BRepAdaptor_CompCurve.hxx>
# include <BRepAdaptor_HCurve.hxx>
# include <BRepAdaptor_HCompCurve.hxx>
# include <BRepAdaptor_Surface.hxx>
# include <BRepAlgoAPI_Common.hxx>
# include <BRepAlgoAPI_Cut.hxx>
@@ -186,6 +184,12 @@
#if OCC_VERSION_HEX >= 0x070300
# include <BRepAlgoAPI_Defeaturing.hxx>
#endif
#if OCC_VERSION_HEX < 0x070600
# include <BRepAdaptor_HCurve.hxx>
# include <BRepAdaptor_HCompCurve.hxx>
#endif
#endif // _PreComp_
#include <boost/algorithm/string/predicate.hpp>
@@ -1097,65 +1101,27 @@ void TopoShape::exportFaceSet(double dev, double ca,
for (ex.Init(this->_Shape, TopAbs_FACE); ex.More(); ex.Next(), index++) {
// get the shape and mesh it
const TopoDS_Face& aFace = TopoDS::Face(ex.Current());
Standard_Integer nbNodesInFace,nbTriInFace;
std::vector<gp_Pnt> points;
std::vector<Poly_Triangle> facets;
if (!Tools::getTriangulation(aFace, points, facets))
continue;
std::vector<Base::Vector3f> vertices;
std::vector<int> indices;
vertices.resize(points.size());
indices.resize(4 * facets.size());
// doing the meshing and checking the result
TopLoc_Location aLoc;
Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation(aFace,aLoc);
if (aPoly.IsNull()) continue;
// getting the transformation of the shape/face
gp_Trsf myTransf;
Standard_Boolean identity = true;
if (!aLoc.IsIdentity()) {
identity = false;
myTransf = aLoc.Transformation();
for (std::size_t i = 0; i < points.size(); i++) {
vertices[i] = Base::convertTo<Base::Vector3f>(points[i]);
}
// getting size and create the array
nbNodesInFace = aPoly->NbNodes();
nbTriInFace = aPoly->NbTriangles();
vertices.resize(nbNodesInFace);
indices.resize(4*nbTriInFace);
// check orientation
TopAbs_Orientation orient = aFace.Orientation();
// cycling through the poly mesh
const Poly_Array1OfTriangle& Triangles = aPoly->Triangles();
const TColgp_Array1OfPnt& Nodes = aPoly->Nodes();
for (int i=1;i<=nbTriInFace;i++) {
// Get the triangle
Standard_Integer N1,N2,N3;
Triangles(i).Get(N1,N2,N3);
// change orientation of the triangles
if (orient != TopAbs_FORWARD) {
Standard_Integer tmp = N1;
N1 = N2;
N2 = tmp;
}
gp_Pnt V1 = Nodes(N1);
gp_Pnt V2 = Nodes(N2);
gp_Pnt V3 = Nodes(N3);
// transform the vertices to the place of the face
if (!identity) {
V1.Transform(myTransf);
V2.Transform(myTransf);
V3.Transform(myTransf);
}
vertices[N1-1].Set((float)(V1.X()),(float)(V1.Y()),(float)(V1.Z()));
vertices[N2-1].Set((float)(V2.X()),(float)(V2.Y()),(float)(V2.Z()));
vertices[N3-1].Set((float)(V3.X()),(float)(V3.Y()),(float)(V3.Z()));
int j = i - 1;
N1--; N2--; N3--;
indices[4*j] = N1; indices[4*j+1] = N2; indices[4*j+2] = N3; indices[4*j+3] = -1;
for (std::size_t i = 0; i < facets.size(); i++) {
Standard_Integer n1,n2,n3;
facets[i].Get(n1, n2, n3);
indices[4 * i ] = n1;
indices[4 * i + 1] = n2;
indices[4 * i + 2] = n3;
indices[4 * i + 3] = -1;
}
builder.beginSeparator();
@@ -1170,7 +1136,7 @@ void TopoShape::exportFaceSet(double dev, double ca,
builder.endPoints();
builder.addIndexedFaceSet(indices);
builder.endSeparator();
} // end of face loop
}
}
void TopoShape::exportLineSet(std::ostream& str) const
@@ -1183,72 +1149,27 @@ void TopoShape::exportLineSet(std::ostream& str) const
// build up map edge->face
TopTools_IndexedDataMapOfShapeListOfShape edge2Face;
TopExp::MapShapesAndAncestors(this->_Shape, TopAbs_EDGE, TopAbs_FACE, edge2Face);
for (int i=0; i<M.Extent(); i++)
{
for (int i=0; i<M.Extent(); i++) {
const TopoDS_Edge& aEdge = TopoDS::Edge(M(i+1));
gp_Trsf myTransf;
TopLoc_Location aLoc;
std::vector<gp_Pnt> points;
// try to triangulate the edge
Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D(aEdge, aLoc);
std::vector<Base::Vector3f> vertices;
Standard_Integer nbNodesInFace;
// triangulation succeeded?
if (!aPoly.IsNull()) {
if (!aLoc.IsIdentity()) {
myTransf = aLoc.Transformation();
}
nbNodesInFace = aPoly->NbNodes();
vertices.resize(nbNodesInFace);
const TColgp_Array1OfPnt& Nodes = aPoly->Nodes();
gp_Pnt V;
for (Standard_Integer i=0;i < nbNodesInFace;i++) {
V = Nodes(i+1);
V.Transform(myTransf);
vertices[i].Set((float)(V.X()),(float)(V.Y()),(float)(V.Z()));
}
}
else {
if (!Tools::getPolygon3D(aEdge, points)) {
// the edge has not its own triangulation, but then a face the edge is attached to
// must provide this triangulation
// Look for one face in our map (it doesn't care which one we take)
const TopoDS_Face& aFace = TopoDS::Face(edge2Face.FindFromKey(aEdge).First());
// take the face's triangulation instead
Handle(Poly_Triangulation) aPolyTria = BRep_Tool::Triangulation(aFace,aLoc);
if (!aLoc.IsIdentity()) {
myTransf = aLoc.Transformation();
}
if (aPolyTria.IsNull()) break;
// this holds the indices of the edge's triangulation to the actual points
Handle(Poly_PolygonOnTriangulation) aPoly = BRep_Tool::PolygonOnTriangulation(aEdge, aPolyTria, aLoc);
if (aPoly.IsNull())
continue; // polygon does not exist
// getting size and create the array
nbNodesInFace = aPoly->NbNodes();
vertices.resize(nbNodesInFace);
const TColStd_Array1OfInteger& indices = aPoly->Nodes();
const TColgp_Array1OfPnt& Nodes = aPolyTria->Nodes();
gp_Pnt V;
int pos = 0;
// go through the index array
for (Standard_Integer i=indices.Lower();i <= indices.Upper();i++) {
V = Nodes(indices(i));
V.Transform(myTransf);
vertices[pos++].Set((float)(V.X()),(float)(V.Y()),(float)(V.Z()));
}
if (!Tools::getPolygonOnTriangulation(aEdge, aFace, points))
continue;
}
std::vector<Base::Vector3f> vertices;
vertices.reserve(points.size());
std::for_each(points.begin(), points.end(), [&vertices](const gp_Pnt& p) {
vertices.push_back(Base::convertTo<Base::Vector3f>(p));
});
builder.addLineSet(vertices, 2, 0, 0, 0);
}
}
@@ -2216,12 +2137,20 @@ TopoDS_Shape TopoShape::makeTube(double radius, double tol, int cont, int maxdeg
if (this->_Shape.IsNull())
Standard_Failure::Raise("Cannot sweep along empty spine");
#if OCC_VERSION_HEX >= 0x070600
Handle(Adaptor3d_Curve) myPath;
if (this->_Shape.ShapeType() == TopAbs_EDGE) {
const TopoDS_Edge& path_edge = TopoDS::Edge(this->_Shape);
myPath = new BRepAdaptor_Curve(path_edge);
}
#else
Handle(Adaptor3d_HCurve) myPath;
if (this->_Shape.ShapeType() == TopAbs_EDGE) {
const TopoDS_Edge& path_edge = TopoDS::Edge(this->_Shape);
BRepAdaptor_Curve path_adapt(path_edge);
myPath = new BRepAdaptor_HCurve(path_adapt);
}
#endif
//else if (this->_Shape.ShapeType() == TopAbs_WIRE) {
// const TopoDS_Wire& path_wire = TopoDS::Wire(this->_Shape);
// BRepAdaptor_CompCurve path_adapt(path_wire);
@@ -3443,46 +3372,40 @@ void TopoShape::getDomains(std::vector<Domain>& domains) const
for (TopExp_Explorer xp(this->_Shape, TopAbs_FACE); xp.More(); xp.Next()) {
TopoDS_Face face = TopoDS::Face(xp.Current());
TopLoc_Location loc;
Handle(Poly_Triangulation) theTriangulation = BRep_Tool::Triangulation(face, loc);
if (theTriangulation.IsNull()) {
std::vector<gp_Pnt> points;
std::vector<Poly_Triangle> facets;
if (!Tools::getTriangulation(face, points, facets)) {
// For a face that cannot be meshed append an empty domain.
// It's important for some algorithms (e.g. color mapping) that the numbers of
// faces and domains match
Domain domain;
domains.push_back(domain);
continue;
}
else {
Domain domain;
// copy the points
domain.points.reserve(points.size());
for (const auto& it : points) {
Standard_Real X, Y, Z;
it.Coord (X, Y, Z);
domain.points.emplace_back(X, Y, Z);
}
Domain domain;
// copy the points
const TColgp_Array1OfPnt& points = theTriangulation->Nodes();
domain.points.reserve(points.Length());
for (int i = 1; i <= points.Length(); i++) {
gp_Pnt p = points(i);
p.Transform(loc.Transformation());
Standard_Real X, Y, Z;
p.Coord (X, Y, Z);
domain.points.emplace_back(X, Y, Z);
// copy the triangles
domain.facets.reserve(facets.size());
for (const auto& it : facets) {
Standard_Integer N1, N2, N3;
it.Get(N1, N2, N3);
Facet tria;
tria.I1 = N1;
tria.I2 = N2;
tria.I3 = N3;
domain.facets.push_back(tria);
}
domains.push_back(domain);
}
// copy the triangles
const TopAbs_Orientation anOrientation = face.Orientation();
bool flip = (anOrientation == TopAbs_REVERSED);
const Poly_Array1OfTriangle& faces = theTriangulation->Triangles();
domain.facets.reserve(faces.Length());
for (int i = 1; i <= faces.Length(); i++) {
Standard_Integer N1, N2, N3;
faces(i).Get(N1, N2, N3);
Facet tria;
tria.I1 = N1-1; tria.I2 = N2-1; tria.I3 = N3-1;
if (flip)
std::swap(tria.I1, tria.I2);
domain.facets.push_back(tria);
}
domains.push_back(domain);
}
}
@@ -3845,7 +3768,7 @@ void TopoShape::getPoints(std::vector<Base::Vector3d> &Points,
Normals.clear();
}
void TopoShape::getLinesFromSubelement(const Data::Segment* element,
void TopoShape::getLinesFromSubElement(const Data::Segment* element,
std::vector<Base::Vector3d> &vertices,
std::vector<Line> &lines) const
{
@@ -3866,72 +3789,32 @@ void TopoShape::getLinesFromSubelement(const Data::Segment* element,
for(TopExp_Explorer exp(shape,TopAbs_EDGE);exp.More();exp.Next()) {
TopoDS_Edge aEdge = TopoDS::Edge(exp.Current());
TopLoc_Location aLoc;
Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D(aEdge, aLoc);
std::vector<gp_Pnt> points;
gp_Trsf myTransf;
Standard_Integer nbNodesInFace;
auto line_start = vertices.size();
// triangulation succeeded?
if (!aPoly.IsNull()) {
if (!aLoc.IsIdentity()) {
myTransf = aLoc.Transformation();
}
nbNodesInFace = aPoly->NbNodes();
const TColgp_Array1OfPnt& Nodes = aPoly->Nodes();
gp_Pnt V;
for (Standard_Integer i=0;i < nbNodesInFace;i++) {
V = Nodes(i+1);
V.Transform(myTransf);
vertices.emplace_back(V.X(),V.Y(),V.Z());
}
}
else {
if (!Tools::getPolygon3D(aEdge, points)) {
// the edge has not its own triangulation, but then a face the edge is attached to
// must provide this triangulation
// Look for one face in our map (it doesn't care which one we take)
int index = edge2Face.FindIndex(aEdge);
if(!index)
if (index < 1)
continue;
const auto &faces = edge2Face.FindFromIndex(index);
if(!faces.Extent())
if (faces.Extent() == 0)
continue;
const TopoDS_Face& aFace = TopoDS::Face(faces.First());
// take the face's triangulation instead
Handle(Poly_Triangulation) aPolyTria = BRep_Tool::Triangulation(aFace,aLoc);
if (!aLoc.IsIdentity()) {
myTransf = aLoc.Transformation();
}
if (aPolyTria.IsNull()) break;
// this holds the indices of the edge's triangulation to the actual points
Handle(Poly_PolygonOnTriangulation) aPoly = BRep_Tool::PolygonOnTriangulation(aEdge, aPolyTria, aLoc);
if (aPoly.IsNull())
continue; // polygon does not exist
// getting size and create the array
nbNodesInFace = aPoly->NbNodes();
const TColStd_Array1OfInteger& indices = aPoly->Nodes();
const TColgp_Array1OfPnt& Nodes = aPolyTria->Nodes();
gp_Pnt V;
// go through the index array
for (Standard_Integer i=indices.Lower();i <= indices.Upper();i++) {
V = Nodes(indices(i));
V.Transform(myTransf);
vertices.emplace_back(V.X(),V.Y(),V.Z());
}
if (!Part::Tools::getPolygonOnTriangulation(aEdge, aFace, points))
continue;
}
if(line_start+1 < vertices.size()) {
auto line_start = vertices.size();
vertices.reserve(vertices.size() + points.size());
std::for_each(points.begin(), points.end(), [&vertices](const gp_Pnt& p) {
vertices.push_back(Base::convertTo<Base::Vector3d>(p));
});
if (line_start+1 < vertices.size()) {
lines.emplace_back();
lines.back().I1 = line_start;
lines.back().I2 = vertices.size()-1;
@@ -3940,7 +3823,7 @@ void TopoShape::getLinesFromSubelement(const Data::Segment* element,
}
}
void TopoShape::getFacesFromSubelement(const Data::Segment* element,
void TopoShape::getFacesFromSubElement(const Data::Segment* element,
std::vector<Base::Vector3d> &points,
std::vector<Base::Vector3d> &pointNormals,
std::vector<Facet> &faces) const
+2 -2
View File
@@ -135,12 +135,12 @@ public:
/// get the subelement by type and number
virtual Data::Segment* getSubElement(const char* Type, unsigned long) const;
/** Get lines from segment */
virtual void getLinesFromSubelement(
virtual void getLinesFromSubElement(
const Data::Segment*,
std::vector<Base::Vector3d> &Points,
std::vector<Line> &lines) const;
/** Get faces from segment */
virtual void getFacesFromSubelement(
virtual void getFacesFromSubElement(
const Data::Segment*,
std::vector<Base::Vector3d> &Points,
std::vector<Base::Vector3d> &PointNormals,
+10
View File
@@ -493,6 +493,15 @@ PyObject* TopoShapeFacePy::getUVNodes(PyObject *args)
return Py::new_reference_to(list);
}
#if OCC_VERSION_HEX >= 0x070600
for (int i=1; i<=mesh->NbNodes(); i++) {
gp_Pnt2d pt2d = mesh->UVNode(i);
Py::Tuple uv(2);
uv.setItem(0, Py::Float(pt2d.X()));
uv.setItem(1, Py::Float(pt2d.Y()));
list.append(uv);
}
#else
const TColgp_Array1OfPnt2d& aNodesUV = mesh->UVNodes();
for (int i=aNodesUV.Lower(); i<=aNodesUV.Upper(); i++) {
gp_Pnt2d pt2d = aNodesUV(i);
@@ -501,6 +510,7 @@ PyObject* TopoShapeFacePy::getUVNodes(PyObject *args)
uv.setItem(1, Py::Float(pt2d.Y()));
list.append(uv);
}
#endif
return Py::new_reference_to(list);
}
+3 -3
View File
@@ -344,9 +344,9 @@ PyObject* TopoShapeWirePy::approximate(PyObject *args, PyObject *kwds)
return 0;
try {
BRepAdaptor_CompCurve adapt(TopoDS::Wire(getTopoShapePtr()->getShape()));
Handle(Adaptor3d_HCurve) hcurve = adapt.Trim(adapt.FirstParameter(),
adapt.LastParameter(),
tol2d);
auto hcurve = adapt.Trim(adapt.FirstParameter(),
adapt.LastParameter(),
tol2d);
Approx_Curve3d approx(hcurve, tol3d, GeomAbs_C0, maxseg, maxdeg);
if (approx.IsDone()) {
return new BSplineCurvePy(new GeomBSplineCurve(approx.Curve()));
+3 -4
View File
@@ -28,7 +28,7 @@
#include "ShapeFromMesh.h"
#include "ui_ShapeFromMesh.h"
#include <App/Application.h>
#include <Base/UnitsApi.h>
#include <App/DocumentObserver.h>
#include <Gui/CommandT.h>
#include <Gui/Selection.h>
@@ -46,8 +46,7 @@ ShapeFromMesh::ShapeFromMesh(QWidget* parent, Qt::WindowFlags fl)
double STD_OCC_TOLERANCE = 1e-6;
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Units");
int decimals = hGrp->GetInt("Decimals");
int decimals = Base::UnitsApi::getDecimals();
double tolerance_from_decimals = pow(10., -decimals);
double minimal_tolerance = tolerance_from_decimals < STD_OCC_TOLERANCE ? STD_OCC_TOLERANCE : tolerance_from_decimals;
@@ -81,7 +80,7 @@ void ShapeFromMesh::perform()
std::string mesh = (*it)->getNameInDocument();
std::string name = doc->getUniqueObjectName(mesh.c_str());
Gui::cmdAppDocument(doc, std::ostringstream() << "addObject(\"Part::Feature\", \"" << name << "\")");
Gui::cmdAppDocumentArgs(doc, "addObject('%s', '%s')", "Part::Feature", name);
std::string partObj = App::DocumentObjectT(doc, name).getObjectPython();
std::string meshObj = App::DocumentObjectT(doc, mesh).getObjectPython();
+4 -2
View File
@@ -711,8 +711,10 @@ int TaskCheckGeometryResults::goBOPSingleCheck(const TopoDS_Shape& shapeIn, Resu
#if OCC_VERSION_HEX >= 0x060900
#if OCC_VERSION_HEX < 0x070500
BOPCheck.SetProgressIndicator(theProgress);
#else
#elif OCC_VERSION_HEX < 0x070600
BOPCheck.SetProgressIndicator(theScope);
#else
Q_UNUSED(theScope)
#endif // 0x070500
#else
Q_UNUSED(theProgress);
@@ -740,7 +742,7 @@ int TaskCheckGeometryResults::goBOPSingleCheck(const TopoDS_Shape& shapeIn, Resu
Base::TimeInfo start_time;
#endif
BOPCheck.Perform();
BOPCheck.Perform();
#ifdef FC_DEBUG
float bopAlgoTime = Base::TimeInfo::diffTimeF(start_time,Base::TimeInfo());
+28 -102
View File
@@ -125,6 +125,7 @@
#include <Mod/Part/App/PartFeature.h>
#include <Mod/Part/App/PrimitiveFeature.h>
#include <Mod/Part/App/Tools.h>
FC_LOG_LEVEL_INIT("Part", true, true)
@@ -133,94 +134,6 @@ using namespace PartGui;
PROPERTY_SOURCE(PartGui::ViewProviderPartExt, Gui::ViewProviderGeometryObject)
void ViewProviderPartExt::getNormals(const TopoDS_Face& theFace,
const Handle(Poly_Triangulation)& aPolyTri,
TColgp_Array1OfDir& theNormals)
{
const TColgp_Array1OfPnt& aNodes = aPolyTri->Nodes();
if(aPolyTri->HasNormals())
{
// normals pre-computed in triangulation structure
const TShort_Array1OfShortReal& aNormals = aPolyTri->Normals();
const Standard_ShortReal* aNormArr = &(aNormals.Value(aNormals.Lower()));
for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
{
const Standard_Integer anId = 3 * (aNodeIter - aNodes.Lower());
const gp_Dir aNorm(aNormArr[anId + 0],
aNormArr[anId + 1],
aNormArr[anId + 2]);
theNormals(aNodeIter) = aNorm;
}
if(theFace.Orientation() == TopAbs_REVERSED)
{
for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
{
theNormals.ChangeValue(aNodeIter).Reverse();
}
}
return;
}
// take in face the surface location
Poly_Connect thePolyConnect(aPolyTri);
const TopoDS_Face aZeroFace = TopoDS::Face(theFace.Located(TopLoc_Location()));
Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aZeroFace);
const Standard_Real aTol = Precision::Confusion();
Handle(TShort_HArray1OfShortReal) aNormals = new TShort_HArray1OfShortReal(1, aPolyTri->NbNodes() * 3);
const Poly_Array1OfTriangle& aTriangles = aPolyTri->Triangles();
const TColgp_Array1OfPnt2d* aNodesUV = aPolyTri->HasUVNodes() && !aSurf.IsNull()
? &aPolyTri->UVNodes()
: NULL;
Standard_Integer aTri[3];
for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
{
// try to retrieve normal from real surface first, when UV coordinates are available
if(aNodesUV == NULL
|| GeomLib::NormEstim(aSurf, aNodesUV->Value(aNodeIter), aTol, theNormals(aNodeIter)) > 1)
{
// compute flat normals
gp_XYZ eqPlan(0.0, 0.0, 0.0);
for(thePolyConnect.Initialize(aNodeIter); thePolyConnect.More(); thePolyConnect.Next())
{
aTriangles(thePolyConnect.Value()).Get(aTri[0], aTri[1], aTri[2]);
const gp_XYZ v1(aNodes(aTri[1]).Coord() - aNodes(aTri[0]).Coord());
const gp_XYZ v2(aNodes(aTri[2]).Coord() - aNodes(aTri[1]).Coord());
const gp_XYZ vv = v1 ^ v2;
const Standard_Real aMod = vv.Modulus();
if(aMod >= aTol)
{
eqPlan += vv / aMod;
}
}
const Standard_Real aModMax = eqPlan.Modulus();
theNormals(aNodeIter) = (aModMax > aTol) ? gp_Dir(eqPlan) : gp::DZ();
}
const Standard_Integer anId = (aNodeIter - aNodes.Lower()) * 3;
aNormals->SetValue(anId + 1, (Standard_ShortReal)theNormals(aNodeIter).X());
aNormals->SetValue(anId + 2, (Standard_ShortReal)theNormals(aNodeIter).Y());
aNormals->SetValue(anId + 3, (Standard_ShortReal)theNormals(aNodeIter).Z());
}
aPolyTri->SetNormals(aNormals);
if(theFace.Orientation() == TopAbs_REVERSED)
{
for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
{
theNormals.ChangeValue(aNodeIter).Reverse();
}
}
}
//**************************************************************************
// Construction/Destruction
@@ -443,24 +356,19 @@ void ViewProviderPartExt::onChanged(const App::Property* prop)
else if (prop == &ShapeMaterial || prop == &ShapeColor) {
pcFaceBind->value = SoMaterialBinding::OVERALL;
ViewProviderGeometryObject::onChanged(prop);
DiffuseColor.setValue(ShapeColor.getValue());
App::Color c = ShapeColor.getValue();
c.a = Transparency.getValue()/100.0f;
DiffuseColor.setValue(c);
}
else if (prop == &Transparency) {
const App::Material& Mat = ShapeMaterial.getValue();
long value = (long)(100*Mat.transparency);
if (value != Transparency.getValue()) {
float trans = Transparency.getValue()/100.0f;
if (pcFaceBind->value.getValue() == SoMaterialBinding::PER_PART) {
int cnt = pcShapeMaterial->diffuseColor.getNum();
pcShapeMaterial->transparency.setNum(cnt);
float *t = pcShapeMaterial->transparency.startEditing();
for (int i=0; i<cnt; i++)
t[i] = trans;
pcShapeMaterial->transparency.finishEditing();
}
else {
pcShapeMaterial->transparency = trans;
}
auto colors = DiffuseColor.getValues();
for (auto &c : colors)
c.a = trans;
DiffuseColor.setValues(colors);
App::PropertyContainer* parent = ShapeMaterial.getContainer();
ShapeMaterial.setContainer(0);
@@ -729,7 +637,7 @@ void ViewProviderPartExt::setHighlightedFaces(const std::vector<App::Color>& col
else if (colors.size() == 1) {
pcFaceBind->value = SoMaterialBinding::OVERALL;
pcShapeMaterial->diffuseColor.setValue(colors[0].r, colors[0].g, colors[0].b);
//pcShapeMaterial->transparency = colors[0].a; do not get transparency from DiffuseColor in this case
pcShapeMaterial->transparency = Transparency.getValue()/100.f;
}
}
@@ -795,6 +703,7 @@ std::map<std::string,App::Color> ViewProviderPartExt::getElementColors(const cha
}
if(size && singleColor) {
color = DiffuseColor[0];
color.a = Transparency.getValue()/100.0f;
ret.clear();
}
ret["Face"] = color;
@@ -1170,16 +1079,25 @@ void ViewProviderPartExt::updateVisual()
// cycling through the poly mesh
#if OCC_VERSION_HEX < 0x070600
const Poly_Array1OfTriangle& Triangles = mesh->Triangles();
const TColgp_Array1OfPnt& Nodes = mesh->Nodes();
TColgp_Array1OfDir Normals (Nodes.Lower(), Nodes.Upper());
#else
int numNodes = mesh->NbNodes();
TColgp_Array1OfDir Normals (1, numNodes);
#endif
if (NormalsFromUV)
getNormals(actFace, mesh, Normals);
Part::Tools::getPointNormals(actFace, mesh, Normals);
for (int g=1;g<=nbTriInFace;g++) {
// Get the triangle
Standard_Integer N1,N2,N3;
#if OCC_VERSION_HEX < 0x070600
Triangles(g).Get(N1,N2,N3);
#else
mesh->Triangle(g).Get(N1,N2,N3);
#endif
// change orientation of the triangle if the face is reversed
if ( orient != TopAbs_FORWARD ) {
@@ -1189,7 +1107,11 @@ void ViewProviderPartExt::updateVisual()
}
// get the 3 points of this triangle
#if OCC_VERSION_HEX < 0x070600
gp_Pnt V1(Nodes(N1)), V2(Nodes(N2)), V3(Nodes(N3));
#else
gp_Pnt V1(mesh->Node(N1)), V2(mesh->Node(N2)), V3(mesh->Node(N3));
#endif
// get the 3 normals of this triangle
gp_Vec NV1, NV2, NV3;
@@ -1266,7 +1188,11 @@ void ViewProviderPartExt::updateVisual()
// rare cases where some points are only referenced by the polygon
// but not by any triangle. Thus, we must apply the coordinates to
// make sure that everything is properly set.
#if OCC_VERSION_HEX < 0x070600
gp_Pnt p(Nodes(nodeIndex));
#else
gp_Pnt p(mesh->Node(nodeIndex));
#endif
if (!identity)
p.Transform(myTransf);
verts[index].setValue((float)(p.X()),(float)(p.Y()),(float)(p.Z()));
-2
View File
@@ -158,8 +158,6 @@ protected:
virtual void onChanged(const App::Property* prop) override;
bool loadParameter();
void updateVisual();
void getNormals(const TopoDS_Face& theFace, const Handle(Poly_Triangulation)& aPolyTri,
TColgp_Array1OfDir& theNormals);
// nodes for the data representation
SoMaterialBinding * pcFaceBind;
+1
View File
@@ -43,6 +43,7 @@ SOFTWARE.
#include <memory> // unique_ptr
#include <numeric> // accumulate
#include <string> // string, stoi, to_string
#include <string_view> // string_view
#include <utility> // declval, forward, move, pair, swap
#include <vector> // vector
+5 -1
View File
@@ -43,6 +43,7 @@
#include <App/Part.h>
#include <Gui/Application.h>
#include <Gui/Command.h>
#include <Gui/CommandT.h>
#include <Gui/Control.h>
#include <Gui/Selection.h>
#include <Gui/MainWindow.h>
@@ -1257,7 +1258,10 @@ void CmdPartDesignPad::activated(int iMsg)
Part::Part2DObject* sketch = dynamic_cast<Part::Part2DObject*>(profile);
FCMD_OBJ_CMD(Feat, "ReferenceAxis = (" << getObjectCmd(sketch) << ",['N_Axis'])");
if (sketch) {
std::ostringstream str;
Gui::cmdAppObject(Feat, str << "ReferenceAxis = (" << getObjectCmd(sketch) << ",['N_Axis'])");
}
finishProfileBased(cmd, sketch, Feat);
cmd->adjustCameraPosition();
+4 -1
View File
@@ -775,7 +775,10 @@ void TaskPadParameters::getReferenceAxis(App::DocumentObject*& obj, std::vector<
int num = ui->directionCB->currentIndex();
const App::PropertyLinkSub& lnk = *(axesInList[num]);
if (lnk.getValue() == 0) {
throw Base::RuntimeError("Still in reference selection mode; reference wasn't selected yet");
// Note: Is is possible that a face of an object is directly padded without defining a profile shape
obj = nullptr;
sub.clear();
//throw Base::RuntimeError("Still in reference selection mode; reference wasn't selected yet");
}
else {
PartDesign::ProfileBased* pcDirection = static_cast<PartDesign::ProfileBased*>(vp->getObject());
+40 -72
View File
@@ -40,7 +40,8 @@
#endif
#include "ViewProviderAddSub.h"
#include "Mod/Part/Gui/SoBrepFaceSet.h"
#include <Mod/Part/Gui/SoBrepFaceSet.h>
#include <Mod/Part/App/Tools.h>
#include <Mod/PartDesign/App/FeatureAddSub.h>
#include <Gui/TaskView/TaskDialog.h>
#include <Gui/Control.h>
@@ -115,9 +116,6 @@ void ViewProviderAddSub::updateAddSubShapeIndicator() {
return;
}
int numTriangles=0,numNodes=0,numNorms=0,numFaces=0;
std::set<int> faceEdges;
try {
// calculating the deflection value
Bnd_Box bounds;
@@ -125,16 +123,14 @@ void ViewProviderAddSub::updateAddSubShapeIndicator() {
bounds.SetGap(0.0);
Standard_Real xMin, yMin, zMin, xMax, yMax, zMax;
bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax);
Standard_Real deflection = ((xMax-xMin)+(yMax-yMin)+(zMax-zMin))/300.0 *
Deviation.getValue();
Standard_Real deflection = ((xMax-xMin)+(yMax-yMin)+(zMax-zMin))/300.0 * Deviation.getValue();
// create or use the mesh on the data structure
#if OCC_VERSION_HEX >= 0x060600
Standard_Real AngDeflectionRads = AngularDeflection.getValue() / 180.0 * M_PI;
BRepMesh_IncrementalMesh(cShape,deflection,Standard_False,
AngDeflectionRads,Standard_True);
BRepMesh_IncrementalMesh(cShape, deflection, Standard_False, AngDeflectionRads, Standard_True);
#else
BRepMesh_IncrementalMesh(cShape,deflection);
BRepMesh_IncrementalMesh(cShape, deflection);
#endif
// We must reset the location here because the transformation data
// are set in the placement property
@@ -142,6 +138,7 @@ void ViewProviderAddSub::updateAddSubShapeIndicator() {
cShape.Location(aLoc);
// count triangles and nodes in the mesh
int numTriangles=0,numNodes=0,numNorms=0,numFaces=0;
TopExp_Explorer Ex;
for (Ex.Init(cShape,TopAbs_FACE);Ex.More();Ex.Next()) {
Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(TopoDS::Face(Ex.Current()), aLoc);
@@ -159,11 +156,12 @@ void ViewProviderAddSub::updateAddSubShapeIndicator() {
previewNorm ->vector .setNum(numNorms);
previewFaceSet ->coordIndex .setNum(numTriangles*4);
previewFaceSet ->partIndex .setNum(numFaces);
// get the raw memory for fast fill up
SbVec3f* verts = previewCoords ->point .startEditing();
SbVec3f* previewNorms = previewNorm ->vector .startEditing();
int32_t* index = previewFaceSet ->coordIndex .startEditing();
int32_t* parts = previewFaceSet ->partIndex .startEditing();
SbVec3f* verts = previewCoords ->point .startEditing();
SbVec3f* previewNorms = previewNorm ->vector .startEditing();
int32_t* index = previewFaceSet ->coordIndex .startEditing();
int32_t* parts = previewFaceSet ->partIndex .startEditing();
// preset the previewNormal vector with null vector
for (int i=0;i < numNorms;i++)
@@ -171,76 +169,46 @@ void ViewProviderAddSub::updateAddSubShapeIndicator() {
int ii = 0,faceNodeOffset=0,faceTriaOffset=0;
for (Ex.Init(cShape, TopAbs_FACE); Ex.More(); Ex.Next(),ii++) {
TopLoc_Location aLoc;
const TopoDS_Face &actFace = TopoDS::Face(Ex.Current());
// get the mesh of the shape
Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(actFace,aLoc);
if (mesh.IsNull()) continue;
// getting the transformation of the shape/face
gp_Trsf myTransf;
Standard_Boolean identity = true;
if (!aLoc.IsIdentity()) {
identity = false;
myTransf = aLoc.Transformation();
}
TopLoc_Location loc;
Handle(Poly_Triangulation) mesh = BRep_Tool::Triangulation(actFace, loc);
if (mesh.IsNull())
continue;
// get triangulation
std::vector<gp_Pnt> points;
std::vector<Poly_Triangle> facets;
Part::Tools::getTriangulation(actFace, points, facets);
// get normal per vertex
std::vector<gp_Vec> vertexnormals;
Part::Tools::getPointNormals(actFace, mesh, vertexnormals);
Part::Tools::applyTransformationOnNormals(loc, vertexnormals);
// getting size of node and triangle array of this face
int nbNodesInFace = mesh->NbNodes();
int nbTriInFace = mesh->NbTriangles();
// check orientation
TopAbs_Orientation orient = actFace.Orientation();
std::size_t nbNodesInFace = points.size();
std::size_t nbTriInFace = facets.size();
for (std::size_t i = 0; i < points.size(); i++) {
verts[faceNodeOffset+i] = SbVec3f(points[i].X(), points[i].Y(), points[i].Z());
}
for (std::size_t i = 0; i < vertexnormals.size(); i++) {
previewNorms[faceNodeOffset+i] = SbVec3f(vertexnormals[i].X(), vertexnormals[i].Y(), vertexnormals[i].Z());
}
// cycling through the poly mesh
const Poly_Array1OfTriangle& Triangles = mesh->Triangles();
const TColgp_Array1OfPnt& Nodes = mesh->Nodes();
TColgp_Array1OfDir Normals (Nodes.Lower(), Nodes.Upper());
getNormals(actFace, mesh, Normals);
for (int g=1;g<=nbTriInFace;g++) {
for (std::size_t g=0; g < nbTriInFace; g++) {
// Get the triangle
Standard_Integer N1,N2,N3;
Triangles(g).Get(N1,N2,N3);
// change orientation of the triangle if the face is reversed
if ( orient != TopAbs_FORWARD ) {
Standard_Integer tmp = N1;
N1 = N2;
N2 = tmp;
}
// get the 3 points of this triangle
gp_Pnt V1(Nodes(N1)), V2(Nodes(N2)), V3(Nodes(N3));
// get the 3 previewNormals of this triangle
gp_Dir NV1(Normals(N1)), NV2(Normals(N2)), NV3(Normals(N3));
// transform the vertices and previewNormals to the place of the face
if(!identity) {
V1.Transform(myTransf);
V2.Transform(myTransf);
V3.Transform(myTransf);
NV1.Transform(myTransf);
NV2.Transform(myTransf);
NV3.Transform(myTransf);
}
// add the previewNormals for all points of this triangle
previewNorms[faceNodeOffset+N1-1] += SbVec3f(NV1.X(),NV1.Y(),NV1.Z());
previewNorms[faceNodeOffset+N2-1] += SbVec3f(NV2.X(),NV2.Y(),NV2.Z());
previewNorms[faceNodeOffset+N3-1] += SbVec3f(NV3.X(),NV3.Y(),NV3.Z());
// set the vertices
verts[faceNodeOffset+N1-1].setValue((float)(V1.X()),(float)(V1.Y()),(float)(V1.Z()));
verts[faceNodeOffset+N2-1].setValue((float)(V2.X()),(float)(V2.Y()),(float)(V2.Z()));
verts[faceNodeOffset+N3-1].setValue((float)(V3.X()),(float)(V3.Y()),(float)(V3.Z()));
facets[g].Get(N1,N2,N3);
// set the index vector with the 3 point indexes and the end delimiter
index[faceTriaOffset*4+4*(g-1)] = faceNodeOffset+N1-1;
index[faceTriaOffset*4+4*(g-1)+1] = faceNodeOffset+N2-1;
index[faceTriaOffset*4+4*(g-1)+2] = faceNodeOffset+N3-1;
index[faceTriaOffset*4+4*(g-1)+3] = SO_END_FACE_INDEX;
index[faceTriaOffset*4+4*g] = faceNodeOffset+N1;
index[faceTriaOffset*4+4*g+1] = faceNodeOffset+N2;
index[faceTriaOffset*4+4*g+2] = faceNodeOffset+N3;
index[faceTriaOffset*4+4*g+3] = SO_END_FACE_INDEX;
}
parts[ii] = nbTriInFace; // new part
+125 -155
View File
@@ -55,6 +55,7 @@
#include <Gui/Application.h>
#include <Gui/Command.h>
#include <Mod/Part/App/TopoShape.h>
#include <Mod/Part/App/Tools.h>
#include <Mod/PartDesign/App/FeatureTransformed.h>
#include <Mod/PartDesign/App/FeatureAddSub.h>
#include <Mod/PartDesign/App/FeatureMultiTransform.h>
@@ -198,162 +199,131 @@ void ViewProviderTransformed::recomputeFeature(bool recompute)
}
// Display the rejected transformations in red
if (rejected > 0) {
try {
// calculating the deflection value
Standard_Real xMin, yMin, zMin, xMax, yMax, zMax;
{
Bnd_Box bounds;
BRepBndLib::Add(cShape, bounds);
bounds.SetGap(0.0);
bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax);
}
Standard_Real deflection = ((xMax-xMin)+(yMax-yMin)+(zMax-zMin))/300.0 * Deviation.getValue();
// create or use the mesh on the data structure
// Note: This DOES have an effect on cShape
#if OCC_VERSION_HEX >= 0x060600
Standard_Real AngDeflectionRads = AngularDeflection.getValue() / 180.0 * M_PI;
BRepMesh_IncrementalMesh(cShape,deflection,Standard_False,
AngDeflectionRads,Standard_True);
#else
BRepMesh_IncrementalMesh(cShape,deflection);
#endif
// We must reset the location here because the transformation data
// are set in the placement property
TopLoc_Location aLoc;
cShape.Location(aLoc);
// count triangles and nodes in the mesh
int nbrTriangles=0, nbrNodes=0;
TopExp_Explorer Ex;
for (Ex.Init(cShape,TopAbs_FACE);Ex.More();Ex.Next()) {
Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(TopoDS::Face(Ex.Current()), aLoc);
// Note: we must also count empty faces
if (!mesh.IsNull()) {
nbrTriangles += mesh->NbTriangles();
nbrNodes += mesh->NbNodes();
}
}
// create memory for the nodes and indexes
SoCoordinate3* rejectedCoords = new SoCoordinate3();
rejectedCoords ->point .setNum(nbrNodes);
SoNormal* rejectedNorms = new SoNormal();
rejectedNorms ->vector .setNum(nbrNodes);
SoIndexedFaceSet* rejectedFaceSet = new SoIndexedFaceSet();
rejectedFaceSet ->coordIndex .setNum(nbrTriangles*4);
// get the raw memory for fast fill up
SbVec3f* verts = rejectedCoords ->point .startEditing();
SbVec3f* norms = rejectedNorms ->vector .startEditing();
int32_t* index = rejectedFaceSet ->coordIndex .startEditing();
// preset the normal vector with null vector
for (int i=0; i < nbrNodes; i++)
norms[i]= SbVec3f(0.0,0.0,0.0);
int ii = 0,FaceNodeOffset=0,FaceTriaOffset=0;
for (Ex.Init(cShape, TopAbs_FACE); Ex.More(); Ex.Next(),ii++) {
TopLoc_Location aLoc;
const TopoDS_Face &actFace = TopoDS::Face(Ex.Current());
// get the mesh of the shape
Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(actFace,aLoc);
if (mesh.IsNull()) continue;
// getting the transformation of the shape/face
gp_Trsf myTransf;
Standard_Boolean identity = true;
if (!aLoc.IsIdentity()) {
identity = false;
myTransf = aLoc.Transformation();
}
// getting size of node and triangle array of this face
int nbNodesInFace = mesh->NbNodes();
int nbTriInFace = mesh->NbTriangles();
// check orientation
TopAbs_Orientation orient = actFace.Orientation();
// cycling through the poly mesh
const Poly_Array1OfTriangle& Triangles = mesh->Triangles();
const TColgp_Array1OfPnt& Nodes = mesh->Nodes();
for (int g=1; g <= nbTriInFace; g++) {
// Get the triangle
Standard_Integer N1,N2,N3;
Triangles(g).Get(N1,N2,N3);
// change orientation of the triangle if the face is reversed
if ( orient != TopAbs_FORWARD ) {
Standard_Integer tmp = N1;
N1 = N2;
N2 = tmp;
}
// get the 3 points of this triangle
gp_Pnt V1(Nodes(N1)), V2(Nodes(N2)), V3(Nodes(N3));
// transform the vertices to the place of the face
if (!identity) {
V1.Transform(myTransf);
V2.Transform(myTransf);
V3.Transform(myTransf);
}
// calculating per vertex normals
// Calculate triangle normal
gp_Vec v1(V1.X(),V1.Y(),V1.Z()),v2(V2.X(),V2.Y(),V2.Z()),v3(V3.X(),V3.Y(),V3.Z());
gp_Vec Normal = (v2-v1)^(v3-v1);
// add the triangle normal to the vertex normal for all points of this triangle
norms[FaceNodeOffset+N1-1] += SbVec3f(Normal.X(),Normal.Y(),Normal.Z());
norms[FaceNodeOffset+N2-1] += SbVec3f(Normal.X(),Normal.Y(),Normal.Z());
norms[FaceNodeOffset+N3-1] += SbVec3f(Normal.X(),Normal.Y(),Normal.Z());
// set the vertices
verts[FaceNodeOffset+N1-1].setValue((float)(V1.X()),(float)(V1.Y()),(float)(V1.Z()));
verts[FaceNodeOffset+N2-1].setValue((float)(V2.X()),(float)(V2.Y()),(float)(V2.Z()));
verts[FaceNodeOffset+N3-1].setValue((float)(V3.X()),(float)(V3.Y()),(float)(V3.Z()));
// set the index vector with the 3 point indexes and the end delimiter
index[FaceTriaOffset*4+4*(g-1)] = FaceNodeOffset+N1-1;
index[FaceTriaOffset*4+4*(g-1)+1] = FaceNodeOffset+N2-1;
index[FaceTriaOffset*4+4*(g-1)+2] = FaceNodeOffset+N3-1;
index[FaceTriaOffset*4+4*(g-1)+3] = SO_END_FACE_INDEX;
}
// counting up the per Face offsets
FaceNodeOffset += nbNodesInFace;
FaceTriaOffset += nbTriInFace;
// normalize all normals
for (int i=0; i < nbrNodes; i++)
norms[i].normalize();
// end the editing of the nodes
rejectedCoords ->point .finishEditing();
rejectedNorms ->vector .finishEditing();
rejectedFaceSet ->coordIndex .finishEditing();
// fill in the transformation matrices
SoMultipleCopy* rejectedTrfms = new SoMultipleCopy();
rejectedTrfms->matrix.finishEditing();
rejectedTrfms->addChild(rejectedFaceSet);
SoSeparator* sep = new SoSeparator();
sep->addChild(rejectedCoords);
sep->addChild(rejectedNorms);
sep->addChild(rejectedTrfms);
pcRejectedRoot->addChild(sep);
}
}
catch (...) {
Base::Console().Error("Cannot compute Inventor representation for the rejected transformations of shape of %s.\n",
pcTransformed->getNameInDocument());
}
showRejectedShape(cShape);
}
}
void ViewProviderTransformed::showRejectedShape(TopoDS_Shape shape)
{
try {
// calculating the deflection value
Standard_Real xMin, yMin, zMin, xMax, yMax, zMax;
{
Bnd_Box bounds;
BRepBndLib::Add(shape, bounds);
bounds.SetGap(0.0);
bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax);
}
Standard_Real deflection = ((xMax-xMin)+(yMax-yMin)+(zMax-zMin))/300.0 * Deviation.getValue();
// create or use the mesh on the data structure
// Note: This DOES have an effect on shape
#if OCC_VERSION_HEX >= 0x060600
Standard_Real AngDeflectionRads = AngularDeflection.getValue() / 180.0 * M_PI;
BRepMesh_IncrementalMesh(shape, deflection, Standard_False, AngDeflectionRads, Standard_True);
#else
BRepMesh_IncrementalMesh(shape, deflection);
#endif
// We must reset the location here because the transformation data
// are set in the placement property
TopLoc_Location aLoc;
shape.Location(aLoc);
// count triangles and nodes in the mesh
int nbrTriangles=0, nbrNodes=0;
TopExp_Explorer Ex;
for (Ex.Init(shape, TopAbs_FACE); Ex.More(); Ex.Next()) {
Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(TopoDS::Face(Ex.Current()), aLoc);
// Note: we must also count empty faces
if (!mesh.IsNull()) {
nbrTriangles += mesh->NbTriangles();
nbrNodes += mesh->NbNodes();
}
}
// create memory for the nodes and indexes
SoCoordinate3* rejectedCoords = new SoCoordinate3();
rejectedCoords ->point .setNum(nbrNodes);
SoNormal* rejectedNorms = new SoNormal();
rejectedNorms ->vector .setNum(nbrNodes);
SoIndexedFaceSet* rejectedFaceSet = new SoIndexedFaceSet();
rejectedFaceSet ->coordIndex .setNum(nbrTriangles*4);
// get the raw memory for fast fill up
SbVec3f* verts = rejectedCoords ->point .startEditing();
SbVec3f* norms = rejectedNorms ->vector .startEditing();
int32_t* index = rejectedFaceSet ->coordIndex .startEditing();
// preset the normal vector with null vector
for (int i=0; i < nbrNodes; i++)
norms[i]= SbVec3f(0.0,0.0,0.0);
int FaceNodeOffset=0,FaceTriaOffset=0;
for (Ex.Init(shape, TopAbs_FACE); Ex.More(); Ex.Next()) {
const TopoDS_Face &actFace = TopoDS::Face(Ex.Current());
// get triangulation
std::vector<gp_Pnt> points;
std::vector<Poly_Triangle> facets;
if (!Part::Tools::getTriangulation(actFace, points, facets))
continue;
// get normal per vertex
std::vector<gp_Vec> vertexnormals;
Part::Tools::getPointNormals(points, facets, vertexnormals);
// getting size of node and triangle array of this face
std::size_t nbNodesInFace = points.size();
std::size_t nbTriInFace = facets.size();
for (std::size_t i = 0; i < points.size(); i++) {
verts[FaceNodeOffset+i] = SbVec3f(points[i].X(), points[i].Y(), points[i].Z());
}
for (std::size_t i = 0; i < vertexnormals.size(); i++) {
norms[FaceNodeOffset+i] = SbVec3f(vertexnormals[i].X(), vertexnormals[i].Y(), vertexnormals[i].Z());
}
// cycling through the poly mesh
for (std::size_t g=0; g < nbTriInFace; g++) {
// Get the triangle
Standard_Integer N1,N2,N3;
facets[g].Get(N1,N2,N3);
// set the index vector with the 3 point indexes and the end delimiter
index[FaceTriaOffset*4+4*g] = FaceNodeOffset+N1;
index[FaceTriaOffset*4+4*g+1] = FaceNodeOffset+N2;
index[FaceTriaOffset*4+4*g+2] = FaceNodeOffset+N3;
index[FaceTriaOffset*4+4*g+3] = SO_END_FACE_INDEX;
}
// counting up the per Face offsets
FaceNodeOffset += nbNodesInFace;
FaceTriaOffset += nbTriInFace;
// normalize all normals
for (int i=0; i < nbrNodes; i++)
norms[i].normalize();
// end the editing of the nodes
rejectedCoords ->point .finishEditing();
rejectedNorms ->vector .finishEditing();
rejectedFaceSet ->coordIndex .finishEditing();
// fill in the transformation matrices
SoMultipleCopy* rejectedTrfms = new SoMultipleCopy();
rejectedTrfms->matrix.finishEditing();
rejectedTrfms->addChild(rejectedFaceSet);
SoSeparator* sep = new SoSeparator();
sep->addChild(rejectedCoords);
sep->addChild(rejectedNorms);
sep->addChild(rejectedTrfms);
pcRejectedRoot->addChild(sep);
}
}
catch (...) {
Base::Console().Error("Cannot compute Inventor representation for the rejected transformations of shape of %s.\n",
getObject()->getNameInDocument());
}
}
@@ -68,6 +68,9 @@ protected:
public:
void recomputeFeature(bool recompute=true);
QString getMessage() const {return diagMessage;}
private:
void showRejectedShape(TopoDS_Shape shape);
};
+1 -4
View File
@@ -49,10 +49,7 @@
#include <TopExp_Explorer.hxx>
#include <gp_Lin.hxx>
#include <BRep_Tool.hxx>
#include <BRepAdaptor_CompCurve.hxx>
#include <BRepAdaptor_HCompCurve.hxx>
#include <Approx_Curve3d.hxx>
#include <BRepAdaptor_HCurve.hxx>
#include <BRepAdaptor_Curve.hxx>
#include "CommandPy.h"
#include "PathPy.h"
+8 -1
View File
@@ -33,6 +33,7 @@
#include <Base/Exception.h>
#include <Base/Matrix.h>
#include <Base/Tools.h>
#include <Base/UnitsApi.h>
#include <App/Application.h>
#include <App/Document.h>
#include <Gui/Application.h>
@@ -197,10 +198,16 @@ CmdPointsConvert::CmdPointsConvert()
void CmdPointsConvert::activated(int iMsg)
{
Q_UNUSED(iMsg);
double STD_OCC_TOLERANCE = 1e-6;
int decimals = Base::UnitsApi::getDecimals();
double tolerance_from_decimals = pow(10., -decimals);
double minimal_tolerance = tolerance_from_decimals < STD_OCC_TOLERANCE ? STD_OCC_TOLERANCE : tolerance_from_decimals;
bool ok;
double tol = QInputDialog::getDouble(Gui::getMainWindow(), QObject::tr("Distance"),
QObject::tr("Enter maximum distance:"), 0.1, 0.05, 10.0, 2, &ok, Qt::MSWindowsFixedSizeDialogHint);
QObject::tr("Enter maximum distance:"), 0.1, minimal_tolerance, 10.0, decimals, &ok, Qt::MSWindowsFixedSizeDialogHint);
if (!ok)
return;
+17 -17
View File
@@ -44,6 +44,7 @@
#include "PovTools.h"
#include "LuxTools.h"
#include <Mod/Part/App/Tools.h>
using Base::Console;
@@ -95,35 +96,34 @@ void LuxTools::writeShape(std::ostream &out, const char *PartName, const TopoDS_
// get the shape and mesh it
const TopoDS_Face& aFace = TopoDS::Face(ex.Current());
// this block mesh the face and transfers it in a C array of vertices and face indexes
Standard_Integer nbNodesInFace,nbTriInFace;
gp_Vec* vertices=0;
gp_Vec* vertexnormals=0;
long* cons=0;
std::vector<gp_Pnt> points;
std::vector<gp_Vec> vertexnormals;
std::vector<Poly_Triangle> facets;
if (!Part::Tools::getTriangulation(aFace, points, facets)) {
break;
}
PovTools::transferToArray(aFace,&vertices,&vertexnormals,&cons,nbNodesInFace,nbTriInFace);
Part::Tools::getPointNormals(points, facets, vertexnormals);
Part::Tools::getPointNormals(points, aFace, vertexnormals);
if (!vertices) break;
// writing vertices
for (int i=0; i < nbNodesInFace; i++) {
P << vertices[i].X() << " " << vertices[i].Y() << " " << vertices[i].Z() << " ";
for (std::size_t i=0; i < points.size(); i++) {
P << points[i].X() << " " << points[i].Y() << " " << points[i].Z() << " ";
}
// writing per vertex normals
for (int j=0; j < nbNodesInFace; j++) {
for (std::size_t j=0; j < vertexnormals.size(); j++) {
N << vertexnormals[j].X() << " " << vertexnormals[j].Y() << " " << vertexnormals[j].Z() << " ";
}
// writing triangle indices
for (int k=0; k < nbTriInFace; k++) {
triindices << cons[3*k]+vi << " " << cons[3*k+2]+vi << " " << cons[3*k+1]+vi << " ";
for (std::size_t k=0; k < facets.size(); k++) {
Standard_Integer n1, n2, n3;
facets[k].Get(n1, n2, n3);
triindices << n1 + vi << " " << n3 + vi << " " << n2 + vi << " ";
}
vi = vi + nbNodesInFace;
delete [] vertexnormals;
delete [] vertices;
delete [] cons;
vi = vi + points.size();
seq.next();
+49 -179
View File
@@ -41,6 +41,7 @@
#include "PovTools.h"
#include <Mod/Part/App/Tools.h>
using Base::Console;
@@ -158,7 +159,7 @@ void PovTools::writeData(const char *FileName, const char *PartName,
std::vector<Base::Vector3d> normals;
std::vector<Data::ComplexGeoData::Facet> facets;
Data::Segment* segm = data->getSubElement("Face", i);
data->getFacesFromSubelement(segm, points, normals, facets);
data->getFacesFromSubElement(segm, points, normals, facets);
delete segm;
// writing per face header
@@ -242,53 +243,53 @@ void PovTools::writeShape(std::ostream &out, const char *PartName,
// get the shape and mesh it
const TopoDS_Face& aFace = TopoDS::Face(ex.Current());
// this block mesh the face and transfers it in a C array of vertices and face indexes
Standard_Integer nbNodesInFace,nbTriInFace;
gp_Vec* vertices=0;
gp_Vec* vertexnormals=0;
long* cons=0;
std::vector<gp_Pnt> points;
std::vector<gp_Vec> vertexnormals;
std::vector<Poly_Triangle> facets;
if (!Part::Tools::getTriangulation(aFace, points, facets)) {
break;
}
Part::Tools::getPointNormals(points, facets, vertexnormals);
Part::Tools::getPointNormals(points, aFace, vertexnormals);
transferToArray(aFace,&vertices,&vertexnormals,&cons,nbNodesInFace,nbTriInFace);
if (!vertices) break;
// writing per face header
out << "// face number" << l << " +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl
<< "#declare " << PartName << l << " = mesh2{" << endl
<< " vertex_vectors {" << endl
<< " " << nbNodesInFace << "," << endl;
<< " " << points.size() << "," << endl;
// writing vertices
for (int i=0; i < nbNodesInFace; i++) {
out << " <" << vertices[i].X() << ","
<< vertices[i].Z() << ","
<< vertices[i].Y() << ">,"
<< endl;
for (std::size_t i=0; i < points.size(); i++) {
out << " <"
<< points[i].X() << ","
<< points[i].Z() << ","
<< points[i].Y() << ">,"
<< endl;
}
out << " }" << endl
// writing per vertex normals
<< " normal_vectors {" << endl
<< " " << nbNodesInFace << "," << endl;
for (int j=0; j < nbNodesInFace; j++) {
out << " <" << vertexnormals[j].X() << ","
<< vertexnormals[j].Z() << ","
<< vertexnormals[j].Y() << ">,"
<< endl;
<< " " << vertexnormals.size() << "," << endl;
for (std::size_t j=0; j < vertexnormals.size(); j++) {
out << " <"
<< vertexnormals[j].X() << ","
<< vertexnormals[j].Z() << ","
<< vertexnormals[j].Y() << ">,"
<< endl;
}
out << " }" << endl
// writing triangle indices
<< " face_indices {" << endl
<< " " << nbTriInFace << "," << endl;
for (int k=0; k < nbTriInFace; k++) {
out << " <" << cons[3*k] << ","<< cons[3*k+2] << ","<< cons[3*k+1] << ">," << endl;
<< " " << facets.size() << "," << endl;
for (std::size_t k=0; k < facets.size(); k++) {
Standard_Integer n1, n2, n3;
facets[k].Get(n1, n2, n3);
out << " <" << n1 << ","<< n3 << "," << n2 << ">," << endl;
}
// end of face
out << " }" << endl
<< "} // end of Face"<< l << endl << endl;
delete [] vertexnormals;
delete [] vertices;
delete [] cons;
seq.next();
} // end of face loop
@@ -323,36 +324,32 @@ void PovTools::writeShapeCSV(const char *FileName,
Base::SequencerLauncher seq("Writing file", l);
// write the file
l = 1;
for (ex.Init(Shape, TopAbs_FACE); ex.More(); ex.Next(),l++) {
for (ex.Init(Shape, TopAbs_FACE); ex.More(); ex.Next()) {
// get the shape and mesh it
const TopoDS_Face& aFace = TopoDS::Face(ex.Current());
// this block mesh the face and transfers it in a C array of vertices and face indexes
Standard_Integer nbNodesInFace,nbTriInFace;
gp_Vec* vertices=0;
gp_Vec* vertexnormals=0;
long* cons=0;
transferToArray(aFace,&vertices,&vertexnormals,&cons,nbNodesInFace,nbTriInFace);
if (!vertices) break;
// writing per face header
// writing vertices
for (int i=0; i < nbNodesInFace; i++) {
fout << vertices[i].X() << cSeperator
<< vertices[i].Z() << cSeperator
<< vertices[i].Y() << cSeperator
<< vertexnormals[i].X() * fLength <<cSeperator
<< vertexnormals[i].Z() * fLength <<cSeperator
<< vertexnormals[i].Y() * fLength <<cSeperator
<< endl;
std::vector<gp_Pnt> points;
std::vector<gp_Vec> vertexnormals;
std::vector<Poly_Triangle> facets;
if (!Part::Tools::getTriangulation(aFace, points, facets)) {
break;
}
delete [] vertexnormals;
delete [] vertices;
delete [] cons;
Part::Tools::getPointNormals(points, facets, vertexnormals);
Part::Tools::getPointNormals(points, aFace, vertexnormals);
// writing per face header
// writing vertices
for (std::size_t i=0; i < points.size(); i++) {
fout << points[i].X() << cSeperator
<< points[i].Z() << cSeperator
<< points[i].Y() << cSeperator
<< vertexnormals[i].X() * fLength << cSeperator
<< vertexnormals[i].Z() * fLength << cSeperator
<< vertexnormals[i].Y() * fLength << cSeperator
<< endl;
}
seq.next();
@@ -360,130 +357,3 @@ void PovTools::writeShapeCSV(const char *FileName,
fout.close();
}
void PovTools::transferToArray(const TopoDS_Face& aFace,gp_Vec** vertices,gp_Vec** vertexnormals, long** cons,int &nbNodesInFace,int &nbTriInFace )
{
TopLoc_Location aLoc;
// doing the meshing and checking the result
//BRepMesh_IncrementalMesh MESH(aFace,fDeflection);
Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation(aFace,aLoc);
if (aPoly.IsNull()) {
Base::Console().Log("Empty face triangulation\n");
nbNodesInFace =0;
nbTriInFace = 0;
vertices = 0l;
cons = 0l;
return;
}
// getting the transformation of the shape/face
gp_Trsf myTransf;
Standard_Boolean identity = true;
if (!aLoc.IsIdentity()) {
identity = false;
myTransf = aLoc.Transformation();
}
Standard_Integer i;
// getting size and create the array
nbNodesInFace = aPoly->NbNodes();
nbTriInFace = aPoly->NbTriangles();
*vertices = new gp_Vec[nbNodesInFace];
*vertexnormals = new gp_Vec[nbNodesInFace];
for (i=0; i < nbNodesInFace; i++) {
(*vertexnormals)[i]= gp_Vec(0.0,0.0,0.0);
}
*cons = new long[3*(nbTriInFace)+1];
// check orientation
TopAbs_Orientation orient = aFace.Orientation();
// cycling through the poly mesh
const Poly_Array1OfTriangle& Triangles = aPoly->Triangles();
const TColgp_Array1OfPnt& Nodes = aPoly->Nodes();
for (i=1; i<=nbTriInFace; i++) {
// Get the triangle
Standard_Integer N1,N2,N3;
Triangles(i).Get(N1,N2,N3);
// change orientation of the triangles
if ( orient != TopAbs_FORWARD )
{
Standard_Integer tmp = N1;
N1 = N2;
N2 = tmp;
}
gp_Pnt V1 = Nodes(N1);
gp_Pnt V2 = Nodes(N2);
gp_Pnt V3 = Nodes(N3);
// transform the vertices to the place of the face
if (!identity) {
V1.Transform(myTransf);
V2.Transform(myTransf);
V3.Transform(myTransf);
}
// Calculate triangle normal
gp_Vec v1(V1.X(),V1.Y(),V1.Z()),v2(V2.X(),V2.Y(),V2.Z()),v3(V3.X(),V3.Y(),V3.Z());
gp_Vec Normal = (v2-v1)^(v3-v1);
//Standard_Real Area = 0.5 * Normal.Magnitude();
// add the triangle normal to the vertex normal for all points of this triangle
(*vertexnormals)[N1-1] += gp_Vec(Normal.X(),Normal.Y(),Normal.Z());
(*vertexnormals)[N2-1] += gp_Vec(Normal.X(),Normal.Y(),Normal.Z());
(*vertexnormals)[N3-1] += gp_Vec(Normal.X(),Normal.Y(),Normal.Z());
(*vertices)[N1-1].SetX((float)(V1.X()));
(*vertices)[N1-1].SetY((float)(V1.Y()));
(*vertices)[N1-1].SetZ((float)(V1.Z()));
(*vertices)[N2-1].SetX((float)(V2.X()));
(*vertices)[N2-1].SetY((float)(V2.Y()));
(*vertices)[N2-1].SetZ((float)(V2.Z()));
(*vertices)[N3-1].SetX((float)(V3.X()));
(*vertices)[N3-1].SetY((float)(V3.Y()));
(*vertices)[N3-1].SetZ((float)(V3.Z()));
int j = i - 1;
N1--;
N2--;
N3--;
(*cons)[3*j] = N1;
(*cons)[3*j+1] = N2;
(*cons)[3*j+2] = N3;
}
// normalize all vertex normals
for (i=0; i < nbNodesInFace; i++) {
gp_Dir clNormal;
try {
Handle(Geom_Surface) Surface = BRep_Tool::Surface(aFace);
gp_Pnt vertex((*vertices)[i].XYZ());
// gp_Pnt vertex((*vertices)[i][0], (*vertices)[i][1], (*vertices)[i][2]);
GeomAPI_ProjectPointOnSurf ProPntSrf(vertex, Surface);
Standard_Real fU, fV;
ProPntSrf.Parameters(1, fU, fV);
GeomLProp_SLProps clPropOfFace(Surface, fU, fV, 2, gp::Resolution());
clNormal = clPropOfFace.Normal();
gp_Vec temp = clNormal;
//Base::Console().Log("unterschied:%.2f",temp.dot((*vertexnormals)[i]));
if ( temp * (*vertexnormals)[i] < 0 )
temp = -temp;
(*vertexnormals)[i] = temp;
}
catch (...) {
}
(*vertexnormals)[i].Normalize();
}
}
-3
View File
@@ -110,9 +110,6 @@ public:
const TopoDS_Shape& Shape,
float fMeshDeviation,
float fLength);
static void transferToArray(const TopoDS_Face& aFace,gp_Vec** vertices,gp_Vec** vertexnormals, long** cons,int &nbNodesInFace,int &nbTriInFace );
};
+3
View File
@@ -47,6 +47,7 @@ set(SketcherGui_UIC_SRCS
SketchRectangularArrayDialog.ui
SketcherRegularPolygonDialog.ui
ConstraintMultiFilterDialog.ui
ConstraintSettingsDialog.ui
)
if(BUILD_QT5)
@@ -120,6 +121,8 @@ SET(SketcherGui_SRCS
SketcherRegularPolygonDialog.cpp
ConstraintMultiFilterDialog.h
ConstraintMultiFilterDialog.cpp
ConstraintSettingsDialog.h
ConstraintSettingsDialog.cpp
TaskDlgEditSketch.cpp
TaskDlgEditSketch.h
ViewProviderPython.cpp
+46 -29
View File
@@ -337,6 +337,7 @@ void CmdSketcherSelectConstraints::activated(int iMsg)
getSelection().clearSelection();
std::vector<std::string> constraintSubNames;
// go through the selected subelements
for (std::vector<std::string>::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) {
// only handle edges
@@ -349,13 +350,15 @@ void CmdSketcherSelectConstraints::activated(int iMsg)
it != vals.end(); ++it,++i)
{
if ((*it)->First == GeoId || (*it)->Second == GeoId || (*it)->Third == GeoId) {
Gui::Selection().addSelection(doc_name.c_str(),
obj_name.c_str(),
Sketcher::PropertyConstraintList::getConstraintName(i).c_str());
constraintSubNames.push_back(Sketcher::PropertyConstraintList::getConstraintName(i));
}
}
}
}
if(!constraintSubNames.empty())
Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), constraintSubNames);
}
bool CmdSketcherSelectConstraints::isActive(void)
@@ -533,17 +536,20 @@ void CmdSketcherSelectRedundantConstraints::activated(int iMsg)
getSelection().clearSelection();
// push the constraints
std::vector<std::string> constraintSubNames;
int i = 0;
for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();it != vals.end(); ++it,++i) {
for(std::vector< int >::const_iterator itc= solverredundant.begin();itc != solverredundant.end(); ++itc) {
if ((*itc) - 1 == i) {
Gui::Selection().addSelection(doc_name.c_str(),
obj_name.c_str(),
Sketcher::PropertyConstraintList::getConstraintName(i).c_str());
constraintSubNames.push_back(Sketcher::PropertyConstraintList::getConstraintName(i));
break;
}
}
}
if(!constraintSubNames.empty())
Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), constraintSubNames);
}
bool CmdSketcherSelectRedundantConstraints::isActive(void)
@@ -587,17 +593,19 @@ void CmdSketcherSelectMalformedConstraints::activated(int iMsg)
getSelection().clearSelection();
// push the constraints
std::vector<std::string> constraintSubNames;
int i = 0;
for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();it != vals.end(); ++it,++i) {
for(std::vector< int >::const_iterator itc= solvermalformed.begin();itc != solvermalformed.end(); ++itc) {
if ((*itc) - 1 == i) {
Gui::Selection().addSelection(doc_name.c_str(),
obj_name.c_str(),
Sketcher::PropertyConstraintList::getConstraintName(i).c_str());
constraintSubNames.push_back(Sketcher::PropertyConstraintList::getConstraintName(i));
break;
}
}
}
if(!constraintSubNames.empty())
Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), constraintSubNames);
}
bool CmdSketcherSelectMalformedConstraints::isActive(void)
@@ -641,17 +649,19 @@ void CmdSketcherSelectPartiallyRedundantConstraints::activated(int iMsg)
getSelection().clearSelection();
// push the constraints
std::vector<std::string> constraintSubNames;
int i = 0;
for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();it != vals.end(); ++it,++i) {
for(std::vector< int >::const_iterator itc= solverpartiallyredundant.begin();itc != solverpartiallyredundant.end(); ++itc) {
if ((*itc) - 1 == i) {
Gui::Selection().addSelection(doc_name.c_str(),
obj_name.c_str(),
Sketcher::PropertyConstraintList::getConstraintName(i).c_str());
constraintSubNames.push_back(Sketcher::PropertyConstraintList::getConstraintName(i));
break;
}
}
}
if(!constraintSubNames.empty())
Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), constraintSubNames);
}
bool CmdSketcherSelectPartiallyRedundantConstraints::isActive(void)
@@ -693,17 +703,19 @@ void CmdSketcherSelectConflictingConstraints::activated(int iMsg)
getSelection().clearSelection();
// push the constraints
std::vector<std::string> constraintSubNames;
int i = 0;
for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();it != vals.end(); ++it,++i) {
for (std::vector< int >::const_iterator itc= solverconflicting.begin();itc != solverconflicting.end(); ++itc) {
if ((*itc) - 1 == i) {
Gui::Selection().addSelection(doc_name.c_str(),
obj_name.c_str(),
Sketcher::PropertyConstraintList::getConstraintName(i).c_str());
constraintSubNames.push_back(Sketcher::PropertyConstraintList::getConstraintName(i));
break;
}
}
}
if(!constraintSubNames.empty())
Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), constraintSubNames);
}
bool CmdSketcherSelectConflictingConstraints::isActive(void)
@@ -747,8 +759,7 @@ void CmdSketcherSelectElementsAssociatedWithConstraints::activated(int iMsg)
std::string obj_name = Obj->getNameInDocument();
std::stringstream ss;
int selected = 0;
std::vector<std::string> elementSubNames;
// go through the selected subelements
for (std::vector<std::string>::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) {
// only handle constraints
@@ -772,9 +783,7 @@ void CmdSketcherSelectElementsAssociatedWithConstraints::activated(int iMsg)
ss << "Vertex" << vertex + 1;
break;
}
Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
selected++;
elementSubNames.push_back(ss.str());
}
if(vals[ConstrId]->Second!=Constraint::GeoUndef){
@@ -794,8 +803,7 @@ void CmdSketcherSelectElementsAssociatedWithConstraints::activated(int iMsg)
break;
}
Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
selected++;
elementSubNames.push_back(ss.str());
}
if(vals[ConstrId]->Third!=Constraint::GeoUndef){
@@ -815,17 +823,20 @@ void CmdSketcherSelectElementsAssociatedWithConstraints::activated(int iMsg)
break;
}
Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
selected++;
elementSubNames.push_back(ss.str());
}
}
}
}
if (selected == 0) {
if (elementSubNames.empty()) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No constraint selected"),
QObject::tr("At least one constraint must be selected"));
}
else {
Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), elementSubNames);
}
}
bool CmdSketcherSelectElementsAssociatedWithConstraints::isActive(void)
@@ -866,22 +877,24 @@ void CmdSketcherSelectElementsWithDoFs::activated(int iMsg)
auto geos = Obj->getInternalGeometry();
auto testselectvertex = [&Obj, &ss, &doc_name, &obj_name](int geoId, PointPos pos) {
std::vector<std::string> elementSubNames;
auto testselectvertex = [&Obj, &ss, &elementSubNames](int geoId, PointPos pos) {
ss.str(std::string());
int vertex = Obj->getVertexIndexGeoPos(geoId, pos);
if (vertex > -1) {
ss << "Vertex" << vertex + 1;
Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
elementSubNames.push_back(ss.str());
}
};
auto testselectedge = [&ss, &doc_name, &obj_name](int geoId) {
auto testselectedge = [&ss, &elementSubNames](int geoId) {
ss.str(std::string());
ss << "Edge" << geoId + 1;
Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
elementSubNames.push_back(ss.str());
};
int geoid = 0;
@@ -911,6 +924,10 @@ void CmdSketcherSelectElementsWithDoFs::activated(int iMsg)
geoid++;
}
if (!elementSubNames.empty()) {
Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), elementSubNames);
}
}
bool CmdSketcherSelectElementsWithDoFs::isActive(void)
+17 -15
View File
@@ -36,19 +36,19 @@ namespace ConstraintFilter {
Datums = 2,
Named = 3,
NonDriving = 4,
Horizontal = 5,
Vertical = 6,
Coincident = 7,
PointOnObject = 8,
Coincident = 5,
PointOnObject = 6,
Vertical = 7,
Horizontal = 8,
Parallel = 9,
Perpendicular = 10,
Tangent = 11,
Equality = 12,
Symmetric = 13,
Block = 14,
Distance = 15,
HorizontalDistance = 16,
VerticalDistance = 17,
HorizontalDistance = 15,
VerticalDistance = 16,
Distance = 17,
Radius = 18,
Weight = 19,
Diameter = 20,
@@ -60,6 +60,8 @@ namespace ConstraintFilter {
enum SpecialFilterValue {
Multiple = 24,
Selection = 25,
AssociatedConstraints = 26,
NumSpecialFilterValue
};
@@ -73,22 +75,22 @@ namespace ConstraintFilter {
1 << FilterValue::Geometric | 1 << FilterValue::Horizontal | 1 << FilterValue::Vertical | 1 << FilterValue::Coincident |
1 << FilterValue::PointOnObject | 1 << FilterValue::Parallel | 1 << FilterValue::Perpendicular | 1 << FilterValue::Tangent |
1 << FilterValue::Equality | 1 << FilterValue::Symmetric | 1 << FilterValue::Block | 1 << FilterValue::InternalAlignment, // Geometric = All others not being datums (1)
1 << FilterValue::Datums | 1 << FilterValue::NonDriving | 1 << FilterValue::Distance | 1 << FilterValue::HorizontalDistance | 1 << FilterValue::VerticalDistance | 1 << FilterValue::Radius | 1 << FilterValue::Weight | 1 << FilterValue::Diameter | 1 << FilterValue::Angle | 1 << FilterValue::SnellsLaw, // Datum = all others not being geometric (2)
1 << FilterValue::Datums | 1 << FilterValue::Distance | 1 << FilterValue::HorizontalDistance | 1 << FilterValue::VerticalDistance | 1 << FilterValue::Radius | 1 << FilterValue::Weight | 1 << FilterValue::Diameter | 1 << FilterValue::Angle | 1 << FilterValue::SnellsLaw, // Datum = all others not being geometric (2)
1 << FilterValue::Named, // Named = Just this (3)
1 << FilterValue::NonDriving, // NonDriving = Just this (4)
1 << FilterValue::Horizontal, // Horizontal = Just this (5)
1 << FilterValue::Vertical, // Vertical = Just this (6)
1 << FilterValue::Coincident, // Coincident = Just this (7)
1 << FilterValue::PointOnObject, // PointOnObject = Just this (8)
1 << FilterValue::Coincident, // Coincident = Just this (5)
1 << FilterValue::PointOnObject, // PointOnObject = Just this (6)
1 << FilterValue::Vertical, // Vertical = Just this (7)
1 << FilterValue::Horizontal, // Horizontal = Just this (8)
1 << FilterValue::Parallel, // Parallel = Just this (9)
1 << FilterValue::Perpendicular, // Perpendicular = Just this (10)
1 << FilterValue::Tangent, // Tangent = Just this (11)
1 << FilterValue::Equality, // Equality = Just this (12)
1 << FilterValue::Symmetric, // Symmetric = Just this (13)
1 << FilterValue::Block, // Block = Just this (14)
1 << FilterValue::Distance, // Distance = Just this (15)
1 << FilterValue::HorizontalDistance, // HorizontalDistance = Just this (16)
1 << FilterValue::VerticalDistance, // VerticalDistance = Just this (17)
1 << FilterValue::HorizontalDistance, // HorizontalDistance = Just this (15)
1 << FilterValue::VerticalDistance, // VerticalDistance = Just this (16)
1 << FilterValue::Distance, // Distance = Just this (17)
1 << FilterValue::Radius, // Radius = Just this (18)
1 << FilterValue::Weight, // Weight = Just this (19)
1 << FilterValue::Diameter, // Diameter = Just this (20)
@@ -93,15 +93,43 @@ void ConstraintMultiFilterDialog::on_listMultiFilter_itemChanged(QListWidgetItem
{
int filterindex = ui->listMultiFilter->row(item);
auto aggregate = filterAggregates[filterindex];
auto itemAggregate = filterAggregates[filterindex];
ui->listMultiFilter->blockSignals(true);
if(item->checkState() == Qt::Checked) {
for(int i = 0; i < ui->listMultiFilter->count(); i++) {
if(aggregate[i])
ui->listMultiFilter->item(i)->setCheckState(Qt::Checked);
for(int i = 0; i < ui->listMultiFilter->count(); i++) {
// any filter comprised on the filter of the activated item, gets the same check state
if(itemAggregate[i])
ui->listMultiFilter->item(i)->setCheckState(item->checkState());
// if unchecking, in addition uncheck any group comprising the unchecked item
if(item->checkState() == Qt::Unchecked) {
if(filterAggregates[i][filterindex])
ui->listMultiFilter->item(i)->setCheckState(Qt::Unchecked);
}
}
// Now that all filters are correctly updated to match dependencies,
// if checking, in addition check any group comprising all items that are checked, and check it if all checked.
if(item->checkState() == Qt::Checked) {
for(int i = 0; i < ui->listMultiFilter->count(); i++) {
if(filterAggregates[i][filterindex]) { // only for groups comprising the changed filter
bool mustBeChecked = true;
for(int j = 0; j < FilterValue::NumFilterValue; j++) {
if (i == j)
continue;
if (filterAggregates[i][j]) // if it is in group
mustBeChecked = mustBeChecked && ui->listMultiFilter->item(j)->checkState() == Qt::Checked;
}
if(mustBeChecked)
ui->listMultiFilter->item(i)->setCheckState(Qt::Checked);
}
}
}
ui->listMultiFilter->blockSignals(false);
}
@@ -9,22 +9,16 @@
<rect>
<x>0</x>
<y>0</y>
<width>325</width>
<width>274</width>
<height>600</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>700</height>
</size>
</property>
<property name="windowTitle">
<string>Multiple filter selection</string>
</property>
@@ -39,16 +33,13 @@
<item>
<widget class="QListWidget" name="listMultiFilter">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>500</height>
</size>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
@@ -78,17 +69,7 @@
</item>
<item>
<property name="text">
<string>Non-Driving</string>
</property>
</item>
<item>
<property name="text">
<string>Horizontal</string>
</property>
</item>
<item>
<property name="text">
<string>Vertical</string>
<string>Reference</string>
</property>
</item>
<item>
@@ -101,6 +82,16 @@
<string>Point on Object</string>
</property>
</item>
<item>
<property name="text">
<string>Vertical</string>
</property>
</item>
<item>
<property name="text">
<string>Horizontal</string>
</property>
</item>
<item>
<property name="text">
<string>Parallel</string>
@@ -131,11 +122,6 @@
<string>Block</string>
</property>
</item>
<item>
<property name="text">
<string>Distance</string>
</property>
</item>
<item>
<property name="text">
<string>Horizontal Distance</string>
@@ -146,6 +132,11 @@
<string>Vertical Distance</string>
</property>
</item>
<item>
<property name="text">
<string>Distance</string>
</property>
</item>
<item>
<property name="text">
<string>Radius</string>
@@ -217,19 +208,6 @@
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
@@ -0,0 +1,136 @@
/***************************************************************************
* Copyright (c) 2021 Abdullah Tahiri <abdullah.tahiri.yo@gmail.com> *
* *
* 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 <QPixmap>
# include <QDialog>
#endif
#include <Gui/BitmapFactory.h>
#include <Gui/MainWindow.h>
#include <Base/Tools.h>
#include <Base/UnitsApi.h>
#include <Gui/PrefWidgets.h>
#include "ui_ConstraintSettingsDialog.h"
#include "ConstraintSettingsDialog.h"
using namespace SketcherGui;
ConstraintSettingsDialog::ConstraintSettingsDialog(void)
: QDialog(Gui::getMainWindow()), ui(new Ui_ConstraintSettingsDialog)
{
ui->setupUi(this);
{ // in case any signal is connected before this
QSignalBlocker block(this);
loadSettings();
snapshotInitialSettings();
}
QObject::connect(
ui->filterInternalAlignment, SIGNAL(stateChanged(int)),
this , SLOT (on_filterInternalAlignment_stateChanged(int))
);
QObject::connect(
ui->extendedInformation, SIGNAL(stateChanged(int)),
this , SLOT (on_extendedInformation_stateChanged(int))
);
QObject::connect(
ui->visualisationTrackingFilter, SIGNAL(stateChanged(int)),
this , SLOT (on_visualisationTrackingFilter_stateChanged(int))
);
}
void ConstraintSettingsDialog::saveSettings()
{
ui->extendedInformation->onSave();
ui->filterInternalAlignment->onSave();
ui->visualisationTrackingFilter->onSave();
}
void ConstraintSettingsDialog::loadSettings()
{
ui->extendedInformation->onRestore();
ui->filterInternalAlignment->onRestore();
ui->visualisationTrackingFilter->onRestore();
}
void ConstraintSettingsDialog::snapshotInitialSettings()
{
auto isChecked = [] (auto prefwidget) {return prefwidget->checkState() == Qt::Checked;};
extendedInformation = isChecked(ui->extendedInformation);
filterInternalAlignment = isChecked(ui->filterInternalAlignment);
visualisationTrackingFilter = isChecked(ui->visualisationTrackingFilter);
}
void ConstraintSettingsDialog::restoreInitialSettings()
{
auto restoreCheck = [] (auto prefwidget, bool initialvalue) {
if( initialvalue != (prefwidget->checkState() == Qt::Checked)) // if the state really changed
initialvalue ? prefwidget->setCheckState(Qt::Checked) : prefwidget->setCheckState(Qt::Unchecked);
};
restoreCheck(ui->extendedInformation, extendedInformation);
restoreCheck(ui->filterInternalAlignment, filterInternalAlignment);
restoreCheck(ui->visualisationTrackingFilter, visualisationTrackingFilter);
}
void ConstraintSettingsDialog::accept()
{
saveSettings();
QDialog::accept();
}
void ConstraintSettingsDialog::reject()
{
restoreInitialSettings();
saveSettings();
QDialog::reject();
}
void ConstraintSettingsDialog::on_filterInternalAlignment_stateChanged(int state)
{
ui->filterInternalAlignment->onSave();
Q_EMIT emit_filterInternalAlignment_stateChanged(state);
}
void ConstraintSettingsDialog::on_visualisationTrackingFilter_stateChanged(int state)
{
ui->visualisationTrackingFilter->onSave();
Q_EMIT emit_visualisationTrackingFilter_stateChanged(state);
}
void ConstraintSettingsDialog::on_extendedInformation_stateChanged(int state)
{
ui->extendedInformation->onSave();
Q_EMIT emit_extendedInformation_stateChanged(state);
}
ConstraintSettingsDialog::~ConstraintSettingsDialog()
{
}
#include "moc_ConstraintSettingsDialog.cpp"
@@ -0,0 +1,70 @@
/***************************************************************************
* Copyright (c) 2021 Abdullah Tahiri <abdullah.tahiri.yo@gmail.com> *
* *
* 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 SKETCHERGUI_ConstraintSettingsDialog_H
#define SKETCHERGUI_ConstraintSettingsDialog_H
#include <QDialog>
#include "ConstraintFilters.h"
namespace SketcherGui {
using namespace ConstraintFilter;
class Ui_ConstraintSettingsDialog;
class ConstraintSettingsDialog : public QDialog
{
Q_OBJECT
public:
ConstraintSettingsDialog(void);
~ConstraintSettingsDialog();
Q_SIGNALS:
void emit_filterInternalAlignment_stateChanged(int);
void emit_extendedInformation_stateChanged(int);
void emit_visualisationTrackingFilter_stateChanged(int);
public Q_SLOTS:
void accept();
void reject();
void on_filterInternalAlignment_stateChanged(int state);
void on_extendedInformation_stateChanged(int state);
void on_visualisationTrackingFilter_stateChanged(int state);
private:
void saveSettings();
void loadSettings();
void snapshotInitialSettings();
void restoreInitialSettings();
private:
std::unique_ptr<Ui_ConstraintSettingsDialog> ui;
bool extendedInformation;
bool filterInternalAlignment;
bool visualisationTrackingFilter;
};
}
#endif // SKETCHERGUI_ConstraintSettingsDialog_H
@@ -0,0 +1,195 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SketcherGui::ConstraintSettingsDialog</class>
<widget class="QWidget" name="SketcherGui::ConstraintSettingsDialog">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>275</width>
<height>215</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Constraint widget settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>List control</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="1" column="0">
<widget class="Gui::PrefCheckBox" name="filterInternalAlignment">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Internal alignments will be hidden</string>
</property>
<property name="text">
<string>Hide internal alignment</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>HideInternalAlignment</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Sketcher</cstring>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="Gui::PrefCheckBox" name="extendedInformation">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Extended information will be added to the list</string>
</property>
<property name="text">
<string>Extended information</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>ExtendedConstraintInformation</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Sketcher</cstring>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>3D view control</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="Gui::PrefCheckBox" name="visualisationTrackingFilter">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Constraint visualisation tracks filter selection so that filtered out constraints are hidden</string>
</property>
<property name="text">
<string>Show only filtered constraints</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>VisualisationTrackingFilter</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Sketcher</cstring>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::PrefCheckBox</class>
<extends>QCheckBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SketcherGui::ConstraintSettingsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SketcherGui::ConstraintSettingsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
</connections>
</ui>
@@ -238,6 +238,9 @@
<file>icons/tools/Sketcher_SelectVerticalAxis.svg</file>
<file>icons/tools/Sketcher_Symmetry.svg</file>
</qresource>
<qresource>
<file>icons/dialogs/Sketcher_Settings.svg</file>
</qresource>
<qresource>
<file>translations/Sketcher_af.qm</file>
<file>translations/Sketcher_ar.qm</file>

Some files were not shown because too many files have changed in this diff Show More