Create outline of 3D shape
This commit is contained in:
parent
06e8c6734d
commit
dc66106683
|
@ -38,6 +38,8 @@
|
|||
#include <Base/PyObjectBase.h>
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/GeometryPyCXX.h>
|
||||
#include <Base/Vector3D.h>
|
||||
#include <Base/VectorPy.h>
|
||||
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
#include <Mod/Part/App/TopoShapePy.h>
|
||||
|
@ -46,8 +48,10 @@
|
|||
|
||||
#include <Mod/Part/App/OCCError.h>
|
||||
|
||||
#include "DrawProjectSplit.h"
|
||||
#include "EdgeWalker.h"
|
||||
|
||||
|
||||
namespace TechDraw {
|
||||
//module level static C++ functions go here
|
||||
}
|
||||
|
@ -70,6 +74,9 @@ public:
|
|||
add_varargs_method("findOuterWire",&Module::findOuterWire,
|
||||
"wire = findOuterWire(edgeList) -- Planar graph traversal finds OuterWire in edge pile."
|
||||
);
|
||||
add_varargs_method("findShapeOutline",&Module::findShapeOutline,
|
||||
"wire = findShapeOutline(shape,scale,direction) -- Project shape in direction and find outer wire of result."
|
||||
);
|
||||
initialize("This is a module for making drawings"); // register with Python
|
||||
}
|
||||
virtual ~Module() {}
|
||||
|
@ -219,6 +226,62 @@ private:
|
|||
}
|
||||
return Py::asObject(outerWire);
|
||||
}
|
||||
|
||||
Py::Object findShapeOutline(const Py::Tuple& args)
|
||||
{
|
||||
PyObject *pcObjShape;
|
||||
double scale;
|
||||
PyObject *pcObjDir;
|
||||
if (!PyArg_ParseTuple(args.ptr(), "OdO", &pcObjShape,
|
||||
&scale,
|
||||
&pcObjDir)) {
|
||||
throw Py::Exception();
|
||||
}
|
||||
|
||||
TopoShapePy* pShape = static_cast<TopoShapePy*>(pcObjShape);
|
||||
if (!pShape) {
|
||||
Base::Console().Message("TRACE - AATDP::findShapeOutline - input shape is null\n");
|
||||
return Py::None();
|
||||
}
|
||||
|
||||
const TopoDS_Shape& shape = pShape->getTopoShapePtr()->getShape();
|
||||
Base::Vector3d dir = static_cast<Base::VectorPy*>(pcObjDir)->value();
|
||||
std::vector<TopoDS_Edge> edgeList;
|
||||
try {
|
||||
edgeList = DrawProjectSplit::getEdgesForWalker(shape,scale,dir);
|
||||
}
|
||||
catch (Standard_Failure) {
|
||||
Handle_Standard_Failure e = Standard_Failure::Caught();
|
||||
throw Py::Exception(Part::PartExceptionOCCError, e->GetMessageString());
|
||||
}
|
||||
|
||||
if (edgeList.empty()) {
|
||||
Base::Console().Log("LOG - ATDP::findShapeOutline: input is empty\n");
|
||||
return Py::None();
|
||||
}
|
||||
|
||||
PyObject* outerWire = nullptr;
|
||||
bool success = false;
|
||||
try {
|
||||
EdgeWalker ew;
|
||||
ew.loadEdges(edgeList);
|
||||
success = ew.perform();
|
||||
if (success) {
|
||||
std::vector<TopoDS_Wire> rw = ew.getResultNoDups();
|
||||
std::vector<TopoDS_Wire> sortedWires = ew.sortStrip(rw,true);
|
||||
outerWire = new TopoShapeWirePy(new TopoShape(*sortedWires.begin()));
|
||||
} else {
|
||||
Base::Console().Warning("ATDP::findShapeOutline: input is not planar graph. Wire detection not done\n");
|
||||
}
|
||||
}
|
||||
catch (Base::Exception &e) {
|
||||
throw Py::Exception(Base::BaseExceptionFreeCADError, e.what());
|
||||
}
|
||||
if (!success) {
|
||||
return Py::None();
|
||||
}
|
||||
return Py::asObject(outerWire);
|
||||
}
|
||||
};
|
||||
|
||||
PyObject* initModule()
|
||||
|
|
|
@ -90,6 +90,8 @@ SET(TechDraw_SRCS
|
|||
PreCompiled.h
|
||||
EdgeWalker.cpp
|
||||
EdgeWalker.h
|
||||
DrawProjectSplit.cpp
|
||||
DrawProjectSplit.h
|
||||
)
|
||||
|
||||
SET(Geometry_SRCS
|
||||
|
|
428
src/Mod/TechDraw/App/DrawProjectSplit.cpp
Normal file
428
src/Mod/TechDraw/App/DrawProjectSplit.cpp
Normal file
|
@ -0,0 +1,428 @@
|
|||
/***************************************************************************
|
||||
* Copyright (c) WandererFan (wandererfan@gmail.com) 2016 *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <sstream>
|
||||
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepGProp.hxx>
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <BRepBuilderAPI_Copy.hxx>
|
||||
#include <BRepLProp_CurveTool.hxx>
|
||||
#include <BRepLProp_CLProps.hxx>
|
||||
#include <BRepExtrema_DistShapeShape.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRepBndLib.hxx>
|
||||
#include <Bnd_Box.hxx>
|
||||
#include <Geom_Curve.hxx>
|
||||
#include <GeomAPI_ProjectPointOnCurve.hxx>
|
||||
#include <GProp_GProps.hxx>
|
||||
#include <gp_Ax2.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <gp_XYZ.hxx>
|
||||
#include <HLRBRep_Algo.hxx>
|
||||
#include <HLRAlgo_Projector.hxx>
|
||||
#include <HLRBRep_ShapeBounds.hxx>
|
||||
#include <HLRBRep_HLRToShape.hxx>
|
||||
#include <ShapeFix_ShapeTolerance.hxx>
|
||||
#include <ShapeExtend_WireData.hxx>
|
||||
#include <ShapeFix_Wire.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopExp.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopTools_IndexedMapOfShape.hxx>
|
||||
|
||||
#endif
|
||||
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <GeomLib_Tool.hxx>
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <Base/BoundBox.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/FileInfo.h>
|
||||
#include <Base/Parameter.h>
|
||||
#include <Mod/Part/App/PartFeature.h>
|
||||
|
||||
#include "DrawUtil.h"
|
||||
#include "Geometry.h"
|
||||
#include "GeometryObject.h"
|
||||
#include "DrawProjectSplit.h"
|
||||
#include "DrawHatch.h"
|
||||
#include "EdgeWalker.h"
|
||||
|
||||
|
||||
//#include <Mod/TechDraw/App/DrawProjectSplitPy.h> // generated from DrawProjectSplitPy.xml
|
||||
|
||||
using namespace TechDraw;
|
||||
using namespace std;
|
||||
|
||||
|
||||
//===========================================================================
|
||||
// DrawProjectSplit
|
||||
//===========================================================================
|
||||
|
||||
DrawProjectSplit::DrawProjectSplit()
|
||||
{
|
||||
}
|
||||
|
||||
DrawProjectSplit::~DrawProjectSplit()
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<TopoDS_Edge> DrawProjectSplit::getEdgesForWalker(TopoDS_Shape shape, double scale, Base::Vector3d direction)
|
||||
{
|
||||
std::vector<TopoDS_Edge> result;
|
||||
if (shape.IsNull()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_Copy BuilderCopy(shape);
|
||||
TopoDS_Shape copyShape = BuilderCopy.Shape();
|
||||
|
||||
gp_Pnt inputCenter(0,0,0);
|
||||
TopoDS_Shape scaledShape;
|
||||
scaledShape = TechDrawGeometry::scaleShape(copyShape,
|
||||
scale);
|
||||
TechDrawGeometry::GeometryObject* go = buildGeometryObject(scaledShape,inputCenter,direction);
|
||||
result = getEdges(go);
|
||||
|
||||
delete go;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
TechDrawGeometry::GeometryObject* DrawProjectSplit::buildGeometryObject(
|
||||
TopoDS_Shape shape,
|
||||
gp_Pnt& inputCenter,
|
||||
Base::Vector3d direction)
|
||||
{
|
||||
TechDrawGeometry::GeometryObject* geometryObject = new TechDrawGeometry::GeometryObject("DrawProjectSplit");
|
||||
|
||||
geometryObject->projectShape(shape,
|
||||
inputCenter,
|
||||
direction);
|
||||
geometryObject->extractGeometry(TechDrawGeometry::ecHARD, //always show the hard&outline visible lines
|
||||
true);
|
||||
geometryObject->extractGeometry(TechDrawGeometry::ecOUTLINE,
|
||||
true);
|
||||
return geometryObject;
|
||||
}
|
||||
|
||||
//! get the projected edges with all their new intersections.
|
||||
std::vector<TopoDS_Edge> DrawProjectSplit::getEdges(TechDrawGeometry::GeometryObject* geometryObject)
|
||||
{
|
||||
const std::vector<TechDrawGeometry::BaseGeom*>& goEdges = geometryObject->getVisibleFaceEdges(true,true);
|
||||
std::vector<TechDrawGeometry::BaseGeom*>::const_iterator itEdge = goEdges.begin();
|
||||
std::vector<TopoDS_Edge> origEdges;
|
||||
for (;itEdge != goEdges.end(); itEdge++) {
|
||||
origEdges.push_back((*itEdge)->occEdge);
|
||||
}
|
||||
|
||||
std::vector<TopoDS_Edge> faceEdges;
|
||||
std::vector<TopoDS_Edge> nonZero;
|
||||
for (auto& e:origEdges) { //drop any zero edges (shouldn't be any by now!!!)
|
||||
if (!DrawUtil::isZeroEdge(e)) {
|
||||
nonZero.push_back(e);
|
||||
} else {
|
||||
Base::Console().Message("INFO - DPS::extractFaces found ZeroEdge!\n");
|
||||
}
|
||||
}
|
||||
faceEdges = nonZero;
|
||||
origEdges = nonZero;
|
||||
|
||||
//HLR algo does not provide all edge intersections for edge endpoints.
|
||||
//need to split long edges touched by Vertex of another edge
|
||||
std::vector<splitPoint> splits;
|
||||
std::vector<TopoDS_Edge>::iterator itOuter = origEdges.begin();
|
||||
int iOuter = 0;
|
||||
for (; itOuter != origEdges.end(); itOuter++, iOuter++) {
|
||||
TopoDS_Vertex v1 = TopExp::FirstVertex((*itOuter));
|
||||
TopoDS_Vertex v2 = TopExp::LastVertex((*itOuter));
|
||||
Bnd_Box sOuter;
|
||||
BRepBndLib::Add(*itOuter, sOuter);
|
||||
sOuter.SetGap(0.1);
|
||||
if (sOuter.IsVoid()) {
|
||||
Base::Console().Message("DPS::Extract Faces - outer Bnd_Box is void\n");
|
||||
continue;
|
||||
}
|
||||
if (DrawUtil::isZeroEdge(*itOuter)) {
|
||||
Base::Console().Message("DPS::extractFaces - outerEdge: %d is ZeroEdge\n",iOuter); //this is not finding ZeroEdges
|
||||
continue; //skip zero length edges. shouldn't happen ;)
|
||||
}
|
||||
int iInner = 0;
|
||||
std::vector<TopoDS_Edge>::iterator itInner = faceEdges.begin();
|
||||
for (; itInner != faceEdges.end(); itInner++,iInner++) {
|
||||
if (iInner == iOuter) {
|
||||
continue;
|
||||
}
|
||||
if (DrawUtil::isZeroEdge((*itInner))) {
|
||||
continue; //skip zero length edges. shouldn't happen ;)
|
||||
}
|
||||
|
||||
Bnd_Box sInner;
|
||||
BRepBndLib::Add(*itInner, sInner);
|
||||
sInner.SetGap(0.1);
|
||||
if (sInner.IsVoid()) {
|
||||
Base::Console().Log("INFO - DPS::Extract Faces - inner Bnd_Box is void\n");
|
||||
continue;
|
||||
}
|
||||
if (sOuter.IsOut(sInner)) { //bboxes of edges don't intersect, don't bother
|
||||
continue;
|
||||
}
|
||||
|
||||
double param = -1;
|
||||
if (isOnEdge((*itInner),v1,param,false)) {
|
||||
gp_Pnt pnt1 = BRep_Tool::Pnt(v1);
|
||||
splitPoint s1;
|
||||
s1.i = iInner;
|
||||
s1.v = Base::Vector3d(pnt1.X(),pnt1.Y(),pnt1.Z());
|
||||
s1.param = param;
|
||||
splits.push_back(s1);
|
||||
}
|
||||
if (isOnEdge((*itInner),v2,param,false)) {
|
||||
gp_Pnt pnt2 = BRep_Tool::Pnt(v2);
|
||||
splitPoint s2;
|
||||
s2.i = iInner;
|
||||
s2.v = Base::Vector3d(pnt2.X(),pnt2.Y(),pnt2.Z());
|
||||
s2.param = param;
|
||||
splits.push_back(s2);
|
||||
}
|
||||
} //inner loop
|
||||
} //outer loop
|
||||
|
||||
std::vector<splitPoint> sorted = sortSplits(splits,true);
|
||||
auto last = std::unique(sorted.begin(), sorted.end(), DrawProjectSplit::splitEqual); //duplicates to back
|
||||
sorted.erase(last, sorted.end()); //remove dupls
|
||||
std::vector<TopoDS_Edge> newEdges = splitEdges(faceEdges,sorted);
|
||||
|
||||
if (newEdges.empty()) {
|
||||
Base::Console().Log("LOG - DPS::extractFaces - no newEdges\n");
|
||||
}
|
||||
return newEdges;
|
||||
}
|
||||
|
||||
|
||||
double DrawProjectSplit::simpleMinDist(TopoDS_Shape s1, TopoDS_Shape s2)
|
||||
{
|
||||
Standard_Real minDist = -1;
|
||||
|
||||
BRepExtrema_DistShapeShape extss(s1, s2);
|
||||
if (!extss.IsDone()) {
|
||||
Base::Console().Message("FE - BRepExtrema_DistShapeShape failed");
|
||||
return -1;
|
||||
}
|
||||
int count = extss.NbSolution();
|
||||
if (count != 0) {
|
||||
minDist = extss.Value();
|
||||
} else {
|
||||
minDist = -1;
|
||||
}
|
||||
return minDist;
|
||||
}
|
||||
|
||||
|
||||
//this routine is the big time consumer. gets called many times (and is slow?))
|
||||
//note param gets modified here
|
||||
bool DrawProjectSplit::isOnEdge(TopoDS_Edge e, TopoDS_Vertex v, double& param, bool allowEnds)
|
||||
{
|
||||
bool result = false;
|
||||
bool outOfBox = false;
|
||||
param = -2;
|
||||
|
||||
//eliminate obvious cases
|
||||
Bnd_Box sBox;
|
||||
BRepBndLib::Add(e, sBox);
|
||||
sBox.SetGap(0.1);
|
||||
if (sBox.IsVoid()) {
|
||||
Base::Console().Message("DPS::isOnEdge - Bnd_Box is void\n");
|
||||
} else {
|
||||
gp_Pnt pt = BRep_Tool::Pnt(v);
|
||||
if (sBox.IsOut(pt)) {
|
||||
outOfBox = true;
|
||||
}
|
||||
}
|
||||
if (!outOfBox) {
|
||||
double dist = simpleMinDist(v,e);
|
||||
if (dist < 0.0) {
|
||||
Base::Console().Error("DPS::isOnEdge - simpleMinDist failed: %.3f\n",dist);
|
||||
result = false;
|
||||
} else if (dist < Precision::Confusion()) {
|
||||
const gp_Pnt pt = BRep_Tool::Pnt(v); //have to duplicate method 3 to get param
|
||||
BRepAdaptor_Curve adapt(e);
|
||||
const Handle_Geom_Curve c = adapt.Curve().Curve();
|
||||
double maxDist = 0.000001; //magic number. less than this gives false positives.
|
||||
//bool found =
|
||||
(void) GeomLib_Tool::Parameter(c,pt,maxDist,param); //already know point it on curve
|
||||
result = true;
|
||||
}
|
||||
if (result) {
|
||||
TopoDS_Vertex v1 = TopExp::FirstVertex(e);
|
||||
TopoDS_Vertex v2 = TopExp::LastVertex(e);
|
||||
if (DrawUtil::isSamePoint(v,v1) || DrawUtil::isSamePoint(v,v2)) {
|
||||
if (!allowEnds) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} //!outofbox
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::vector<TopoDS_Edge> DrawProjectSplit::splitEdges(std::vector<TopoDS_Edge> edges, std::vector<splitPoint> splits)
|
||||
{
|
||||
std::vector<TopoDS_Edge> result;
|
||||
std::vector<TopoDS_Edge> newEdges;
|
||||
std::vector<splitPoint> edgeSplits; //splits for current edge
|
||||
int iEdge = 0; //current edge index
|
||||
int iSplit = 0; //current splitindex
|
||||
int ii = 0; //i value of current split
|
||||
int endEdge = edges.size();
|
||||
int endSplit = splits.size();
|
||||
int imax = std::numeric_limits<int>::max();
|
||||
|
||||
while ((iEdge < endEdge) ) {
|
||||
if (iSplit < endSplit) {
|
||||
ii = splits[iSplit].i;
|
||||
} else {
|
||||
ii = imax;
|
||||
}
|
||||
if (ii == iEdge) {
|
||||
edgeSplits.push_back(splits[iSplit]);
|
||||
iSplit++;
|
||||
} else if (ii > iEdge) {
|
||||
if (!edgeSplits.empty()) { //save *iedge's splits
|
||||
newEdges = split1Edge(edges[iEdge],edgeSplits);
|
||||
result.insert(result.end(), newEdges.begin(), newEdges.end());
|
||||
edgeSplits.clear();
|
||||
} else {
|
||||
result.push_back(edges[iEdge]); //save *iedge
|
||||
}
|
||||
iEdge++; //next edge
|
||||
} else if (iEdge > ii) {
|
||||
iSplit++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!edgeSplits.empty()) { //handle last batch
|
||||
newEdges = split1Edge(edges[iEdge],edgeSplits);
|
||||
result.insert(result.end(), newEdges.begin(), newEdges.end());
|
||||
edgeSplits.clear();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::vector<TopoDS_Edge> DrawProjectSplit::split1Edge(TopoDS_Edge e, std::vector<splitPoint> splits)
|
||||
{
|
||||
std::vector<TopoDS_Edge> result;
|
||||
if (splits.empty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
BRepAdaptor_Curve adapt(e);
|
||||
Handle_Geom_Curve c = adapt.Curve().Curve();
|
||||
double first = BRepLProp_CurveTool::FirstParameter(adapt);
|
||||
double last = BRepLProp_CurveTool::LastParameter(adapt);
|
||||
if (first > last) {
|
||||
//TODO parms.reverse();
|
||||
Base::Console().Message("DPS::split1Edge - edge is backwards!\n");
|
||||
return result;
|
||||
}
|
||||
std::vector<double> parms;
|
||||
parms.push_back(first);
|
||||
for (auto& s:splits) {
|
||||
parms.push_back(s.param);
|
||||
}
|
||||
|
||||
parms.push_back(last);
|
||||
std::vector<double>::iterator pfirst = parms.begin();
|
||||
auto parms2 = parms.begin() + 1;
|
||||
std::vector<double>::iterator psecond = parms2;
|
||||
std::vector<double>::iterator pstop = parms.end();
|
||||
for (; psecond != pstop; pfirst++,psecond++) {
|
||||
try {
|
||||
BRepBuilderAPI_MakeEdge mkEdge(c, *pfirst, *psecond);
|
||||
if (mkEdge.IsDone()) {
|
||||
TopoDS_Edge e1 = mkEdge.Edge();
|
||||
result.push_back(e1);
|
||||
}
|
||||
}
|
||||
catch (Standard_Failure) {
|
||||
Base::Console().Message("LOG - DPS::split1Edge failed building edge segment\n");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<splitPoint> DrawProjectSplit::sortSplits(std::vector<splitPoint>& s, bool ascend)
|
||||
{
|
||||
std::vector<splitPoint> sorted = s;
|
||||
std::sort(sorted.begin(), sorted.end(), DrawProjectSplit::splitCompare);
|
||||
if (ascend) {
|
||||
std::reverse(sorted.begin(),sorted.end());
|
||||
}
|
||||
return sorted;
|
||||
}
|
||||
|
||||
//return true if p1 "is greater than" p2
|
||||
/*static*/bool DrawProjectSplit::splitCompare(const splitPoint& p1, const splitPoint& p2)
|
||||
{
|
||||
bool result = false;
|
||||
if (p1.i > p2.i) {
|
||||
result = true;
|
||||
} else if (p1.i < p2.i) {
|
||||
result = false;
|
||||
} else if (p1.param > p2.param) {
|
||||
result = true;
|
||||
} else if (p1.param < p2.param) {
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//return true if p1 "is equal to" p2
|
||||
/*static*/bool DrawProjectSplit::splitEqual(const splitPoint& p1, const splitPoint& p2)
|
||||
{
|
||||
bool result = false;
|
||||
if ((p1.i == p2.i) &&
|
||||
(fabs(p1.param - p2.param) < Precision::Confusion())) {
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
86
src/Mod/TechDraw/App/DrawProjectSplit.h
Normal file
86
src/Mod/TechDraw/App/DrawProjectSplit.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
/***************************************************************************
|
||||
* Copyright (c) WandererFan (wandererfan@gmail.com) 2016 *
|
||||
* *
|
||||
* 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 _DrawProjectSplit_h_
|
||||
#define _DrawProjectSplit_h_
|
||||
|
||||
|
||||
#include <TopoDS_Edge.hxx>
|
||||
#include <TopoDS_Vertex.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
|
||||
#include <App/DocumentObject.h>
|
||||
#include <App/PropertyLinks.h>
|
||||
#include <App/PropertyStandard.h>
|
||||
#include <App/FeaturePython.h>
|
||||
#include <Base/Vector3D.h>
|
||||
#include <Base/BoundBox.h>
|
||||
|
||||
class gp_Pnt;
|
||||
|
||||
namespace TechDrawGeometry
|
||||
{
|
||||
class GeometryObject;
|
||||
class Vertex;
|
||||
class BaseGeom;
|
||||
}
|
||||
|
||||
namespace TechDraw
|
||||
{
|
||||
struct splitPoint {
|
||||
int i;
|
||||
Base::Vector3d v;
|
||||
double param;
|
||||
};
|
||||
|
||||
class TechDrawExport DrawProjectSplit
|
||||
{
|
||||
public:
|
||||
DrawProjectSplit();
|
||||
~DrawProjectSplit();
|
||||
|
||||
public:
|
||||
static std::vector<TopoDS_Edge> getEdgesForWalker(TopoDS_Shape shape, double scale, Base::Vector3d direction);
|
||||
static TechDrawGeometry::GeometryObject* buildGeometryObject(TopoDS_Shape shape, gp_Pnt& center, Base::Vector3d direction);
|
||||
|
||||
static bool isOnEdge(TopoDS_Edge e, TopoDS_Vertex v, double& param, bool allowEnds = false);
|
||||
static std::vector<TopoDS_Edge> splitEdges(std::vector<TopoDS_Edge> orig, std::vector<splitPoint> splits);
|
||||
static std::vector<TopoDS_Edge> split1Edge(TopoDS_Edge e, std::vector<splitPoint> splitPoints);
|
||||
static double simpleMinDist(TopoDS_Shape s1, TopoDS_Shape s2); //const; //probably sb static or DrawUtil
|
||||
|
||||
static std::vector<splitPoint> sortSplits(std::vector<splitPoint>& s, bool ascend);
|
||||
static bool splitCompare(const splitPoint& p1, const splitPoint& p2);
|
||||
static bool splitEqual(const splitPoint& p1, const splitPoint& p2);
|
||||
|
||||
protected:
|
||||
static std::vector<TopoDS_Edge> getEdges(TechDrawGeometry::GeometryObject* geometryObject);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
typedef App::FeaturePythonT<DrawProjectSplit> DrawProjectSplitPython;
|
||||
|
||||
} //namespace TechDraw
|
||||
|
||||
#endif // #ifndef _DrawProjectSplit_h_
|
|
@ -118,7 +118,6 @@ void DrawViewCollection::rebuildViewList()
|
|||
|
||||
short DrawViewCollection::mustExecute() const
|
||||
{
|
||||
// If Tolerance Property is touched
|
||||
if (Views.isTouched() ||
|
||||
Source.isTouched()) {
|
||||
return 1;
|
||||
|
|
|
@ -95,7 +95,6 @@ using namespace std;
|
|||
// DrawViewPart
|
||||
//===========================================================================
|
||||
|
||||
App::PropertyFloatConstraint::Constraints DrawViewPart::floatRange = {0.01f,5.0f,0.05f};
|
||||
|
||||
PROPERTY_SOURCE(TechDraw::DrawViewPart, TechDraw::DrawView)
|
||||
|
||||
|
@ -108,17 +107,13 @@ DrawViewPart::DrawViewPart(void) : geometryObject(0)
|
|||
//properties that affect Geometry
|
||||
ADD_PROPERTY_TYPE(Source ,(0),group,App::Prop_None,"3D Shape to view");
|
||||
ADD_PROPERTY_TYPE(Direction ,(0,0,1.0) ,group,App::Prop_None,"Projection direction. The direction you are looking from.");
|
||||
// ADD_PROPERTY_TYPE(XAxisDirection ,(1,0,0) ,group,App::Prop_None,"Where to place projection's XAxis (rotation)");
|
||||
ADD_PROPERTY_TYPE(Tolerance,(0.05f),group,App::Prop_None,"Internal tolerance for calculations");
|
||||
Tolerance.setConstraints(&floatRange);
|
||||
|
||||
//properties that affect Appearance
|
||||
//visible outline
|
||||
ADD_PROPERTY_TYPE(SmoothVisible ,(false),sgroup,App::Prop_None,"Visible Smooth lines on/off");
|
||||
ADD_PROPERTY_TYPE(SeamVisible ,(false),sgroup,App::Prop_None,"Visible Seam lines on/off");
|
||||
ADD_PROPERTY_TYPE(IsoVisible ,(false),sgroup,App::Prop_None,"Visible Iso u,v lines on/off");
|
||||
ADD_PROPERTY_TYPE(HardHidden ,(false),sgroup,App::Prop_None,"Hidden Hard lines on/off"); // and outline
|
||||
//hidden outline
|
||||
ADD_PROPERTY_TYPE(HardHidden ,(false),sgroup,App::Prop_None,"Hidden Hard lines on/off");
|
||||
ADD_PROPERTY_TYPE(SmoothHidden ,(false),sgroup,App::Prop_None,"Hidden Smooth lines on/off");
|
||||
ADD_PROPERTY_TYPE(SeamHidden ,(false),sgroup,App::Prop_None,"Hidden Seam lines on/off");
|
||||
ADD_PROPERTY_TYPE(IsoHidden ,(false),sgroup,App::Prop_None,"Hidden Iso u,v lines on/off");
|
||||
|
@ -135,7 +130,7 @@ DrawViewPart::DrawViewPart(void) : geometryObject(0)
|
|||
//properties that affect Section Line
|
||||
ADD_PROPERTY_TYPE(ShowSectionLine ,(true) ,sgroup,App::Prop_None,"Show/hide section line if applicable");
|
||||
|
||||
geometryObject = new TechDrawGeometry::GeometryObject(this);
|
||||
geometryObject = nullptr;
|
||||
getRunControl();
|
||||
|
||||
}
|
||||
|
@ -162,47 +157,20 @@ App::DocumentObjectExecReturn *DrawViewPart::execute(void)
|
|||
return new App::DocumentObjectExecReturn("FVP - Linked shape object is empty");
|
||||
}
|
||||
|
||||
//Base::Console().Message("TRACE - DVP::execute - %s/%s ScaleType: %s\n",getNameInDocument(),Label.getValue(),ScaleType.getValueAsString());
|
||||
|
||||
(void) DrawView::execute(); //make sure Scale is up to date
|
||||
|
||||
geometryObject->setTolerance(Tolerance.getValue());
|
||||
geometryObject->setScale(Scale.getValue());
|
||||
|
||||
//TODO: remove these try/catch block when code is stable
|
||||
gp_Pnt inputCenter;
|
||||
try {
|
||||
inputCenter = TechDrawGeometry::findCentroid(shape,
|
||||
Direction.getValue());
|
||||
shapeCentroid = Base::Vector3d(inputCenter.X(),inputCenter.Y(),inputCenter.Z());
|
||||
}
|
||||
catch (Standard_Failure) {
|
||||
Handle_Standard_Failure e1 = Standard_Failure::Caught();
|
||||
Base::Console().Log("LOG - DVP::execute - findCentroid failed for %s - %s **\n",getNameInDocument(),e1->GetMessageString());
|
||||
return new App::DocumentObjectExecReturn(e1->GetMessageString());
|
||||
}
|
||||
inputCenter = TechDrawGeometry::findCentroid(shape,
|
||||
Direction.getValue());
|
||||
shapeCentroid = Base::Vector3d(inputCenter.X(),inputCenter.Y(),inputCenter.Z());
|
||||
|
||||
TopoDS_Shape mirroredShape;
|
||||
try {
|
||||
mirroredShape = TechDrawGeometry::mirrorShape(shape,
|
||||
inputCenter,
|
||||
Scale.getValue());
|
||||
}
|
||||
catch (Standard_Failure) {
|
||||
Handle_Standard_Failure e2 = Standard_Failure::Caught();
|
||||
Base::Console().Log("LOG - DVP::execute - mirrorShape failed for %s - %s **\n",getNameInDocument(),e2->GetMessageString());
|
||||
return new App::DocumentObjectExecReturn(e2->GetMessageString());
|
||||
}
|
||||
mirroredShape = TechDrawGeometry::mirrorShape(shape,
|
||||
inputCenter,
|
||||
Scale.getValue());
|
||||
|
||||
try {
|
||||
geometryObject->setIsoCount(IsoCount.getValue());
|
||||
buildGeometryObject(mirroredShape,inputCenter);
|
||||
}
|
||||
catch (Standard_Failure) {
|
||||
Handle_Standard_Failure e3 = Standard_Failure::Caught();
|
||||
Base::Console().Log("LOG - DVP::execute - buildGeometryObject failed for %s - %s **\n",getNameInDocument(),e3->GetMessageString());
|
||||
return new App::DocumentObjectExecReturn(e3->GetMessageString());
|
||||
}
|
||||
geometryObject = buildGeometryObject(mirroredShape,inputCenter);
|
||||
|
||||
#if MOD_TECHDRAW_HANDLE_FACES
|
||||
if (handleFaces()) {
|
||||
|
@ -238,64 +206,68 @@ short DrawViewPart::mustExecute() const
|
|||
|
||||
void DrawViewPart::onChanged(const App::Property* prop)
|
||||
{
|
||||
//Base::Console().Message("TRACE - DVP::onChanged(%s) - %s\n",prop->getName(),Label.getValue());
|
||||
|
||||
DrawView::onChanged(prop);
|
||||
|
||||
//TODO: when scale changes, any Dimensions for this View sb recalculated. DVD should pick this up subject to topological naming issues.
|
||||
}
|
||||
|
||||
void DrawViewPart::buildGeometryObject(TopoDS_Shape shape, gp_Pnt& inputCenter)
|
||||
//note: slightly different than routine with same name in DrawProjectSplit
|
||||
TechDrawGeometry::GeometryObject* DrawViewPart::buildGeometryObject(TopoDS_Shape shape, gp_Pnt& inputCenter)
|
||||
{
|
||||
Base::Vector3d baseProjDir = Direction.getValue();
|
||||
TechDrawGeometry::GeometryObject* go = new TechDrawGeometry::GeometryObject(getNameInDocument());
|
||||
go->setIsoCount(IsoCount.getValue());
|
||||
|
||||
Base::Vector3d baseProjDir = Direction.getValue();
|
||||
saveParamSpace(baseProjDir);
|
||||
|
||||
geometryObject->projectShape(shape,
|
||||
inputCenter,
|
||||
Direction.getValue());
|
||||
geometryObject->extractGeometry(TechDrawGeometry::ecHARD, //always show the hard&outline visible lines
|
||||
true);
|
||||
geometryObject->extractGeometry(TechDrawGeometry::ecOUTLINE,
|
||||
true);
|
||||
go->projectShape(shape,
|
||||
inputCenter,
|
||||
Direction.getValue());
|
||||
go->extractGeometry(TechDrawGeometry::ecHARD, //always show the hard&outline visible lines
|
||||
true);
|
||||
go->extractGeometry(TechDrawGeometry::ecOUTLINE,
|
||||
true);
|
||||
if (SmoothVisible.getValue()) {
|
||||
geometryObject->extractGeometry(TechDrawGeometry::ecSMOOTH,
|
||||
true);
|
||||
go->extractGeometry(TechDrawGeometry::ecSMOOTH,
|
||||
true);
|
||||
}
|
||||
if (SeamVisible.getValue()) {
|
||||
geometryObject->extractGeometry(TechDrawGeometry::ecSEAM,
|
||||
true);
|
||||
go->extractGeometry(TechDrawGeometry::ecSEAM,
|
||||
true);
|
||||
}
|
||||
if ((IsoVisible.getValue()) && (IsoCount.getValue() > 0)) {
|
||||
geometryObject->extractGeometry(TechDrawGeometry::ecUVISO,
|
||||
true);
|
||||
go->extractGeometry(TechDrawGeometry::ecUVISO,
|
||||
true);
|
||||
}
|
||||
if (HardHidden.getValue()) {
|
||||
geometryObject->extractGeometry(TechDrawGeometry::ecHARD,
|
||||
false);
|
||||
geometryObject->extractGeometry(TechDrawGeometry::ecOUTLINE,
|
||||
false);
|
||||
go->extractGeometry(TechDrawGeometry::ecHARD,
|
||||
false);
|
||||
go->extractGeometry(TechDrawGeometry::ecOUTLINE,
|
||||
false);
|
||||
}
|
||||
if (SmoothHidden.getValue()) {
|
||||
geometryObject->extractGeometry(TechDrawGeometry::ecSMOOTH,
|
||||
false);
|
||||
go->extractGeometry(TechDrawGeometry::ecSMOOTH,
|
||||
false);
|
||||
}
|
||||
if (SeamHidden.getValue()) {
|
||||
geometryObject->extractGeometry(TechDrawGeometry::ecSEAM,
|
||||
false);
|
||||
go->extractGeometry(TechDrawGeometry::ecSEAM,
|
||||
false);
|
||||
}
|
||||
if (IsoHidden.getValue() && (IsoCount.getValue() > 0)) {
|
||||
geometryObject->extractGeometry(TechDrawGeometry::ecUVISO,
|
||||
false);
|
||||
go->extractGeometry(TechDrawGeometry::ecUVISO,
|
||||
false);
|
||||
}
|
||||
bbox = geometryObject->calcBoundingBox();
|
||||
bbox = go->calcBoundingBox();
|
||||
return go;
|
||||
}
|
||||
|
||||
//! make faces from the existing edge geometry
|
||||
void DrawViewPart::extractFaces()
|
||||
{
|
||||
geometryObject->clearFaceGeom();
|
||||
const std::vector<TechDrawGeometry::BaseGeom*>& goEdges = geometryObject->getVisibleFaceEdges();
|
||||
const std::vector<TechDrawGeometry::BaseGeom*>& goEdges =
|
||||
geometryObject->getVisibleFaceEdges(SmoothVisible.getValue(),SeamVisible.getValue());
|
||||
std::vector<TechDrawGeometry::BaseGeom*>::const_iterator itEdge = goEdges.begin();
|
||||
std::vector<TopoDS_Edge> origEdges;
|
||||
for (;itEdge != goEdges.end(); itEdge++) {
|
||||
|
@ -356,7 +328,7 @@ void DrawViewPart::extractFaces()
|
|||
}
|
||||
|
||||
double param = -1;
|
||||
if (isOnEdge((*itInner),v1,param,false)) {
|
||||
if (DrawProjectSplit::isOnEdge((*itInner),v1,param,false)) {
|
||||
gp_Pnt pnt1 = BRep_Tool::Pnt(v1);
|
||||
splitPoint s1;
|
||||
s1.i = iInner;
|
||||
|
@ -364,7 +336,7 @@ void DrawViewPart::extractFaces()
|
|||
s1.param = param;
|
||||
splits.push_back(s1);
|
||||
}
|
||||
if (isOnEdge((*itInner),v2,param,false)) {
|
||||
if (DrawProjectSplit::isOnEdge((*itInner),v2,param,false)) {
|
||||
gp_Pnt pnt2 = BRep_Tool::Pnt(v2);
|
||||
splitPoint s2;
|
||||
s2.i = iInner;
|
||||
|
@ -375,10 +347,10 @@ void DrawViewPart::extractFaces()
|
|||
} //inner loop
|
||||
} //outer loop
|
||||
|
||||
std::vector<splitPoint> sorted = sortSplits(splits,true);
|
||||
auto last = std::unique(sorted.begin(), sorted.end(), DrawViewPart::splitEqual); //duplicates to back
|
||||
std::vector<splitPoint> sorted = DrawProjectSplit::sortSplits(splits,true);
|
||||
auto last = std::unique(sorted.begin(), sorted.end(), DrawProjectSplit::splitEqual); //duplicates to back
|
||||
sorted.erase(last, sorted.end()); //remove dupls
|
||||
std::vector<TopoDS_Edge> newEdges = splitEdges(faceEdges,sorted);
|
||||
std::vector<TopoDS_Edge> newEdges = DrawProjectSplit::splitEdges(faceEdges,sorted);
|
||||
|
||||
if (newEdges.empty()) {
|
||||
Base::Console().Log("LOG - DVP::extractFaces - no newEdges\n");
|
||||
|
@ -408,247 +380,6 @@ void DrawViewPart::extractFaces()
|
|||
}
|
||||
}
|
||||
|
||||
double DrawViewPart::simpleMinDist(TopoDS_Shape s1, TopoDS_Shape s2)
|
||||
{
|
||||
Standard_Real minDist = -1;
|
||||
|
||||
BRepExtrema_DistShapeShape extss(s1, s2);
|
||||
if (!extss.IsDone()) {
|
||||
Base::Console().Message("DVP - BRepExtrema_DistShapeShape failed");
|
||||
return -1;
|
||||
}
|
||||
int count = extss.NbSolution();
|
||||
if (count != 0) {
|
||||
minDist = extss.Value();
|
||||
} else {
|
||||
minDist = -1;
|
||||
}
|
||||
return minDist;
|
||||
}
|
||||
|
||||
//this routine is the big time consumer. gets called many times (and is slow?))
|
||||
//note param gets modified here
|
||||
bool DrawViewPart::isOnEdge(TopoDS_Edge e, TopoDS_Vertex v, double& param, bool allowEnds)
|
||||
{
|
||||
bool result = false;
|
||||
bool outOfBox = false;
|
||||
param = -2;
|
||||
|
||||
//eliminate obvious cases
|
||||
Bnd_Box sBox;
|
||||
BRepBndLib::Add(e, sBox);
|
||||
sBox.SetGap(0.1);
|
||||
if (sBox.IsVoid()) {
|
||||
Base::Console().Message("DVP::isOnEdge - Bnd_Box is void for %s\n",getNameInDocument());
|
||||
} else {
|
||||
gp_Pnt pt = BRep_Tool::Pnt(v);
|
||||
if (sBox.IsOut(pt)) {
|
||||
outOfBox = true;
|
||||
}
|
||||
}
|
||||
if (!outOfBox) {
|
||||
if (m_interAlgo == 1) {
|
||||
//1) using projPointOnCurve. roughly similar to dist to shape w/ bndbox. hangs(?) w/o bndbox
|
||||
try {
|
||||
gp_Pnt pt = BRep_Tool::Pnt(v);
|
||||
BRepAdaptor_Curve adapt(e);
|
||||
Handle_Geom_Curve c = adapt.Curve().Curve();
|
||||
GeomAPI_ProjectPointOnCurve proj(pt,c);
|
||||
int n = proj.NbPoints();
|
||||
if (n > 0) {
|
||||
if (proj.LowerDistance() < Precision::Confusion()) {
|
||||
param = proj.LowerDistanceParameter();
|
||||
result = true;
|
||||
}
|
||||
if (result) {
|
||||
TopoDS_Vertex v1 = TopExp::FirstVertex(e);
|
||||
TopoDS_Vertex v2 = TopExp::LastVertex(e);
|
||||
if (DrawUtil::isSamePoint(v,v1) || DrawUtil::isSamePoint(v,v2)) {
|
||||
if (!allowEnds) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Standard_Failure) {
|
||||
Handle_Standard_Failure e = Standard_Failure::Caught(); //no perp projection
|
||||
}
|
||||
} else if (m_interAlgo == 2) { //can't provide param as is
|
||||
double dist = simpleMinDist(v,e);
|
||||
if (dist < 0.0) {
|
||||
Base::Console().Error("DVP::isOnEdge - simpleMinDist failed: %.3f\n",dist);
|
||||
result = false;
|
||||
} else if (dist < Precision::Confusion()) {
|
||||
const gp_Pnt pt = BRep_Tool::Pnt(v); //have to duplicate method 3 to get param
|
||||
BRepAdaptor_Curve adapt(e);
|
||||
const Handle_Geom_Curve c = adapt.Curve().Curve();
|
||||
double maxDist = 0.000001; //magic number. less than this gives false positives.
|
||||
//bool found =
|
||||
(void) GeomLib_Tool::Parameter(c,pt,maxDist,param); //already know point it on curve
|
||||
result = true;
|
||||
}
|
||||
if (result) {
|
||||
TopoDS_Vertex v1 = TopExp::FirstVertex(e);
|
||||
TopoDS_Vertex v2 = TopExp::LastVertex(e);
|
||||
if (DrawUtil::isSamePoint(v,v1) || DrawUtil::isSamePoint(v,v2)) {
|
||||
if (!allowEnds) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (m_interAlgo == 3) {
|
||||
const gp_Pnt pt = BRep_Tool::Pnt(v);
|
||||
BRepAdaptor_Curve adapt(e);
|
||||
const Handle_Geom_Curve c = adapt.Curve().Curve();
|
||||
double par = -1;
|
||||
double maxDist = 0.000001; //magic number. less than this gives false positives.
|
||||
bool found = GeomLib_Tool::Parameter(c,pt,maxDist,par);
|
||||
if (found) {
|
||||
result = true;
|
||||
param = par;
|
||||
TopoDS_Vertex v1 = TopExp::FirstVertex(e);
|
||||
TopoDS_Vertex v2 = TopExp::LastVertex(e);
|
||||
if (DrawUtil::isSamePoint(v,v1) || DrawUtil::isSamePoint(v,v2)) {
|
||||
if (!allowEnds) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} //!outofbox
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<TopoDS_Edge> DrawViewPart::splitEdges(std::vector<TopoDS_Edge> edges, std::vector<splitPoint> splits)
|
||||
{
|
||||
std::vector<TopoDS_Edge> result;
|
||||
std::vector<TopoDS_Edge> newEdges;
|
||||
std::vector<splitPoint> edgeSplits; //splits for current edge
|
||||
int iEdge = 0; //current edge index
|
||||
int iSplit = 0; //current splitindex
|
||||
int ii = 0; //i value of current split
|
||||
int endEdge = edges.size();
|
||||
int endSplit = splits.size();
|
||||
int imax = std::numeric_limits<int>::max();
|
||||
|
||||
while ((iEdge < endEdge) ) {
|
||||
if (iSplit < endSplit) {
|
||||
ii = splits[iSplit].i;
|
||||
} else {
|
||||
ii = imax;
|
||||
}
|
||||
if (ii == iEdge) {
|
||||
edgeSplits.push_back(splits[iSplit]);
|
||||
iSplit++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ii > iEdge) {
|
||||
if (!edgeSplits.empty()) { //save *iedge's splits
|
||||
newEdges = split1Edge(edges[iEdge],edgeSplits);
|
||||
result.insert(result.end(), newEdges.begin(), newEdges.end());
|
||||
edgeSplits.clear();
|
||||
} else {
|
||||
result.push_back(edges[iEdge]); //save *iedge
|
||||
}
|
||||
iEdge++; //next edge
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iEdge > ii) {
|
||||
iSplit++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!edgeSplits.empty()) { //handle last batch
|
||||
newEdges = split1Edge(edges[iEdge],edgeSplits);
|
||||
result.insert(result.end(), newEdges.begin(), newEdges.end());
|
||||
edgeSplits.clear();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<TopoDS_Edge> DrawViewPart::split1Edge(TopoDS_Edge e, std::vector<splitPoint> splits)
|
||||
{
|
||||
//Base::Console().Message("DVP::split1Edge - splits: %d\n",splits.size());
|
||||
std::vector<TopoDS_Edge> result;
|
||||
if (splits.empty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
BRepAdaptor_Curve adapt(e);
|
||||
Handle_Geom_Curve c = adapt.Curve().Curve();
|
||||
double first = BRepLProp_CurveTool::FirstParameter(adapt);
|
||||
double last = BRepLProp_CurveTool::LastParameter(adapt);
|
||||
if (first > last) {
|
||||
//TODO parms.reverse();
|
||||
Base::Console().Message("DVP::split1Edge - edge is backwards!\n");
|
||||
return result;
|
||||
}
|
||||
std::vector<double> parms;
|
||||
parms.push_back(first);
|
||||
for (auto& s:splits) {
|
||||
parms.push_back(s.param);
|
||||
}
|
||||
|
||||
parms.push_back(last);
|
||||
std::vector<double>::iterator pfirst = parms.begin();
|
||||
auto parms2 = parms.begin() + 1;
|
||||
std::vector<double>::iterator psecond = parms2;
|
||||
std::vector<double>::iterator pstop = parms.end();
|
||||
for (; psecond != pstop; pfirst++,psecond++) {
|
||||
try {
|
||||
BRepBuilderAPI_MakeEdge mkEdge(c, *pfirst, *psecond);
|
||||
if (mkEdge.IsDone()) {
|
||||
TopoDS_Edge e1 = mkEdge.Edge();
|
||||
result.push_back(e1);
|
||||
}
|
||||
}
|
||||
catch (Standard_Failure) {
|
||||
Base::Console().Message("LOG - DVP::split1Edge failed building edge segment\n");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<splitPoint> DrawViewPart::sortSplits(std::vector<splitPoint>& s, bool ascend)
|
||||
{
|
||||
std::vector<splitPoint> sorted = s;
|
||||
std::sort(sorted.begin(), sorted.end(), DrawViewPart::splitCompare);
|
||||
if (ascend) {
|
||||
std::reverse(sorted.begin(),sorted.end());
|
||||
}
|
||||
return sorted;
|
||||
}
|
||||
|
||||
//return true if p1 "is greater than" p2
|
||||
/*static*/bool DrawViewPart::splitCompare(const splitPoint& p1, const splitPoint& p2)
|
||||
{
|
||||
bool result = false;
|
||||
if (p1.i > p2.i) {
|
||||
result = true;
|
||||
} else if (p1.i < p2.i) {
|
||||
result = false;
|
||||
} else if (p1.param > p2.param) {
|
||||
result = true;
|
||||
} else if (p1.param < p2.param) {
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//return true if p1 "is equal to" p2
|
||||
/*static*/bool DrawViewPart::splitEqual(const splitPoint& p1, const splitPoint& p2)
|
||||
{
|
||||
bool result = false;
|
||||
if ((p1.i == p2.i) &&
|
||||
(fabs(p1.param - p2.param) < Precision::Confusion())) {
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<TechDraw::DrawHatch*> DrawViewPart::getHatches() const
|
||||
{
|
||||
|
@ -763,6 +494,9 @@ Base::Vector3d DrawViewPart::projectPoint(const Base::Vector3d& pt) const
|
|||
bool DrawViewPart::hasGeometry(void) const
|
||||
{
|
||||
bool result = false;
|
||||
if (geometryObject == nullptr) {
|
||||
return result;
|
||||
}
|
||||
const std::vector<TechDrawGeometry::Vertex*> &verts = getVertexGeometry();
|
||||
const std::vector<TechDrawGeometry::BaseGeom*> &edges = getEdgeGeometry();
|
||||
if (verts.empty() &&
|
||||
|
@ -802,18 +536,15 @@ std::vector<DrawViewSection*> DrawViewPart::getSectionRefs(void) const
|
|||
|
||||
const std::vector<TechDrawGeometry::BaseGeom *> DrawViewPart::getVisibleFaceEdges() const
|
||||
{
|
||||
return geometryObject->getVisibleFaceEdges();
|
||||
return geometryObject->getVisibleFaceEdges(SmoothVisible.getValue(),SeamVisible.getValue());
|
||||
}
|
||||
|
||||
void DrawViewPart::getRunControl()
|
||||
{
|
||||
Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
|
||||
.GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/RunControl");
|
||||
m_interAlgo = hGrp->GetInt("InterAlgo", 2l);
|
||||
m_sectionEdges = hGrp->GetBool("ShowSectionEdges", 1l);
|
||||
m_handleFaces = hGrp->GetBool("HandleFaces", 1l);
|
||||
// Base::Console().Message("TRACE - DVP::getRunControl - interAlgo: %ld sectionFaces: %ld handleFaces: %ld\n",
|
||||
// m_interAlgo,m_sectionEdges,m_handleFaces);
|
||||
}
|
||||
|
||||
bool DrawViewPart::handleFaces(void)
|
||||
|
|
|
@ -32,12 +32,12 @@
|
|||
#include <App/DocumentObject.h>
|
||||
#include <App/PropertyLinks.h>
|
||||
#include <App/PropertyStandard.h>
|
||||
#include "DrawView.h"
|
||||
#include <App/FeaturePython.h>
|
||||
|
||||
#include <Base/BoundBox.h>
|
||||
|
||||
//#include "GeometryObject.h"
|
||||
#include "DrawView.h"
|
||||
#include "DrawProjectSplit.h"
|
||||
|
||||
class gp_Pnt;
|
||||
|
||||
|
@ -55,11 +55,7 @@ class DrawHatch;
|
|||
|
||||
namespace TechDraw
|
||||
{
|
||||
struct splitPoint {
|
||||
int i;
|
||||
Base::Vector3d v;
|
||||
double param;
|
||||
};
|
||||
|
||||
class DrawViewSection;
|
||||
|
||||
class TechDrawExport DrawViewPart : public DrawView
|
||||
|
@ -72,7 +68,6 @@ public:
|
|||
|
||||
App::PropertyLink Source; //Part Feature
|
||||
App::PropertyVector Direction; //TODO: Rename to YAxisDirection or whatever this actually is (ProjectionDirection)
|
||||
//App::PropertyVector XAxisDirection;
|
||||
App::PropertyBool SeamVisible;
|
||||
App::PropertyBool SmoothVisible;
|
||||
//App::PropertyBool OutlinesVisible;
|
||||
|
@ -90,7 +85,6 @@ public:
|
|||
App::PropertyFloat IsoWidth;
|
||||
App::PropertyBool ArcCenterMarks;
|
||||
App::PropertyFloat CenterScale;
|
||||
App::PropertyFloatConstraint Tolerance;
|
||||
App::PropertyBool HorizCenterLine;
|
||||
App::PropertyBool VertCenterLine;
|
||||
App::PropertyBool ShowSectionLine;
|
||||
|
@ -144,31 +138,21 @@ protected:
|
|||
Base::BoundBox3d bbox;
|
||||
|
||||
void onChanged(const App::Property* prop);
|
||||
void buildGeometryObject(TopoDS_Shape shape, gp_Pnt& center);
|
||||
TechDrawGeometry::GeometryObject* buildGeometryObject(TopoDS_Shape shape, gp_Pnt& center);
|
||||
void extractFaces();
|
||||
|
||||
bool isOnEdge(TopoDS_Edge e, TopoDS_Vertex v, double& param, bool allowEnds = false);
|
||||
std::vector<TopoDS_Edge> splitEdges(std::vector<TopoDS_Edge> orig, std::vector<splitPoint> splits);
|
||||
std::vector<TopoDS_Edge> split1Edge(TopoDS_Edge e, std::vector<splitPoint> splitPoints);
|
||||
double simpleMinDist(TopoDS_Shape s1, TopoDS_Shape s2); //const; //probably sb static or DrawUtil
|
||||
|
||||
//Projection parameter space
|
||||
void saveParamSpace(const Base::Vector3d& direction);
|
||||
Base::Vector3d uDir; //paperspace X
|
||||
Base::Vector3d vDir; //paperspace Y
|
||||
Base::Vector3d wDir; //paperspace Z
|
||||
Base::Vector3d shapeCentroid;
|
||||
std::vector<splitPoint> sortSplits(std::vector<splitPoint>& s, bool ascend);
|
||||
static bool splitCompare(const splitPoint& p1, const splitPoint& p2);
|
||||
static bool splitEqual(const splitPoint& p1, const splitPoint& p2);
|
||||
void getRunControl(void);
|
||||
|
||||
long int m_interAlgo;
|
||||
bool m_sectionEdges;
|
||||
bool m_handleFaces;
|
||||
|
||||
private:
|
||||
static App::PropertyFloatConstraint::Constraints floatRange;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
#include "Geometry.h"
|
||||
#include "GeometryObject.h"
|
||||
#include "EdgeWalker.h"
|
||||
#include "DrawProjectSplit.h"
|
||||
#include "DrawViewSection.h"
|
||||
|
||||
using namespace TechDraw;
|
||||
|
@ -219,9 +220,6 @@ App::DocumentObjectExecReturn *DrawViewSection::execute(void)
|
|||
return DrawView::execute();
|
||||
}
|
||||
|
||||
geometryObject->setTolerance(Tolerance.getValue());
|
||||
geometryObject->setScale(Scale.getValue());
|
||||
|
||||
gp_Pnt inputCenter;
|
||||
try {
|
||||
inputCenter = TechDrawGeometry::findCentroid(rawShape,
|
||||
|
@ -229,7 +227,7 @@ App::DocumentObjectExecReturn *DrawViewSection::execute(void)
|
|||
TopoDS_Shape mirroredShape = TechDrawGeometry::mirrorShape(rawShape,
|
||||
inputCenter,
|
||||
Scale.getValue());
|
||||
buildGeometryObject(mirroredShape,inputCenter); //this is original shape after cut by section prism
|
||||
geometryObject = buildGeometryObject(mirroredShape,inputCenter); //this is original shape after cut by section prism
|
||||
|
||||
#if MOD_TECHDRAW_HANDLE_FACES
|
||||
extractFaces();
|
||||
|
|
|
@ -38,10 +38,8 @@
|
|||
#include <gp_Elips.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <gp_Vec.hxx>
|
||||
//#include <HLRTopoBRep_OutLiner.hxx>
|
||||
#include <HLRBRep.hxx>
|
||||
#include <HLRBRep_Algo.hxx>
|
||||
//#include <HLRBRep_Data.hxx>
|
||||
#include <HLRBRep_HLRToShape.hxx>
|
||||
#include <HLRAlgo_Projector.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
|
@ -69,8 +67,6 @@
|
|||
#include "GeometryObject.h"
|
||||
#include "DrawViewPart.h"
|
||||
|
||||
//#include <QDebug>
|
||||
|
||||
using namespace TechDrawGeometry;
|
||||
using namespace TechDraw;
|
||||
using namespace std;
|
||||
|
@ -80,11 +76,9 @@ struct EdgePoints {
|
|||
TopoDS_Edge edge;
|
||||
};
|
||||
|
||||
|
||||
GeometryObject::GeometryObject(DrawViewPart* parent) :
|
||||
Tolerance(0.05f),
|
||||
GeometryObject::GeometryObject(std::string parent) :
|
||||
Scale(1.f),
|
||||
m_parent(parent),
|
||||
m_parentName(parent),
|
||||
m_isoCount(0)
|
||||
{
|
||||
}
|
||||
|
@ -94,21 +88,18 @@ GeometryObject::~GeometryObject()
|
|||
clear();
|
||||
}
|
||||
|
||||
void GeometryObject::setTolerance(double value)
|
||||
{
|
||||
Tolerance = value;
|
||||
}
|
||||
|
||||
void GeometryObject::setScale(double value)
|
||||
{
|
||||
Scale = value;
|
||||
}
|
||||
|
||||
const std::vector<BaseGeom *> GeometryObject::getVisibleFaceEdges() const
|
||||
|
||||
const std::vector<BaseGeom *> GeometryObject::getVisibleFaceEdges(const bool smooth, const bool seam) const
|
||||
{
|
||||
std::vector<BaseGeom *> result;
|
||||
bool smoothOK = m_parent->SmoothVisible.getValue();
|
||||
bool seamOK = m_parent->SeamVisible.getValue();
|
||||
bool smoothOK = smooth;
|
||||
bool seamOK = seam;
|
||||
|
||||
for (auto& e:edgeGeom) {
|
||||
if (e->visible) {
|
||||
switch (e->classOfEdge) {
|
||||
|
@ -184,7 +175,7 @@ void GeometryObject::projectShape(const TopoDS_Shape& input,
|
|||
auto end = chrono::high_resolution_clock::now();
|
||||
auto diff = end - start;
|
||||
double diffOut = chrono::duration <double, milli> (diff).count();
|
||||
Base::Console().Log("TIMING - %s GO spent: %.3f millisecs in HLRBRep_Algo & co\n",m_parent->getNameInDocument(),diffOut);
|
||||
Base::Console().Log("TIMING - %s GO spent: %.3f millisecs in HLRBRep_Algo & co\n",m_parentName.c_str(),diffOut);
|
||||
|
||||
try {
|
||||
HLRBRep_HLRToShape hlrToShape(brep_hlr);
|
||||
|
@ -297,7 +288,6 @@ void GeometryObject::addGeomFromCompound(TopoDS_Shape edgeCompound, edgeClass ca
|
|||
//add vertices of new edge if not already in list
|
||||
if (visible) {
|
||||
BaseGeom* lastAdded = edgeGeom.back();
|
||||
//if (edgeGeom.empty()) {horrible_death();} //back() undefined behavior (can't happen? baseFactory always returns a Base?)
|
||||
bool v1Add = true, v2Add = true;
|
||||
bool c1Add = true;
|
||||
TechDrawGeometry::Vertex* v1 = new TechDrawGeometry::Vertex(lastAdded->getStartPoint());
|
||||
|
@ -754,24 +744,22 @@ TopoDS_Shape TechDrawGeometry::mirrorShape(const TopoDS_Shape &input,
|
|||
return transShape;
|
||||
}
|
||||
|
||||
/// debug functions
|
||||
/* TODO: Clean this up when faces are actually working properly...
|
||||
|
||||
void debugEdge(const TopoDS_Edge &e)
|
||||
|
||||
//!scales a shape about a origin
|
||||
TopoDS_Shape TechDrawGeometry::scaleShape(const TopoDS_Shape &input,
|
||||
double scale)
|
||||
{
|
||||
TopoDS_Shape transShape;
|
||||
try {
|
||||
gp_Trsf scaleTransform;
|
||||
scaleTransform.SetScale(gp_Pnt(0,0,0), scale);
|
||||
|
||||
gp_Pnt p0 = BRep_Tool::Pnt(TopExp::FirstVertex(e));
|
||||
|
||||
gp_Pnt p1 = BRep_Tool::Pnt(TopExp::LastVertex(e));
|
||||
|
||||
qDebug()<<p0.X()<<','<<p0.Y()<<','<<p0.Z()<<"\t - \t"<<p1.X()<<','<<p1.Y()<<','<<p1.Z();
|
||||
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
const char* _printBool(bool b)
|
||||
{
|
||||
return (b ? "True" : "False");
|
||||
BRepBuilderAPI_Transform mkTrf(input, scaleTransform);
|
||||
transShape = mkTrf.Shape();
|
||||
}
|
||||
catch (...) {
|
||||
Base::Console().Log("GeometryObject::scaleShape - scale failed.\n");
|
||||
return transShape;
|
||||
}
|
||||
return transShape;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <TopoDS_Compound.hxx>
|
||||
//#include <HLRBRep_Data.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
|
||||
#include <Base/Vector3D.h>
|
||||
|
@ -33,7 +32,6 @@
|
|||
#include <vector>
|
||||
|
||||
#include "Geometry.h"
|
||||
//#include "DrawViewPart.h"
|
||||
|
||||
namespace TechDraw
|
||||
{
|
||||
|
@ -48,6 +46,8 @@ namespace TechDrawGeometry
|
|||
TopoDS_Shape TechDrawExport mirrorShape(const TopoDS_Shape &input,
|
||||
const gp_Pnt& inputCenter,
|
||||
double scale);
|
||||
TopoDS_Shape TechDrawExport scaleShape(const TopoDS_Shape &input,
|
||||
double scale);
|
||||
|
||||
//! Returns the centroid of shape, as viewed according to direction
|
||||
gp_Pnt TechDrawExport findCentroid(const TopoDS_Shape &shape,
|
||||
|
@ -61,12 +61,11 @@ class TechDrawExport GeometryObject
|
|||
{
|
||||
public:
|
||||
/// Constructor
|
||||
GeometryObject(TechDraw::DrawViewPart* parent);
|
||||
GeometryObject(std::string parent);
|
||||
virtual ~GeometryObject();
|
||||
|
||||
void clear();
|
||||
|
||||
void setTolerance(double value);
|
||||
void setScale(double value);
|
||||
|
||||
//! Returns 2D bounding box
|
||||
|
@ -74,7 +73,7 @@ public:
|
|||
|
||||
const std::vector<Vertex *> & getVertexGeometry() const { return vertexGeom; };
|
||||
const std::vector<BaseGeom *> & getEdgeGeometry() const { return edgeGeom; };
|
||||
const std::vector<BaseGeom *> getVisibleFaceEdges() const;
|
||||
const std::vector<BaseGeom *> getVisibleFaceEdges(bool smooth, bool seam) const;
|
||||
const std::vector<Face *> & getFaceGeometry() const { return faceGeom; };
|
||||
|
||||
void projectShape(const TopoDS_Shape &input,
|
||||
|
@ -84,6 +83,7 @@ public:
|
|||
void addFaceGeom(Face * f);
|
||||
void clearFaceGeom();
|
||||
void setIsoCount(int i) { m_isoCount = i; }
|
||||
void setParentName(std::string n); //for debug messages
|
||||
|
||||
protected:
|
||||
//HLR output
|
||||
|
@ -128,10 +128,9 @@ protected:
|
|||
|
||||
bool findVertex(Base::Vector2D v);
|
||||
|
||||
double Tolerance;
|
||||
double Scale;
|
||||
|
||||
TechDraw::DrawViewPart* m_parent;
|
||||
std::string m_parentName;
|
||||
int m_isoCount;
|
||||
};
|
||||
|
||||
|
|
|
@ -250,7 +250,6 @@ void QGIViewPart::updateView(bool update)
|
|||
viewPart->isTouched() ||
|
||||
viewPart->Source.isTouched() ||
|
||||
viewPart->Direction.isTouched() ||
|
||||
viewPart->Tolerance.isTouched() ||
|
||||
viewPart->Scale.isTouched() ||
|
||||
viewPart->HardHidden.isTouched() ||
|
||||
viewPart->SmoothVisible.isTouched() ||
|
||||
|
@ -290,6 +289,9 @@ void QGIViewPart::drawViewPart()
|
|||
if ( viewPart == nullptr ) {
|
||||
return;
|
||||
}
|
||||
if (!viewPart->hasGeometry()) {
|
||||
return;
|
||||
}
|
||||
|
||||
float lineWidth = viewPart->LineWidth.getValue() * lineScaleFactor;
|
||||
float lineWidthHid = viewPart->HiddenWidth.getValue() * lineScaleFactor;
|
||||
|
|
Loading…
Reference in New Issue
Block a user