Merge branch 'master' into master
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -354,7 +354,7 @@ def removeInterVertices(wire):
|
||||
|
||||
|
||||
def cleanProjection(shape, tessellate=True, seglength=0.05):
|
||||
"""Return a compound of edges, optionally tesselate ellipses, splines
|
||||
"""Return a compound of edges, optionally tessellate ellipses, splines
|
||||
and bezcurves.
|
||||
|
||||
The function was formerly used to workaround bugs in the projection
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "Mesh.h"
|
||||
#include "MeshPy.h"
|
||||
#include "MeshPointPy.h"
|
||||
#include "EdgePy.h"
|
||||
#include "FacetPy.h"
|
||||
#include "MeshFeaturePy.h"
|
||||
#include "FeatureMeshImport.h"
|
||||
@@ -66,6 +67,7 @@ PyMOD_INIT_FUNC(Mesh)
|
||||
|
||||
// add mesh elements
|
||||
Base::Interpreter().addType(&Mesh::MeshPointPy ::Type,meshModule,"MeshPoint");
|
||||
Base::Interpreter().addType(&Mesh::EdgePy ::Type,meshModule,"Edge");
|
||||
Base::Interpreter().addType(&Mesh::FacetPy ::Type,meshModule,"Facet");
|
||||
Base::Interpreter().addType(&Mesh::MeshPy ::Type,meshModule,"Mesh");
|
||||
Base::Interpreter().addType(&Mesh::MeshFeaturePy::Type,meshModule,"Feature");
|
||||
|
||||
@@ -28,12 +28,14 @@ if (BUILD_QT5)
|
||||
)
|
||||
endif()
|
||||
|
||||
generate_from_xml(EdgePy)
|
||||
generate_from_xml(FacetPy)
|
||||
generate_from_xml(MeshFeaturePy)
|
||||
generate_from_xml(MeshPointPy)
|
||||
generate_from_xml(MeshPy)
|
||||
|
||||
SET(Mesh_XML_SRCS
|
||||
EdgePy.xml
|
||||
FacetPy.xml
|
||||
MeshFeaturePy.xml
|
||||
MeshPointPy.xml
|
||||
@@ -331,6 +333,9 @@ SET(Mesh_SRCS
|
||||
Exporter.h
|
||||
Importer.cpp
|
||||
Importer.h
|
||||
Edge.cpp
|
||||
Edge.h
|
||||
EdgePyImp.cpp
|
||||
Facet.cpp
|
||||
Facet.h
|
||||
FacetPyImp.cpp
|
||||
|
||||
@@ -280,6 +280,25 @@ bool MeshGeomEdge::IntersectWithLine (const Base::Vector3f &rclPt,
|
||||
return dist2 + dist3 <= dist1 + eps;
|
||||
}
|
||||
|
||||
bool MeshGeomEdge::IsParallel(const MeshGeomEdge &edge) const
|
||||
{
|
||||
Base::Vector3f r(_aclPoints[1] - _aclPoints[0]);
|
||||
Base::Vector3f s(edge._aclPoints[1] - edge._aclPoints[0]);
|
||||
Base::Vector3f n = r.Cross(s);
|
||||
return n.IsNull();
|
||||
}
|
||||
|
||||
bool MeshGeomEdge::IsCollinear(const MeshGeomEdge &edge) const
|
||||
{
|
||||
if (IsParallel(edge)) {
|
||||
Base::Vector3f r(_aclPoints[1] - _aclPoints[0]);
|
||||
Base::Vector3f d = edge._aclPoints[0] - _aclPoints[0];
|
||||
return d.Cross(r).IsNull();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MeshGeomEdge::IntersectWithEdge (const MeshGeomEdge &edge, Base::Vector3f &res) const
|
||||
{
|
||||
const float eps = 1e-06f;
|
||||
@@ -1017,6 +1036,15 @@ void MeshGeomFacet::SubSample (float fStep, std::vector<Base::Vector3f> &rclPoin
|
||||
rclPoints.insert(rclPoints.end(), clPoints.begin(), clPoints.end());
|
||||
}
|
||||
|
||||
bool MeshGeomFacet::IsCoplanar(const MeshGeomFacet &facet) const
|
||||
{
|
||||
const float eps = 1e-06f;
|
||||
const float unit = 0.9995f;
|
||||
float mult = fabs(this->GetNormal() * facet.GetNormal());
|
||||
float dist = fabs(DistancePlaneToPoint(facet._aclPoints[0]));
|
||||
return (mult >= unit) && (dist <= eps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast Triangle-Triangle Intersection Test by Tomas Moeller
|
||||
* http://www.acm.org/jgt/papers/Moller97/tritri.html
|
||||
@@ -1049,6 +1077,39 @@ int MeshGeomFacet::IntersectWithFacet (const MeshGeomFacet& rclFacet,
|
||||
Base::Vector3f& rclPt0,
|
||||
Base::Vector3f& rclPt1) const
|
||||
{
|
||||
// Note: tri_tri_intersect_with_isection() does not return line of
|
||||
// intersection when triangles are coplanar. See tritritest.h:18 and 658.
|
||||
if (IsCoplanar(rclFacet)) {
|
||||
// Since tri_tri_intersect_with_isection may return garbage values try to get
|
||||
// sensible values with edge/edge intersections
|
||||
std::vector<Base::Vector3f> intersections;
|
||||
for (short i=0; i<3; i++) {
|
||||
MeshGeomEdge edge1 = GetEdge(i);
|
||||
for (short j=0; j<3; j++) {
|
||||
MeshGeomEdge edge2 = rclFacet.GetEdge(j);
|
||||
Base::Vector3f point;
|
||||
if (edge1.IntersectWithEdge(edge2, point)) {
|
||||
intersections.push_back(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If triangles overlap there can be more than two intersection points
|
||||
// In that case use any two of them.
|
||||
if (intersections.size() >= 2) {
|
||||
rclPt0 = intersections[0];
|
||||
rclPt1 = intersections[1];
|
||||
return 2;
|
||||
}
|
||||
else if (intersections.size() == 1) {
|
||||
rclPt0 = intersections[0];
|
||||
rclPt1 = intersections[0];
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
float V[3][3], U[3][3];
|
||||
int coplanar = 0;
|
||||
float isectpt1[3], isectpt2[3];
|
||||
@@ -1070,45 +1131,17 @@ int MeshGeomFacet::IntersectWithFacet (const MeshGeomFacet& rclFacet,
|
||||
rclPt0.x = isectpt1[0]; rclPt0.y = isectpt1[1]; rclPt0.z = isectpt1[2];
|
||||
rclPt1.x = isectpt2[0]; rclPt1.y = isectpt2[1]; rclPt1.z = isectpt2[2];
|
||||
|
||||
// Note: tri_tri_intersect_with_isection() does not return line of
|
||||
// intersection when triangles are coplanar. See tritritest.h:18 and 658.
|
||||
if (coplanar) {
|
||||
// Since tri_tri_intersect_with_isection may return garbage values try to get
|
||||
// sensible values with edge/edge intersections
|
||||
std::vector<Base::Vector3f> intersections;
|
||||
for (short i=0; i<3; i++) {
|
||||
MeshGeomEdge edge1 = GetEdge(i);
|
||||
for (short j=0; j<3; j++) {
|
||||
MeshGeomEdge edge2 = rclFacet.GetEdge(j);
|
||||
Base::Vector3f point;
|
||||
if (edge1.IntersectWithEdge(edge2, point)) {
|
||||
intersections.push_back(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If triangles overlap there can be more than two intersection points
|
||||
// In that case use any two of them.
|
||||
if (intersections.size() >= 2) {
|
||||
rclPt0 = intersections[0];
|
||||
rclPt1 = intersections[1];
|
||||
}
|
||||
else if (intersections.size() == 1) {
|
||||
rclPt0 = intersections[0];
|
||||
rclPt1 = intersections[0];
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
// With extremely acute-angled triangles it may happen that the algorithm
|
||||
// claims an intersection but the intersection points are far outside the
|
||||
// model. So, a plausibility check is to verify that the intersection points
|
||||
// are inside the bounding boxes of both triangles.
|
||||
Base::BoundBox3f box1 = this->GetBoundBox();
|
||||
box1.Enlarge(0.001f);
|
||||
if (!box1.IsInBox(rclPt0) || !box1.IsInBox(rclPt1))
|
||||
return 0;
|
||||
|
||||
Base::BoundBox3f box2 = rclFacet.GetBoundBox();
|
||||
box2.Enlarge(0.001f);
|
||||
if (!box2.IsInBox(rclPt0) || !box2.IsInBox(rclPt1))
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -198,6 +198,16 @@ public:
|
||||
* Checks if the projection point of \a point lies on the edge.
|
||||
*/
|
||||
bool IsProjectionPointOf(const Base::Vector3f& point) const;
|
||||
/**
|
||||
* Checks if the two edges are parallel.
|
||||
* \note Parallel edges could be collinear.
|
||||
*/
|
||||
bool IsParallel(const MeshGeomEdge &edge) const;
|
||||
/**
|
||||
* Checks if the two edges are collinear.
|
||||
* \note Collinear edges always are parallel.
|
||||
*/
|
||||
bool IsCollinear(const MeshGeomEdge &edge) const;
|
||||
|
||||
public:
|
||||
Base::Vector3f _aclPoints[2]; /**< Corner points */
|
||||
@@ -536,6 +546,10 @@ public:
|
||||
/** Apply a transformation on the triangle.
|
||||
*/
|
||||
void Transform(const Base::Matrix4D&);
|
||||
/**
|
||||
* Checks if the two triangles are coplanar.
|
||||
*/
|
||||
bool IsCoplanar(const MeshGeomFacet &facet) const;
|
||||
|
||||
protected:
|
||||
Base::Vector3f _clNormal; /**< Normal of the facet. */
|
||||
|
||||
@@ -41,7 +41,7 @@ OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
*/
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#define FABS(x) ((float)fabs(x)) /* implement as is fastest on your machine */
|
||||
|
||||
|
||||
74
src/Mod/Mesh/App/Edge.cpp
Normal file
74
src/Mod/Mesh/App/Edge.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2021 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 51 Franklin Street, *
|
||||
* Fifth Floor, Boston, MA 02110-1301, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
# include <sstream>
|
||||
#endif
|
||||
|
||||
#include "Edge.h"
|
||||
#include "Mesh.h"
|
||||
|
||||
using namespace Mesh;
|
||||
|
||||
Edge::Edge()
|
||||
: Index(-1)
|
||||
, Mesh(nullptr)
|
||||
{
|
||||
for (int i=0; i<2; i++) {
|
||||
PIndex[i] = MeshCore::POINT_INDEX_MAX;
|
||||
NIndex[i] = MeshCore::FACET_INDEX_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
Edge::Edge(const Edge& e)
|
||||
: MeshCore::MeshGeomEdge(e)
|
||||
, Index(e.Index)
|
||||
, Mesh(e.Mesh)
|
||||
{
|
||||
for (int i=0; i<2; i++) {
|
||||
PIndex[i] = e.PIndex[i];
|
||||
NIndex[i] = e.NIndex[i];
|
||||
}
|
||||
}
|
||||
|
||||
Edge::~Edge()
|
||||
{
|
||||
}
|
||||
|
||||
void Edge::operator = (const Edge& e)
|
||||
{
|
||||
MeshCore::MeshGeomEdge::operator = (e);
|
||||
Mesh = e.Mesh;
|
||||
Index = e.Index;
|
||||
for (int i=0; i<2; i++) {
|
||||
PIndex[i] = e.PIndex[i];
|
||||
NIndex[i] = e.NIndex[i];
|
||||
}
|
||||
}
|
||||
|
||||
void Edge::unbound()
|
||||
{
|
||||
Index = -1;
|
||||
Mesh = nullptr;
|
||||
}
|
||||
63
src/Mod/Mesh/App/Edge.h
Normal file
63
src/Mod/Mesh/App/Edge.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2021 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 51 Franklin Street, *
|
||||
* Fifth Floor, Boston, MA 02110-1301, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef MESH_EDGE_H
|
||||
#define MESH_EDGE_H
|
||||
|
||||
#include <Base/Matrix.h>
|
||||
#include <Base/Vector3D.h>
|
||||
#include <Base/Handle.h>
|
||||
|
||||
#include <Mod/Mesh/App/Core/Elements.h>
|
||||
|
||||
namespace Mesh
|
||||
{
|
||||
// forward declaration
|
||||
class MeshObject;
|
||||
|
||||
/** The Edge helper class
|
||||
* The Edge class provides an interface for the EdgePy class for
|
||||
* convenient access to the Mesh data structure. This class should not be used
|
||||
* for programming algorithms in C++. Use Mesh Core classes instead!
|
||||
*/
|
||||
class MeshExport Edge : public MeshCore::MeshGeomEdge
|
||||
{
|
||||
public:
|
||||
Edge();
|
||||
Edge(const Edge& f);
|
||||
~Edge();
|
||||
|
||||
bool isBound() const {return Index != -1;}
|
||||
void unbound();
|
||||
void operator = (const Edge& f);
|
||||
|
||||
int Index;
|
||||
MeshCore::PointIndex PIndex[2];
|
||||
MeshCore::FacetIndex NIndex[2];
|
||||
Base::Reference<MeshObject> Mesh;
|
||||
};
|
||||
|
||||
} // namespace Mesh
|
||||
|
||||
|
||||
#endif // MESH_EDGE_H
|
||||
90
src/Mod/Mesh/App/EdgePy.xml
Normal file
90
src/Mod/Mesh/App/EdgePy.xml
Normal file
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="PyObjectBase"
|
||||
Name="EdgePy"
|
||||
Twin="Edge"
|
||||
TwinPointer="Edge"
|
||||
Include="Mod/Mesh/App/Edge.h"
|
||||
FatherInclude="Base/PyObjectBase.h"
|
||||
Namespace="Mesh"
|
||||
Constructor="true"
|
||||
Delete="true"
|
||||
FatherNamespace="Base">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Werner Mayer" EMail="wmayer[at]users.sourceforge.net" />
|
||||
<DeveloperDocu>Edge in a Mesh</DeveloperDocu>
|
||||
<UserDocu>Edge in mesh
|
||||
This is an edge of a facet in a MeshObject. You can get it by e.g. iterating over the facets of a
|
||||
mesh and calling getEdge(index).
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
<Methode Name="intersectWithEdge">
|
||||
<Documentation>
|
||||
<UserDocu>intersectWithEdge(Edge) -> list
|
||||
Get a list of intersection points with another edge.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="isParallel">
|
||||
<Documentation>
|
||||
<UserDocu>isParallel(Edge) -> bool
|
||||
Checks if the two edges are parallel.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="isCollinear">
|
||||
<Documentation>
|
||||
<UserDocu>isCollinear(Edge) -> bool
|
||||
Checks if the two edges are collinear.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="unbound">
|
||||
<Documentation>
|
||||
<UserDocu>method unbound()
|
||||
Cut the connection to a MeshObject. The edge becomes
|
||||
free and is more or less a simple edge.
|
||||
After calling unbound() no topological operation will
|
||||
work!
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="Index" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>The index of this edge of the facet</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Index" Type="Long"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Points" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>A list of points of the edge</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Points" Type="List"/>
|
||||
</Attribute>
|
||||
<Attribute Name="PointIndices" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>The index tuple of point vertices of the mesh this edge is built of</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="PointIndices" Type="Tuple"/>
|
||||
</Attribute>
|
||||
<Attribute Name="NeighbourIndices" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>The index tuple of neighbour facets of the mesh this edge is adjacent with</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="NeighbourIndices" Type="Tuple"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Length" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>The length of the edge</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Length" Type="Float"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Bound" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Bound state of the edge</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Bound" Type="Boolean"/>
|
||||
</Attribute>
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
194
src/Mod/Mesh/App/EdgePyImp.cpp
Normal file
194
src/Mod/Mesh/App/EdgePyImp.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2021 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 51 Franklin Street, *
|
||||
* Fifth Floor, Boston, MA 02110-1301, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include "Mesh.h"
|
||||
#include "Edge.h"
|
||||
#include <Mod/Mesh/App/EdgePy.h>
|
||||
#include <Mod/Mesh/App/EdgePy.cpp>
|
||||
|
||||
#include <Base/Converter.h>
|
||||
#include <Base/VectorPy.h>
|
||||
#include <Base/GeometryPyCXX.h>
|
||||
|
||||
using namespace Mesh;
|
||||
|
||||
// returns a string which represent the object e.g. when printed in python
|
||||
std::string EdgePy::representation() const
|
||||
{
|
||||
EdgePy::PointerType ptr = getEdgePtr();
|
||||
std::stringstream str;
|
||||
str << "Edge (";
|
||||
str << "(" << ptr->_aclPoints[0].x << ", " << ptr->_aclPoints[0].y << ", " << ptr->_aclPoints[0].z << ", Idx=" << ptr->PIndex[0] << "), ";
|
||||
str << "(" << ptr->_aclPoints[1].x << ", " << ptr->_aclPoints[1].y << ", " << ptr->_aclPoints[1].z << ", Idx=" << ptr->PIndex[1] << "), ";
|
||||
str << "Idx=" << ptr->Index << ", (" << ptr->NIndex[0] << ", " << ptr->NIndex[1] << ")";
|
||||
str << ")";
|
||||
|
||||
return str.str();
|
||||
}
|
||||
|
||||
PyObject *EdgePy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper
|
||||
{
|
||||
// create a new instance of EdgePy and the Twin object
|
||||
return new EdgePy(new Edge);
|
||||
}
|
||||
|
||||
// constructor method
|
||||
int EdgePy::PyInit(PyObject* args, PyObject* /*kwds*/)
|
||||
{
|
||||
PyObject* pt1 = nullptr;
|
||||
PyObject* pt2 = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "|O!O!", &Base::VectorPy::Type, &pt1
|
||||
, &Base::VectorPy::Type, &pt2))
|
||||
return -1;
|
||||
|
||||
if (pt1)
|
||||
getEdgePtr()->_aclPoints[0] = Base::convertTo<Base::Vector3f>(Py::Vector(pt1, false).toVector());
|
||||
if (pt2)
|
||||
getEdgePtr()->_aclPoints[1] = Base::convertTo<Base::Vector3f>(Py::Vector(pt2, false).toVector());
|
||||
return 0;
|
||||
}
|
||||
|
||||
Py::Long EdgePy::getIndex() const
|
||||
{
|
||||
return Py::Long((long) getEdgePtr()->Index);
|
||||
}
|
||||
|
||||
PyObject* EdgePy::intersectWithEdge(PyObject *args)
|
||||
{
|
||||
PyObject* object;
|
||||
if (!PyArg_ParseTuple(args, "O!", &EdgePy::Type, &object))
|
||||
return nullptr;
|
||||
EdgePy *edge = static_cast<EdgePy*>(object);
|
||||
EdgePy::PointerType edge_ptr = edge->getEdgePtr();
|
||||
EdgePy::PointerType this_ptr = this->getEdgePtr();
|
||||
Base::Vector3f p;
|
||||
bool ok = this_ptr->IntersectWithEdge(*edge_ptr, p);
|
||||
|
||||
try {
|
||||
Py::List sct;
|
||||
if (ok) {
|
||||
Py::Tuple pt(3);
|
||||
pt.setItem(0, Py::Float(p.x));
|
||||
pt.setItem(1, Py::Float(p.y));
|
||||
pt.setItem(2, Py::Float(p.z));
|
||||
sct.append(pt);
|
||||
}
|
||||
return Py::new_reference_to(sct);
|
||||
}
|
||||
catch (const Py::Exception&) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* EdgePy::isParallel(PyObject *args)
|
||||
{
|
||||
PyObject* object;
|
||||
if (!PyArg_ParseTuple(args, "O!", &EdgePy::Type, &object))
|
||||
return nullptr;
|
||||
EdgePy *edge = static_cast<EdgePy*>(object);
|
||||
EdgePy::PointerType edge_ptr = edge->getEdgePtr();
|
||||
EdgePy::PointerType this_ptr = this->getEdgePtr();
|
||||
bool ok = this_ptr->IsParallel(*edge_ptr);
|
||||
return Py::new_reference_to(Py::Boolean(ok));
|
||||
}
|
||||
|
||||
PyObject* EdgePy::isCollinear(PyObject *args)
|
||||
{
|
||||
PyObject* object;
|
||||
if (!PyArg_ParseTuple(args, "O!", &EdgePy::Type, &object))
|
||||
return nullptr;
|
||||
EdgePy *edge = static_cast<EdgePy*>(object);
|
||||
EdgePy::PointerType edge_ptr = edge->getEdgePtr();
|
||||
EdgePy::PointerType this_ptr = this->getEdgePtr();
|
||||
bool ok = this_ptr->IsCollinear(*edge_ptr);
|
||||
return Py::new_reference_to(Py::Boolean(ok));
|
||||
}
|
||||
|
||||
PyObject* EdgePy::unbound(PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return nullptr;
|
||||
getEdgePtr()->unbound();
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
Py::Boolean EdgePy::getBound() const
|
||||
{
|
||||
return Py::Boolean(getEdgePtr()->isBound());
|
||||
}
|
||||
|
||||
Py::List EdgePy::getPoints() const
|
||||
{
|
||||
EdgePy::PointerType edge = this->getEdgePtr();
|
||||
|
||||
Py::List pts;
|
||||
for (int i=0; i<2; i++) {
|
||||
Py::Tuple pt(3);
|
||||
pt.setItem(0, Py::Float(edge->_aclPoints[i].x));
|
||||
pt.setItem(1, Py::Float(edge->_aclPoints[i].y));
|
||||
pt.setItem(2, Py::Float(edge->_aclPoints[i].z));
|
||||
pts.append(pt);
|
||||
}
|
||||
|
||||
return pts;
|
||||
}
|
||||
|
||||
Py::Tuple EdgePy::getPointIndices() const
|
||||
{
|
||||
EdgePy::PointerType edge = this->getEdgePtr();
|
||||
|
||||
Py::Tuple idxTuple(2);
|
||||
for (int i=0; i<2; i++) {
|
||||
idxTuple.setItem(i, Py::Long(edge->PIndex[i]));
|
||||
}
|
||||
return idxTuple;
|
||||
}
|
||||
|
||||
Py::Tuple EdgePy::getNeighbourIndices() const
|
||||
{
|
||||
EdgePy::PointerType edge = this->getEdgePtr();
|
||||
|
||||
Py::Tuple idxTuple(2);
|
||||
for (int i=0; i<2; i++) {
|
||||
idxTuple.setItem(i, Py::Long(edge->NIndex[i]));
|
||||
}
|
||||
return idxTuple;
|
||||
}
|
||||
|
||||
Py::Float EdgePy::getLength() const
|
||||
{
|
||||
EdgePy::PointerType edge = this->getEdgePtr();
|
||||
return Py::Float(Base::Distance(edge->_aclPoints[0], edge->_aclPoints[1]));
|
||||
}
|
||||
|
||||
PyObject *EdgePy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int EdgePy::setCustomAttributes(const char* /*attr*/, PyObject * /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -69,3 +69,23 @@ void Facet::operator = (const Facet& f)
|
||||
NIndex[i] = f.NIndex[i];
|
||||
}
|
||||
}
|
||||
|
||||
Edge Facet::getEdge(int index) const
|
||||
{
|
||||
index = index % 3;
|
||||
Edge edge;
|
||||
// geometric coordinates
|
||||
edge._aclPoints[0] = this->_aclPoints[index];
|
||||
edge._aclPoints[1] = this->_aclPoints[(index + 1) % 3];
|
||||
|
||||
// indices
|
||||
edge.Index = index;
|
||||
edge.PIndex[0] = this->PIndex[index];
|
||||
edge.PIndex[1] = this->PIndex[(index + 1) % 3];
|
||||
edge.NIndex[0] = this->Index;
|
||||
edge.NIndex[1] = this->NIndex[index];
|
||||
edge._bBorder = (this->NIndex[index] == MeshCore::FACET_INDEX_MAX);
|
||||
|
||||
edge.Mesh = this->Mesh;
|
||||
return edge;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include <Base/Vector3D.h>
|
||||
#include <Base/Handle.h>
|
||||
|
||||
#include "Core/Elements.h"
|
||||
#include <Mod/Mesh/App/Edge.h>
|
||||
|
||||
namespace Mesh
|
||||
{
|
||||
@@ -49,6 +49,7 @@ public:
|
||||
|
||||
bool isBound() const {return Index != MeshCore::FACET_INDEX_MAX;}
|
||||
void operator = (const Facet& f);
|
||||
Edge getEdge(int) const;
|
||||
|
||||
MeshCore::FacetIndex Index;
|
||||
MeshCore::PointIndex PIndex[3];
|
||||
|
||||
@@ -56,6 +56,13 @@ The two angles are given in radian.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getEdge">
|
||||
<Documentation>
|
||||
<UserDocu>getEdge(int) -> Edge
|
||||
Returns the edge of the facet.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="Index" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>The index of this facet in the MeshObject</UserDocu>
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "Facet.h"
|
||||
#include <Mod/Mesh/App/FacetPy.h>
|
||||
#include <Mod/Mesh/App/FacetPy.cpp>
|
||||
#include <Mod/Mesh/App/EdgePy.h>
|
||||
|
||||
#include <Base/VectorPy.h>
|
||||
#include <Base/GeometryPyCXX.h>
|
||||
@@ -78,6 +79,16 @@ PyObject* FacetPy::unbound(PyObject *args)
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* FacetPy::getEdge(PyObject *args)
|
||||
{
|
||||
int index;
|
||||
if (!PyArg_ParseTuple(args, "i", &index))
|
||||
return nullptr;
|
||||
|
||||
Edge edge = getFacetPtr()->getEdge(index);
|
||||
return new EdgePy(new Edge(edge));
|
||||
}
|
||||
|
||||
Py::Long FacetPy::getIndex() const
|
||||
{
|
||||
return Py::Long((long) getFacetPtr()->Index);
|
||||
@@ -85,7 +96,7 @@ Py::Long FacetPy::getIndex() const
|
||||
|
||||
Py::Boolean FacetPy::getBound() const
|
||||
{
|
||||
return Py::Boolean(getFacetPtr()->Index != UINT_MAX);
|
||||
return Py::Boolean(getFacetPtr()->isBound());
|
||||
}
|
||||
|
||||
Py::Object FacetPy::getNormal() const
|
||||
|
||||
@@ -226,6 +226,59 @@ class MeshGeoTestCases(unittest.TestCase):
|
||||
res=f1.intersect(f2)
|
||||
self.assertTrue(len(res) == 0)
|
||||
|
||||
def testIntersectionOfTransformedMesh(self):
|
||||
self.planarMesh.append( [0.0,10.0,10.0] )
|
||||
self.planarMesh.append( [10.0,0.0,10.0] )
|
||||
self.planarMesh.append( [10.0,10.0,10.0] )
|
||||
self.planarMesh.append( [6.0,8.0,10.0] )
|
||||
self.planarMesh.append( [16.0,8.0,10.0] )
|
||||
self.planarMesh.append( [6.0,18.0,10.0] )
|
||||
planarMeshObject = Mesh.Mesh(self.planarMesh)
|
||||
|
||||
mat = Base.Matrix()
|
||||
mat.rotateX(1.0)
|
||||
mat.rotateY(1.0)
|
||||
mat.rotateZ(1.0)
|
||||
planarMeshObject.transformGeometry(mat)
|
||||
|
||||
f1 = planarMeshObject.Facets[0]
|
||||
f2 = planarMeshObject.Facets[1]
|
||||
res=f1.intersect(f2)
|
||||
self.assertEqual(len(res), 2)
|
||||
|
||||
def testIntersectionOfParallelTriangles(self):
|
||||
self.planarMesh.append( [0.0,10.0,10.0] )
|
||||
self.planarMesh.append( [10.0,0.0,10.0] )
|
||||
self.planarMesh.append( [10.0,10.0,10.0] )
|
||||
self.planarMesh.append( [6.0,8.0,10.1] )
|
||||
self.planarMesh.append( [16.0,8.0,10.1] )
|
||||
self.planarMesh.append( [6.0,18.0,10.1] )
|
||||
planarMeshObject = Mesh.Mesh(self.planarMesh)
|
||||
|
||||
mat = Base.Matrix()
|
||||
mat.rotateX(1.0)
|
||||
mat.rotateY(1.0)
|
||||
mat.rotateZ(1.0)
|
||||
planarMeshObject.transformGeometry(mat)
|
||||
|
||||
f1 = planarMeshObject.Facets[0]
|
||||
f2 = planarMeshObject.Facets[1]
|
||||
res=f1.intersect(f2)
|
||||
self.assertTrue(len(res) == 0)
|
||||
|
||||
def testIntersectionOnEdge(self):
|
||||
self.planarMesh.append( [5.0, -1.9371663331985474, 0.49737977981567383] )
|
||||
self.planarMesh.append( [4.0, -1.9371663331985474, 0.49737977981567383] )
|
||||
self.planarMesh.append( [5.0, -1.9842294454574585, 0.25066646933555603] )
|
||||
self.planarMesh.append( [4.6488823890686035, -1.7827962636947632, 0.4577442705631256] )
|
||||
self.planarMesh.append( [4.524135112762451, -2.0620131492614746, 0.5294350385665894] )
|
||||
self.planarMesh.append( [4.6488823890686035, -1.8261089324951172, 0.23069120943546295] )
|
||||
planarMeshObject = Mesh.Mesh(self.planarMesh)
|
||||
f1 = planarMeshObject.Facets[0]
|
||||
f2 = planarMeshObject.Facets[1]
|
||||
res = f1.intersect(f2)
|
||||
self.assertEqual(len(res), 2)
|
||||
|
||||
def testIntersectionCoplanar(self):
|
||||
self.planarMesh.append( [0.,10.,10.] )
|
||||
self.planarMesh.append( [10.,0.,10.] )
|
||||
@@ -252,6 +305,65 @@ class MeshGeoTestCases(unittest.TestCase):
|
||||
res = f1.intersect(f2)
|
||||
self.assertTrue(len(res) == 2)
|
||||
|
||||
def testIntersectionOfIntersectingEdges(self):
|
||||
self.planarMesh.append( [0.,10.,10.] )
|
||||
self.planarMesh.append( [10.,0.,10.] )
|
||||
self.planarMesh.append( [10.,10.,10.] )
|
||||
self.planarMesh.append( [6.,8.,10.] )
|
||||
self.planarMesh.append( [16.,8.,10.] )
|
||||
self.planarMesh.append( [6.,18.,10.] )
|
||||
planarMeshObject = Mesh.Mesh(self.planarMesh)
|
||||
|
||||
edge1 = planarMeshObject.Facets[0].getEdge(2)
|
||||
edge2 = planarMeshObject.Facets[1].getEdge(2)
|
||||
res = edge1.intersectWithEdge(edge2)
|
||||
self.assertTrue(len(res) == 1)
|
||||
self.assertEqual(res[0][0], 6.0)
|
||||
self.assertEqual(res[0][1], 10.0)
|
||||
self.assertEqual(res[0][2], 10.0)
|
||||
|
||||
def testIntersectionOfParallelEdges(self):
|
||||
self.planarMesh.append( [0.,10.,10.] )
|
||||
self.planarMesh.append( [10.,0.,10.] )
|
||||
self.planarMesh.append( [10.,10.,10.] )
|
||||
self.planarMesh.append( [6.,8.,10.] )
|
||||
self.planarMesh.append( [16.,8.,10.] )
|
||||
self.planarMesh.append( [6.,18.,10.] )
|
||||
planarMeshObject = Mesh.Mesh(self.planarMesh)
|
||||
|
||||
edge1 = planarMeshObject.Facets[0].getEdge(2)
|
||||
edge2 = planarMeshObject.Facets[1].getEdge(0)
|
||||
res = edge1.intersectWithEdge(edge2)
|
||||
self.assertTrue(len(res) == 0)
|
||||
|
||||
def testIntersectionOfCollinearEdges(self):
|
||||
self.planarMesh.append( [0.,0.,0.] )
|
||||
self.planarMesh.append( [6.,0.,0.] )
|
||||
self.planarMesh.append( [3.,4.,0.] )
|
||||
self.planarMesh.append( [7.,0.,0.] )
|
||||
self.planarMesh.append( [13.,0.,0.] )
|
||||
self.planarMesh.append( [10.,4.,0.] )
|
||||
planarMeshObject = Mesh.Mesh(self.planarMesh)
|
||||
|
||||
edge1 = planarMeshObject.Facets[0].getEdge(0)
|
||||
edge2 = planarMeshObject.Facets[1].getEdge(0)
|
||||
res = edge1.intersectWithEdge(edge2)
|
||||
self.assertTrue(len(res) == 0)
|
||||
|
||||
def testIntersectionOfWarpedEdges(self):
|
||||
self.planarMesh.append( [0.,0.,0.] )
|
||||
self.planarMesh.append( [6.,0.,0.] )
|
||||
self.planarMesh.append( [3.,4.,0.] )
|
||||
self.planarMesh.append( [2.,2.,1.] )
|
||||
self.planarMesh.append( [8.,2.,1.] )
|
||||
self.planarMesh.append( [5.,6.,1.] )
|
||||
planarMeshObject = Mesh.Mesh(self.planarMesh)
|
||||
|
||||
edge1 = planarMeshObject.Facets[0].getEdge(1)
|
||||
edge2 = planarMeshObject.Facets[1].getEdge(0)
|
||||
res = edge1.intersectWithEdge(edge2)
|
||||
self.assertTrue(len(res) == 0)
|
||||
|
||||
def testSelfIntersection(self):
|
||||
s = b"""solid Simple
|
||||
facet normal 0.0e0 0.0e0 1.0e1
|
||||
|
||||
@@ -7137,7 +7137,7 @@ bool CmdSketcherConstrainSnellsLaw::isActive(void)
|
||||
DEF_STD_CMD_A(CmdSketcherConstrainInternalAlignment)
|
||||
|
||||
// NOTE: This command is deprecated. Nobody seriously uses today manual creation of an internal alignment constraint
|
||||
// The only reason this code remains is the extremelly unlikely scenario that some user macro may rely on it.
|
||||
// The only reason this code remains is the extremely unlikely scenario that some user macro may rely on it.
|
||||
CmdSketcherConstrainInternalAlignment::CmdSketcherConstrainInternalAlignment()
|
||||
:Command("Sketcher_ConstrainInternalAlignment")
|
||||
{
|
||||
|
||||
@@ -1002,7 +1002,7 @@ void TaskSketcherConstrains::onSelectionChanged(const Gui::SelectionChanges& msg
|
||||
if(geoid != Sketcher::Constraint::GeoUndef && pointpos == Sketcher::none){
|
||||
// It is not possible to update on single addition/removal of a geometric element,
|
||||
// as one removal may imply removing a constraint that should be added by a different element
|
||||
// that is still selected. The necessary checks outweight a full rebuild of the filter.
|
||||
// that is still selected. The necessary checks outweigh a full rebuild of the filter.
|
||||
updateAssociatedConstraintsFilter();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
<height>401</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>400</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
|
||||
@@ -107,6 +107,9 @@ void SketcherValidation::changeEvent(QEvent *e)
|
||||
|
||||
void SketcherValidation::on_findButton_clicked()
|
||||
{
|
||||
if (sketch.expired())
|
||||
return;
|
||||
|
||||
double prec = Precision::Confusion();
|
||||
bool ok;
|
||||
double conv;
|
||||
@@ -150,6 +153,9 @@ void SketcherValidation::on_findButton_clicked()
|
||||
|
||||
void SketcherValidation::on_fixButton_clicked()
|
||||
{
|
||||
if (sketch.expired())
|
||||
return;
|
||||
|
||||
// undo command open
|
||||
App::Document* doc = sketch->getDocument();
|
||||
doc->openTransaction("add coincident constraint");
|
||||
@@ -167,6 +173,9 @@ void SketcherValidation::on_fixButton_clicked()
|
||||
|
||||
void SketcherValidation::on_highlightButton_clicked()
|
||||
{
|
||||
if (sketch.expired())
|
||||
return;
|
||||
|
||||
std::vector<Base::Vector3d> points;
|
||||
|
||||
points = sketchAnalyser.getOpenVertices();
|
||||
@@ -178,6 +187,9 @@ void SketcherValidation::on_highlightButton_clicked()
|
||||
|
||||
void SketcherValidation::on_findConstraint_clicked()
|
||||
{
|
||||
if (sketch.expired())
|
||||
return;
|
||||
|
||||
if (sketch->evaluateConstraints()) {
|
||||
QMessageBox::information(this, tr("No invalid constraints"),
|
||||
tr("No invalid constraints found"));
|
||||
@@ -192,12 +204,18 @@ void SketcherValidation::on_findConstraint_clicked()
|
||||
|
||||
void SketcherValidation::on_fixConstraint_clicked()
|
||||
{
|
||||
if (sketch.expired())
|
||||
return;
|
||||
|
||||
sketch->validateConstraints();
|
||||
ui->fixConstraint->setEnabled(false);
|
||||
}
|
||||
|
||||
void SketcherValidation::on_findReversed_clicked()
|
||||
{
|
||||
if (sketch.expired())
|
||||
return;
|
||||
|
||||
std::vector<Base::Vector3d> points;
|
||||
const std::vector<Part::Geometry *>& geom = sketch->getExternalGeometry();
|
||||
for (std::size_t i=0; i<geom.size(); i++) {
|
||||
@@ -241,6 +259,9 @@ void SketcherValidation::on_findReversed_clicked()
|
||||
|
||||
void SketcherValidation::on_swapReversed_clicked()
|
||||
{
|
||||
if (sketch.expired())
|
||||
return;
|
||||
|
||||
App::Document* doc = sketch->getDocument();
|
||||
doc->openTransaction("Sketch porting");
|
||||
|
||||
@@ -255,6 +276,9 @@ void SketcherValidation::on_swapReversed_clicked()
|
||||
|
||||
void SketcherValidation::on_orientLockEnable_clicked()
|
||||
{
|
||||
if (sketch.expired())
|
||||
return;
|
||||
|
||||
App::Document* doc = sketch->getDocument();
|
||||
doc->openTransaction("Constraint orientation lock");
|
||||
|
||||
@@ -269,6 +293,9 @@ void SketcherValidation::on_orientLockEnable_clicked()
|
||||
|
||||
void SketcherValidation::on_orientLockDisable_clicked()
|
||||
{
|
||||
if (sketch.expired())
|
||||
return;
|
||||
|
||||
App::Document* doc = sketch->getDocument();
|
||||
doc->openTransaction("Constraint orientation unlock");
|
||||
|
||||
@@ -284,6 +311,9 @@ void SketcherValidation::on_orientLockDisable_clicked()
|
||||
|
||||
void SketcherValidation::on_delConstrExtr_clicked()
|
||||
{
|
||||
if (sketch.expired())
|
||||
return;
|
||||
|
||||
int reply;
|
||||
reply = QMessageBox::question(this,
|
||||
tr("Delete constraints to external geom."),
|
||||
@@ -337,21 +367,28 @@ void SketcherValidation::showPoints(const std::vector<Base::Vector3d>& pts)
|
||||
}
|
||||
coords->point.finishEditing();
|
||||
|
||||
Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(sketch);
|
||||
vp->getRoot()->addChild(coincidenceRoot);
|
||||
if (!sketch.expired()) {
|
||||
Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(sketch.get());
|
||||
vp->getRoot()->addChild(coincidenceRoot);
|
||||
}
|
||||
}
|
||||
|
||||
void SketcherValidation::hidePoints()
|
||||
{
|
||||
if (coincidenceRoot) {
|
||||
Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(sketch);
|
||||
vp->getRoot()->removeChild(coincidenceRoot);
|
||||
coincidenceRoot = 0;
|
||||
if (!sketch.expired()) {
|
||||
Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(sketch.get());
|
||||
vp->getRoot()->removeChild(coincidenceRoot);
|
||||
}
|
||||
coincidenceRoot = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void SketcherValidation::on_findDegenerated_clicked()
|
||||
{
|
||||
if (sketch.expired())
|
||||
return;
|
||||
|
||||
double prec = Precision::Confusion();
|
||||
int count = sketchAnalyser.detectDegeneratedGeometries(prec);
|
||||
|
||||
@@ -369,6 +406,9 @@ void SketcherValidation::on_findDegenerated_clicked()
|
||||
|
||||
void SketcherValidation::on_fixDegenerated_clicked()
|
||||
{
|
||||
if (sketch.expired())
|
||||
return;
|
||||
|
||||
// undo command open
|
||||
App::Document* doc = sketch->getDocument();
|
||||
doc->openTransaction("Remove degenerated geometry");
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <Base/Vector3D.h>
|
||||
#include <App/DocumentObserver.h>
|
||||
#include <Gui/TaskView/TaskDialog.h>
|
||||
#include <Mod/Sketcher/App/SketchAnalysis.h>
|
||||
|
||||
@@ -67,7 +68,7 @@ private:
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui_TaskSketcherValidation> ui;
|
||||
Sketcher::SketchObject* sketch;
|
||||
App::WeakPtrT<Sketcher::SketchObject> sketch;
|
||||
Sketcher::SketchAnalysis sketchAnalyser;
|
||||
SoGroup* coincidenceRoot;
|
||||
};
|
||||
|
||||
@@ -3193,7 +3193,7 @@ QString ViewProviderSketch::getPresentationString(const Constraint *constraint)
|
||||
// Hide units if user has requested it, is being displayed in the base
|
||||
// units, and the schema being used has a clear base unit in the first
|
||||
// place. Otherwise, display units.
|
||||
if( iHideUnits )
|
||||
if( iHideUnits && constraint->Type != Sketcher::Angle )
|
||||
{
|
||||
// Only hide the default length unit. Right now there is not an easy way
|
||||
// to get that from the Unit system so we have to manually add it here.
|
||||
@@ -5766,7 +5766,7 @@ Restart:
|
||||
break;
|
||||
|
||||
SoDatumLabel *asciiText = static_cast<SoDatumLabel *>(sep->getChild(CONSTRAINT_SEPARATOR_INDEX_MATERIAL_OR_DATUMLABEL));
|
||||
asciiText->string = SbString(Constr->getPresentationValue().getUserString().toUtf8().constData());
|
||||
asciiText->string = SbString( getPresentationString(Constr).toUtf8().constData() );
|
||||
asciiText->datumtype = SoDatumLabel::ANGLE;
|
||||
asciiText->param1 = Constr->LabelDistance;
|
||||
asciiText->param2 = startangle;
|
||||
|
||||
@@ -176,7 +176,7 @@
|
||||
recomputeCells(from, to=None)
|
||||
|
||||
Manually recompute cells in the given range with the given order without
|
||||
following depedency order.
|
||||
following dependency order.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
|
||||
@@ -298,6 +298,7 @@ App::DocumentObjectExecReturn *Filling::execute(void)
|
||||
}
|
||||
|
||||
// Add the constraints of border curves/faces (bound)
|
||||
int numBoundaries = BoundaryEdges.getSize();
|
||||
addConstraints(builder, BoundaryEdges, BoundaryFaces, BoundaryOrder, Standard_True);
|
||||
|
||||
// Add additional edge constraints if available (unbound)
|
||||
@@ -316,7 +317,8 @@ App::DocumentObjectExecReturn *Filling::execute(void)
|
||||
}
|
||||
|
||||
//Build the face
|
||||
builder.Build();
|
||||
if (numBoundaries > 1)
|
||||
builder.Build();
|
||||
if (!builder.IsDone()) {
|
||||
Standard_Failure::Raise("Failed to create a face from constraints");
|
||||
}
|
||||
@@ -327,7 +329,6 @@ App::DocumentObjectExecReturn *Filling::execute(void)
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
|
||||
return new App::DocumentObjectExecReturn(e.GetMessageString());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user