Fix handling of BezierCurves
Replace custom bbox code with OCC/Base code Refactor duplicate code Geometry/DrawProjectSplit
This commit is contained in:
@@ -124,8 +124,8 @@ std::vector<TopoDS_Edge> DrawProjectSplit::getEdgesForWalker(TopoDS_Shape shape,
|
||||
|
||||
|
||||
TechDrawGeometry::GeometryObject* DrawProjectSplit::buildGeometryObject(
|
||||
TopoDS_Shape shape,
|
||||
gp_Pnt& inputCenter,
|
||||
TopoDS_Shape shape,
|
||||
gp_Pnt& inputCenter,
|
||||
Base::Vector3d direction)
|
||||
{
|
||||
TechDrawGeometry::GeometryObject* geometryObject = new TechDrawGeometry::GeometryObject("DrawProjectSplit");
|
||||
@@ -231,30 +231,10 @@ std::vector<TopoDS_Edge> DrawProjectSplit::getEdges(TechDrawGeometry::GeometryOb
|
||||
Base::Console().Log("LOG - DPS::extractFaces - no newEdges\n");
|
||||
}
|
||||
newEdges = removeDuplicateEdges(newEdges);
|
||||
|
||||
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)
|
||||
@@ -276,7 +256,7 @@ bool DrawProjectSplit::isOnEdge(TopoDS_Edge e, TopoDS_Vertex v, double& param, b
|
||||
}
|
||||
}
|
||||
if (!outOfBox) {
|
||||
double dist = simpleMinDist(v,e);
|
||||
double dist = DrawUtil::simpleMinDist(v,e);
|
||||
if (dist < 0.0) {
|
||||
Base::Console().Error("DPS::isOnEdge - simpleMinDist failed: %.3f\n",dist);
|
||||
result = false;
|
||||
|
||||
@@ -46,8 +46,7 @@ class BaseGeom;
|
||||
|
||||
namespace TechDraw
|
||||
{
|
||||
struct splitPoint
|
||||
{
|
||||
struct splitPoint {
|
||||
int i;
|
||||
Base::Vector3d v;
|
||||
double param;
|
||||
@@ -69,8 +68,6 @@ public:
|
||||
static bool edgeEqual(const edgeSortItem& e1, const edgeSortItem& e2);
|
||||
std::string dump(void);
|
||||
};
|
||||
|
||||
|
||||
class TechDrawExport DrawProjectSplit
|
||||
{
|
||||
public:
|
||||
@@ -84,16 +81,13 @@ public:
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
static std::vector<TopoDS_Edge> removeDuplicateEdges(std::vector<TopoDS_Edge>& inEdges);
|
||||
static std::vector<edgeSortItem> sortEdges(std::vector<edgeSortItem>& e, bool ascend);
|
||||
|
||||
|
||||
protected:
|
||||
static std::vector<TopoDS_Edge> getEdges(TechDrawGeometry::GeometryObject* geometryObject);
|
||||
|
||||
|
||||
@@ -39,14 +39,15 @@
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <Precision.hxx>
|
||||
#include <BRepLProp_CLProps.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <BRepExtrema_DistShapeShape.hxx>
|
||||
#include <BRepGProp.hxx>
|
||||
#include <BRepLProp_CLProps.hxx>
|
||||
#include <BRepLProp_CurveTool.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopTools_IndexedMapOfShape.hxx>
|
||||
#include <TopExp.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <BRepGProp.hxx>
|
||||
#include <GProp_GProps.hxx>
|
||||
|
||||
#endif
|
||||
@@ -139,6 +140,23 @@ bool DrawUtil::isZeroEdge(TopoDS_Edge e)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
double DrawUtil::simpleMinDist(TopoDS_Shape s1, TopoDS_Shape s2)
|
||||
{
|
||||
Standard_Real minDist = -1;
|
||||
|
||||
BRepExtrema_DistShapeShape extss(s1, s2);
|
||||
if (!extss.IsDone()) {
|
||||
Base::Console().Message("DU::simpleMinDist - BRepExtrema_DistShapeShape failed");
|
||||
return -1;
|
||||
}
|
||||
int count = extss.NbSolution();
|
||||
if (count != 0) {
|
||||
minDist = extss.Value();
|
||||
} else {
|
||||
minDist = -1;
|
||||
}
|
||||
return minDist;
|
||||
}
|
||||
|
||||
//! assumes 2d on XY
|
||||
//! quick angle for straight edges
|
||||
@@ -211,7 +229,6 @@ double DrawUtil::angleWithX(TopoDS_Edge e, TopoDS_Vertex v)
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool DrawUtil::isFirstVert(TopoDS_Edge e, TopoDS_Vertex v)
|
||||
{
|
||||
bool result = false;
|
||||
@@ -286,6 +303,7 @@ int DrawUtil::vectorCompare(const Base::Vector3d& v1, const Base::Vector3d& v2)
|
||||
}
|
||||
|
||||
|
||||
|
||||
//based on Function provided by Joe Dowsett, 2014
|
||||
double DrawUtil::sensibleScale(double working_scale)
|
||||
{
|
||||
|
||||
@@ -47,6 +47,7 @@ class TechDrawExport DrawUtil {
|
||||
static std::string makeGeomName(std::string geomType, int index);
|
||||
static bool isSamePoint(TopoDS_Vertex v1, TopoDS_Vertex v2);
|
||||
static bool isZeroEdge(TopoDS_Edge e);
|
||||
static double simpleMinDist(TopoDS_Shape s1, TopoDS_Shape s2);
|
||||
static double sensibleScale(double working_scale);
|
||||
static double angleWithX(TopoDS_Edge e, bool reverse);
|
||||
static double angleWithX(TopoDS_Edge e, TopoDS_Vertex v);
|
||||
|
||||
@@ -54,8 +54,9 @@
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/Tools2D.h>
|
||||
//#include <Base/Vector3D.h>
|
||||
|
||||
#include "Geometry.h"
|
||||
#include "DrawUtil.h"
|
||||
|
||||
using namespace TechDrawGeometry;
|
||||
|
||||
@@ -64,7 +65,6 @@ Wire::Wire()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Wire::Wire(const TopoDS_Wire &w)
|
||||
{
|
||||
TopExp_Explorer edges(w, TopAbs_EDGE);
|
||||
@@ -72,10 +72,8 @@ Wire::Wire(const TopoDS_Wire &w)
|
||||
const auto edge( TopoDS::Edge(edges.Current()) );
|
||||
geoms.push_back( BaseGeom::baseFactory(edge) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Wire::~Wire()
|
||||
{
|
||||
for(auto it : geoms) {
|
||||
@@ -84,7 +82,6 @@ Wire::~Wire()
|
||||
geoms.clear();
|
||||
}
|
||||
|
||||
|
||||
Face::~Face()
|
||||
{
|
||||
for(auto it : wires) {
|
||||
@@ -93,14 +90,13 @@ Face::~Face()
|
||||
wires.clear();
|
||||
}
|
||||
|
||||
|
||||
BaseGeom::BaseGeom() :
|
||||
geomType(NOTDEF),
|
||||
extractType(Plain),
|
||||
extractType(Plain), //obs
|
||||
classOfEdge(ecNONE),
|
||||
visible(true),
|
||||
reversed(false),
|
||||
ref3D(-1)
|
||||
ref3D(-1) //obs?
|
||||
{
|
||||
}
|
||||
|
||||
@@ -137,13 +133,7 @@ double BaseGeom::minDist(Base::Vector2D p)
|
||||
double minDist = -1.0;
|
||||
gp_Pnt pnt(p.fX,p.fY,0.0);
|
||||
TopoDS_Vertex v = BRepBuilderAPI_MakeVertex(pnt);
|
||||
BRepExtrema_DistShapeShape extss(occEdge, v);
|
||||
if (extss.IsDone()) {
|
||||
int count = extss.NbSolution();
|
||||
if (count != 0) {
|
||||
minDist = extss.Value();
|
||||
}
|
||||
}
|
||||
minDist = TechDraw::DrawUtil::simpleMinDist(occEdge,v);
|
||||
return minDist;
|
||||
}
|
||||
|
||||
@@ -181,13 +171,22 @@ Base::Vector2D BaseGeom::nearPoint(Base::Vector2D p)
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string BaseGeom::dump()
|
||||
{
|
||||
Base::Vector2D start = getStartPoint();
|
||||
Base::Vector2D end = getEndPoint();
|
||||
std::stringstream ss;
|
||||
ss << "BaseGeom: s:(" << start.fX << "," << start.fY << ") e:(" << end.fX << "," << end.fY << ") ";
|
||||
ss << "type: " << geomType << " class: " << classOfEdge << " viz: " << visible << " rev: " << reversed;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
//! Convert 1 OCC edge into 1 BaseGeom (static factory method)
|
||||
BaseGeom* BaseGeom::baseFactory(TopoDS_Edge edge)
|
||||
{
|
||||
BaseGeom* result = NULL;
|
||||
BRepAdaptor_Curve adapt(edge);
|
||||
|
||||
switch(adapt.GetType()) {
|
||||
case GeomAbs_Circle: {
|
||||
double f = adapt.FirstParameter();
|
||||
@@ -197,11 +196,9 @@ BaseGeom* BaseGeom::baseFactory(TopoDS_Edge edge)
|
||||
|
||||
if (fabs(l-f) > 1.0 && s.SquareDistance(e) < 0.001) {
|
||||
Circle *circle = new Circle(edge);
|
||||
//circle->extractType = extractionType;
|
||||
result = circle;
|
||||
} else {
|
||||
AOC *aoc = new AOC(edge);
|
||||
//aoc->extractType = extractionType;
|
||||
result = aoc;
|
||||
}
|
||||
} break;
|
||||
@@ -212,40 +209,47 @@ BaseGeom* BaseGeom::baseFactory(TopoDS_Edge edge)
|
||||
gp_Pnt e = adapt.Value(l);
|
||||
if (fabs(l-f) > 1.0 && s.SquareDistance(e) < 0.001) {
|
||||
Ellipse *ellipse = new Ellipse(edge);
|
||||
//ellipse->extractType = extractionType;
|
||||
result = ellipse;
|
||||
} else {
|
||||
AOE *aoe = new AOE(edge);
|
||||
//aoe->extractType = extractionType;
|
||||
result = aoe;
|
||||
}
|
||||
} break;
|
||||
case GeomAbs_BezierCurve: {
|
||||
Handle_Geom_BezierCurve bez = adapt.Bezier();
|
||||
//if (bez->Degree() < 4) {
|
||||
result = new BezierSegment(edge);
|
||||
//}
|
||||
// OCC is quite happy with Degree > 3 but QtGui handles only 2,3
|
||||
} break;
|
||||
case GeomAbs_BSplineCurve: {
|
||||
BSpline *bspline = 0;
|
||||
Generic* gen = NULL;
|
||||
try {
|
||||
bspline = new BSpline(edge);
|
||||
//bspline->extractType = extractionType;
|
||||
if (bspline->isLine()) {
|
||||
gen = new Generic(edge);
|
||||
//gen->extractType = extractionType;
|
||||
result = gen;
|
||||
delete bspline;
|
||||
bspline = nullptr;
|
||||
} else {
|
||||
result = bspline;
|
||||
}
|
||||
break;
|
||||
}
|
||||
catch (Standard_Failure) {
|
||||
delete bspline;
|
||||
delete gen;
|
||||
bspline = 0;
|
||||
// Move onto generating a primitive
|
||||
if (bspline != nullptr) {
|
||||
delete bspline;
|
||||
bspline = nullptr;
|
||||
}
|
||||
if (gen != nullptr) {
|
||||
delete gen;
|
||||
gen = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
default: {
|
||||
Generic *primitive = new Generic(edge);
|
||||
//primitive->extractType = extractionType;
|
||||
result = primitive;
|
||||
} break;
|
||||
}
|
||||
@@ -306,8 +310,6 @@ Circle::Circle(const TopoDS_Edge &e)
|
||||
|
||||
gp_Circ circ = c.Circle();
|
||||
const gp_Pnt& p = circ.Location();
|
||||
//const gp_Ax2& p1 = circ.Position();
|
||||
//const gp_Pnt& l = p1.Location();
|
||||
|
||||
radius = circ.Radius();
|
||||
center = Base::Vector2D(p.X(), p.Y());
|
||||
@@ -364,17 +366,6 @@ double AOC::distToArc(Base::Vector3d p)
|
||||
Base::Vector2D p2(p.x,p.y);
|
||||
double result = minDist(p2);
|
||||
return result;
|
||||
// double minDist = -1.0;
|
||||
// gp_Pnt pnt(p.x,p.y,p.z);
|
||||
// TopoDS_Vertex v = BRepBuilderAPI_MakeVertex(pnt);
|
||||
// BRepExtrema_DistShapeShape extss(occEdge, v);
|
||||
// if (extss.IsDone()) {
|
||||
// int count = extss.NbSolution();
|
||||
// if (count != 0) {
|
||||
// minDist = extss.Value();
|
||||
// }
|
||||
// }
|
||||
// return minDist;
|
||||
}
|
||||
|
||||
|
||||
@@ -443,6 +434,8 @@ BSpline::BSpline(const TopoDS_Edge &e)
|
||||
double f,l;
|
||||
gp_Pnt s,m,ePt;
|
||||
//if startpoint == endpoint conversion to BSpline will fail
|
||||
//Base::Console().Message("TRACE - Geometry::BSpline - start(%.3f,%.3f,%.3f) end(%.3f,%.3f,%.3f)\n",
|
||||
// s.X(),s.Y(),s.Z(),ePt.X(),ePt.Y(),ePt.Z());
|
||||
|
||||
if (spline->Degree() > 3) { //if spline is too complex, approximate it
|
||||
Standard_Real tol3D = 0.001; //1/1000 of a mm? screen can't resolve this
|
||||
@@ -464,36 +457,36 @@ BSpline::BSpline(const TopoDS_Edge &e)
|
||||
s = c.Value(f);
|
||||
m = c.Value((l+f)/2.0);
|
||||
ePt = c.Value(l);
|
||||
Base::Console().Log("Error - Geometry::BSpline - from:(%.3f,%.3f) to:(%.3f,%.3f) poles: %d\n",
|
||||
Base::Console().Log("Error - Geometry::BSpline - no result- from:(%.3f,%.3f) to:(%.3f,%.3f) poles: %d\n",
|
||||
s.X(),s.Y(),ePt.X(),ePt.Y(),spline->NbPoles());
|
||||
//throw Base::Exception("Geometry::BSpline - could not approximate curve");
|
||||
throw Base::Exception("Geometry::BSpline - could not approximate curve");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GeomConvert_BSplineCurveToBezierCurve crt(spline);
|
||||
|
||||
BezierSegment tempSegment;
|
||||
gp_Pnt controlPoint;
|
||||
if (fail) {
|
||||
BezierSegment tempSegment;
|
||||
tempSegment.poles = 3;
|
||||
tempSegment.pnts[0] = Base::Vector2D(s.X(),s.Y());
|
||||
tempSegment.pnts[1] = Base::Vector2D(m.X(),m.Y());
|
||||
tempSegment.pnts[2] = Base::Vector2D(ePt.X(),ePt.Y());
|
||||
tempSegment.degree = 2;
|
||||
tempSegment.pnts.push_back(Base::Vector2D(s.X(),s.Y()));
|
||||
tempSegment.pnts.push_back(Base::Vector2D(m.X(),m.Y()));
|
||||
tempSegment.pnts.push_back(Base::Vector2D(ePt.X(),ePt.Y()));
|
||||
segments.push_back(tempSegment);
|
||||
} else {
|
||||
for (Standard_Integer i = 1; i <= crt.NbArcs(); ++i) {
|
||||
BezierSegment tempSegment;
|
||||
Handle_Geom_BezierCurve bezier = crt.Arc(i);
|
||||
if (bezier->Degree() > 3) {
|
||||
throw Base::Exception("Geometry::BSpline - converted curve degree > 3");
|
||||
Base::Console().Log("Geometry::BSpline - converted curve degree > 3\n");
|
||||
}
|
||||
tempSegment.poles = bezier->NbPoles();
|
||||
// Note: We really only need to keep the pnts[0] for the first Bezier segment,
|
||||
// assuming this only gets used as in QGIViewPart::drawPainterPath
|
||||
// ...it also gets used in GeometryObject::calcBoundingBox(), similar note applies
|
||||
tempSegment.degree = bezier->Degree();
|
||||
for (int pole = 1; pole <= tempSegment.poles; ++pole) {
|
||||
controlPoint = bezier->Pole(pole);
|
||||
tempSegment.pnts[pole - 1] = Base::Vector2D(controlPoint.X(), controlPoint.Y());
|
||||
tempSegment.pnts.push_back(Base::Vector2D(controlPoint.X(), controlPoint.Y()));
|
||||
}
|
||||
segments.push_back(tempSegment);
|
||||
}
|
||||
@@ -513,6 +506,23 @@ bool BSpline::isLine()
|
||||
return result;
|
||||
}
|
||||
|
||||
BezierSegment::BezierSegment(const TopoDS_Edge &e)
|
||||
{
|
||||
geomType = BEZIER;
|
||||
occEdge = e;
|
||||
BRepAdaptor_Curve c(e);
|
||||
Handle_Geom_BezierCurve bez = c.Bezier();
|
||||
poles = bez->NbPoles();
|
||||
degree = bez->Degree();
|
||||
if (poles > 4) {
|
||||
Base::Console().Log("Warning - BezierSegment has degree > 3: %d\n",degree);
|
||||
}
|
||||
for (int i = 1; i <= poles; ++i) {
|
||||
gp_Pnt controlPoint = bez->Pole(i);
|
||||
pnts.push_back(Base::Vector2D(controlPoint.X(), controlPoint.Y()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//**** Vertex
|
||||
Vertex::Vertex(double x, double y)
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
namespace TechDrawGeometry {
|
||||
|
||||
enum ExtractionType { //obs sb vis/hid + hard/smooth/seam/out(edgeClass?)
|
||||
enum ExtractionType { //obs
|
||||
Plain,
|
||||
WithHidden,
|
||||
WithSmooth
|
||||
@@ -54,6 +54,7 @@ enum GeomType {
|
||||
ARCOFCIRCLE,
|
||||
ELLIPSE,
|
||||
ARCOFELLIPSE,
|
||||
BEZIER,
|
||||
BSPLINE,
|
||||
GENERIC
|
||||
};
|
||||
@@ -70,7 +71,7 @@ class TechDrawExport BaseGeom
|
||||
edgeClass classOfEdge;
|
||||
bool visible;
|
||||
bool reversed;
|
||||
int ref3D;
|
||||
int ref3D; //obs?
|
||||
TopoDS_Edge occEdge; //projected Edge
|
||||
|
||||
std::vector<Base::Vector2D> findEndPoints();
|
||||
@@ -80,6 +81,7 @@ class TechDrawExport BaseGeom
|
||||
Base::Vector2D nearPoint(Base::Vector2D p);
|
||||
Base::Vector2D nearPoint(const BaseGeom* p);
|
||||
static BaseGeom* baseFactory(TopoDS_Edge edge);
|
||||
std::string dump();
|
||||
};
|
||||
|
||||
typedef std::vector<BaseGeom *> BaseGeomPtrVector;
|
||||
@@ -158,23 +160,18 @@ class TechDrawExport AOC: public Circle
|
||||
double distToArc(Base::Vector3d p);
|
||||
};
|
||||
|
||||
/// Handles degree 1 to 3 Bezier segments
|
||||
/*!
|
||||
* \todo extend this to higher orders if necessary
|
||||
*/
|
||||
struct BezierSegment
|
||||
class TechDrawExport BezierSegment: public BaseGeom
|
||||
{
|
||||
/// Number of entries in pnts that are valid
|
||||
int poles;
|
||||
public:
|
||||
BezierSegment(const TopoDS_Edge &e);
|
||||
BezierSegment() {}
|
||||
~BezierSegment() = default;
|
||||
|
||||
/// Control points for this segment
|
||||
/*!
|
||||
* Note that first and last used points define the endpoints for this
|
||||
* segment, so when we know that a sequence of BezierSegment objects are
|
||||
* going to be strung together, then we only need to know the start of
|
||||
* the first element (or the end of the last element).
|
||||
*/
|
||||
Base::Vector2D pnts[4];
|
||||
int poles;
|
||||
int degree;
|
||||
|
||||
//Base::Vector2D pnts[4];
|
||||
std::vector<Base::Vector2D> pnts;
|
||||
};
|
||||
|
||||
class TechDrawExport BSpline: public BaseGeom
|
||||
|
||||
@@ -281,6 +281,10 @@ void GeometryObject::addGeomFromCompound(TopoDS_Shape edgeCompound, edgeClass ca
|
||||
continue;
|
||||
}
|
||||
base = BaseGeom::baseFactory(edge);
|
||||
if (base == nullptr) {
|
||||
Base::Console().Message("Error - GO::addGeomFromCompound - baseFactory failed for edge: %d\n",i);
|
||||
throw Base::Exception("GeometryObject::addGeomFromCompound - baseFactory failed");
|
||||
}
|
||||
base->classOfEdge = category;
|
||||
base->visible = visible;
|
||||
edgeGeom.push_back(base);
|
||||
@@ -352,182 +356,6 @@ void GeometryObject::addFaceGeom(Face* f)
|
||||
faceGeom.push_back(f);
|
||||
}
|
||||
|
||||
/////////////// bbox routines
|
||||
|
||||
Base::BoundBox3d GeometryObject::boundingBoxOfBspline(const BSpline *spline) const
|
||||
{
|
||||
Base::BoundBox3d bb;
|
||||
for (std::vector<BezierSegment>::const_iterator segItr( spline->segments.begin() );
|
||||
segItr != spline->segments.end(); ++segItr) {
|
||||
switch (segItr->poles) {
|
||||
case 0: // Degenerate, but safe ignore
|
||||
break;
|
||||
case 2: // Degenerate - straight line
|
||||
bb.Add(Base::Vector3d( segItr->pnts[1].fX,
|
||||
segItr->pnts[1].fY,
|
||||
0 ));
|
||||
// fall through
|
||||
case 1: // Degenerate - just a point
|
||||
bb.Add(Base::Vector3d( segItr->pnts[0].fX,
|
||||
segItr->pnts[0].fY,
|
||||
0 ));
|
||||
break;
|
||||
case 3: {
|
||||
double
|
||||
px[3] = { segItr->pnts[0].fX,
|
||||
segItr->pnts[1].fX,
|
||||
segItr->pnts[2].fX },
|
||||
py[3] = { segItr->pnts[0].fY,
|
||||
segItr->pnts[1].fY,
|
||||
segItr->pnts[2].fY },
|
||||
slns[4] = { 0, 1 }; // Consider the segment's end points
|
||||
|
||||
// if's are to prevent problems with divide-by-0
|
||||
if ((2 * px[1] - px[0] - px[2]) == 0) {
|
||||
slns[2] = -1;
|
||||
} else {
|
||||
slns[2] = (px[1] - px[0]) / (2 * px[1] - px[0] - px[2]);
|
||||
}
|
||||
if ((2 * py[1] - py[0] - py[2]) == 0) {
|
||||
slns[3] = -1;
|
||||
} else {
|
||||
slns[3] = (py[1] - py[0]) / (2 * py[1] - py[0] - py[2]);
|
||||
}
|
||||
|
||||
// evaluate B(t) at the endpoints and zeros
|
||||
for (int s(0); s < 4; ++s) {
|
||||
double t( slns[s] );
|
||||
if (t < 0 || t > 1) {
|
||||
continue;
|
||||
}
|
||||
double tx( px[0] * (1 - t) * (1 - t) +
|
||||
px[1] * 2 * (1 - t) * t +
|
||||
px[2] * t * t ),
|
||||
ty( py[0] * (1 - t) * (1 - t) +
|
||||
py[1] * 2 * (1 - t) * t +
|
||||
py[2] * t * t );
|
||||
bb.Add( Base::Vector3d(tx, ty, 0) );
|
||||
}
|
||||
} break;
|
||||
case 4: {
|
||||
double
|
||||
px[4] = { segItr->pnts[0].fX,
|
||||
segItr->pnts[1].fX,
|
||||
segItr->pnts[2].fX,
|
||||
segItr->pnts[3].fX },
|
||||
py[4] = { segItr->pnts[0].fY,
|
||||
segItr->pnts[1].fY,
|
||||
segItr->pnts[2].fY,
|
||||
segItr->pnts[3].fY },
|
||||
// If B(t) is the cubic Bezier, find t where B'(t) == 0
|
||||
//
|
||||
// For control points P0-P3, B'(t) works out to be:
|
||||
// B'(t) = t^2 * (-3P0 + 9P1 - 9P2 + 3P3) +
|
||||
// t * (6P0 - 12P1 + 6P2) +
|
||||
// 3 * (P1 - P0)
|
||||
//
|
||||
// So, we use the quadratic formula!
|
||||
ax = -3 * px[0] + 9 * px[1] - 9 * px[2] + 3 * px[3],
|
||||
ay = -3 * py[0] + 9 * py[1] - 9 * py[2] + 3 * py[3],
|
||||
bx = 6 * px[0] - 12 * px[1] + 6 * px[2],
|
||||
by = 6 * py[0] - 12 * py[1] + 6 * py[2],
|
||||
cx = 3 * px[1] - 3 * px[0],
|
||||
cy = 3 * py[1] - 3 * py[0],
|
||||
|
||||
slns[6] = { 0, 1 }; // Consider the segment's end points
|
||||
|
||||
// if's are to prevent problems with divide-by-0 and NaN
|
||||
if ( (2 * ax) == 0 || (bx * bx - 4 * ax * cx) < 0 ) {
|
||||
slns[2] = -1;
|
||||
slns[3] = -1;
|
||||
} else {
|
||||
slns[2] = (-bx + sqrt(bx * bx - 4 * ax * cx)) / (2 * ax);
|
||||
slns[3] = (-bx - sqrt(bx * bx - 4 * ax * cx)) / (2 * ax);
|
||||
}
|
||||
if ((2 * ay) == 0 || (by * by - 4 * ay * cy) < 0 ) {
|
||||
slns[4] = -1;
|
||||
slns[5] = -1;
|
||||
} else {
|
||||
slns[4] = (-by + sqrt(by * by - 4 * ay * cy)) / (2 * ay);
|
||||
slns[5] = (-by - sqrt(by * by - 4 * ay * cy)) / (2 * ay);
|
||||
}
|
||||
|
||||
// evaluate B(t) at the endpoints and zeros
|
||||
for (int s(0); s < 6; ++s) {
|
||||
double t( slns[s] );
|
||||
if (t < 0 || t > 1) {
|
||||
continue;
|
||||
}
|
||||
double tx( px[0] * (1 - t) * (1 - t) * (1 - t) +
|
||||
px[1] * 3 * (1 - t) * (1 - t) * t +
|
||||
px[2] * 3 * (1 - t) * t * t +
|
||||
px[3] * t * t * t ),
|
||||
ty( py[0] * (1 - t) * (1 - t) * (1 - t) +
|
||||
py[1] * 3 * (1 - t) * (1 - t) * t +
|
||||
py[2] * 3 * (1 - t) * t * t +
|
||||
py[3] * t * t * t );
|
||||
bb.Add( Base::Vector3d(tx, ty, 0) );
|
||||
}
|
||||
|
||||
} break;
|
||||
default:
|
||||
throw Base::Exception("Invalid degree bezier segment in GeometryObject::calcBoundingBox");
|
||||
}
|
||||
}
|
||||
return bb;
|
||||
}
|
||||
|
||||
Base::BoundBox3d GeometryObject::boundingBoxOfAoe(const Ellipse *aoe,
|
||||
double start,
|
||||
double end, bool cw) const
|
||||
{
|
||||
// Using the ellipse form:
|
||||
// (xc, yc) = centre of ellipse
|
||||
// phi = angle of ellipse major axis off X axis
|
||||
// a, b = half of major, minor axes
|
||||
//
|
||||
// x(theta) = xc + a*cos(theta)*cos(phi) - b*sin(theta)*sin(phi)
|
||||
// y(theta) = yc + a*cos(theta)*sin(phi) + b*sin(theta)*cos(phi)
|
||||
|
||||
double a (aoe->major / 2.0),
|
||||
b (aoe->minor / 2.0),
|
||||
phi (aoe->angle),
|
||||
xc (aoe->center.fX),
|
||||
yc (aoe->center.fY);
|
||||
|
||||
if (a == 0 || b == 0) {
|
||||
// Degenerate case - TODO: handle as line instead of throwing
|
||||
throw Base::Exception("Ellipse with invalid major axis in GeometryObject::boundingBoxOfAoe()");
|
||||
}
|
||||
|
||||
// Calculate points of interest for the bounding box. These are points
|
||||
// where d(x)/d(theta) and d(y)/d(theta) = 0 (where the x and y extremes
|
||||
// of the ellipse would be if it were complete), and arc endpoints.
|
||||
double testAngles[6] = { atan(tan(phi) * (-b / a)),
|
||||
testAngles[0] + M_PI };
|
||||
if (tan(phi) == 0) {
|
||||
testAngles[2] = M_PI / 2.0;
|
||||
testAngles[3] = 3.0 * M_PI / 2.0;
|
||||
} else {
|
||||
testAngles[2] = atan((1.0 / tan(phi)) * (b / a));
|
||||
testAngles[3] = testAngles[2] + M_PI;
|
||||
}
|
||||
testAngles[4] = start;
|
||||
testAngles[5] = end;
|
||||
|
||||
// Add extremes to bounding box, if they are within the arc
|
||||
Base::BoundBox3d bb;
|
||||
for (int ai(0); ai < 6; ++ai) {
|
||||
double theta(testAngles[ai]);
|
||||
if (isWithinArc(theta, start, end, cw) ) {
|
||||
bb.Add( Base::Vector3d(xc + a*cos(theta)*cos(phi) - b*sin(theta)*sin(phi),
|
||||
yc + a*cos(theta)*sin(phi) - b*sin(theta)*cos(phi),
|
||||
0) );
|
||||
}
|
||||
}
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
||||
bool GeometryObject::isWithinArc(double theta, double first,
|
||||
double last, bool cw) const
|
||||
@@ -569,78 +397,19 @@ bool GeometryObject::isWithinArc(double theta, double first,
|
||||
|
||||
Base::BoundBox3d GeometryObject::calcBoundingBox() const
|
||||
{
|
||||
Base::BoundBox3d bbox;
|
||||
|
||||
// First calculate bounding box based on vertices
|
||||
for(std::vector<Vertex *>::const_iterator it( vertexGeom.begin() );
|
||||
it != vertexGeom.end(); ++it) {
|
||||
bbox.Add( Base::Vector3d((*it)->pnt.fX, (*it)->pnt.fY, 0.) );
|
||||
}
|
||||
|
||||
// Now, consider geometry where vertices don't define bounding box eg circles
|
||||
Bnd_Box testBox;
|
||||
testBox.SetGap(0.0);
|
||||
for (std::vector<BaseGeom *>::const_iterator it( edgeGeom.begin() );
|
||||
it != edgeGeom.end(); ++it) {
|
||||
switch ((*it)->geomType) {
|
||||
case CIRCLE: {
|
||||
Circle *c = static_cast<Circle *>(*it);
|
||||
bbox.Add( Base::BoundBox3d(-c->radius + c->center.fX,
|
||||
-c->radius + c->center.fY,
|
||||
0,
|
||||
c->radius + c->center.fX,
|
||||
c->radius + c->center.fY,
|
||||
0) );
|
||||
} break;
|
||||
|
||||
case ARCOFCIRCLE: {
|
||||
AOC *arc = static_cast<AOC *>(*it);
|
||||
|
||||
// Endpoints of arc
|
||||
bbox.Add( Base::Vector3d(arc->radius * cos(arc->startAngle),
|
||||
arc->radius * sin(arc->startAngle),
|
||||
0.0) );
|
||||
bbox.Add( Base::Vector3d(arc->radius * cos(arc->endAngle),
|
||||
arc->radius * sin(arc->endAngle),
|
||||
0.0) );
|
||||
|
||||
// Extreme X and Y values if they're within the arc
|
||||
for (double theta = 0.0; theta < 6.5; theta += M_PI / 2.0) {
|
||||
if (isWithinArc(theta, arc->startAngle, arc->endAngle, arc->cw)) {
|
||||
bbox.Add( Base::Vector3d(arc->radius * cos(theta),
|
||||
arc->radius * sin(theta),
|
||||
0.0) );
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case ELLIPSE: {
|
||||
bbox.Add( boundingBoxOfAoe(static_cast<Ellipse *>(*it)) );
|
||||
} break;
|
||||
|
||||
case ARCOFELLIPSE: {
|
||||
AOE *aoe = static_cast<AOE *>(*it);
|
||||
double start = aoe->startAngle,
|
||||
end = aoe->endAngle;
|
||||
bool cw = aoe->cw;
|
||||
bbox.Add( boundingBoxOfAoe(static_cast<Ellipse *>(*it), start, end, cw) );
|
||||
} break;
|
||||
|
||||
case BSPLINE: {
|
||||
bbox.Add( boundingBoxOfBspline(static_cast<BSpline *>(*it)) );
|
||||
} break;
|
||||
|
||||
case GENERIC: {
|
||||
// this case ends up just drawing line segments between points
|
||||
Generic *gen = static_cast<Generic *>(*it);
|
||||
for (std::vector<Base::Vector2D>::const_iterator segIt = gen->points.begin();
|
||||
segIt != gen->points.end(); ++segIt) {
|
||||
bbox.Add( Base::Vector3d(segIt->fX, segIt->fY, 0) );
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
throw Base::Exception("Unknown geomType in GeometryObject::calcBoundingBox()");
|
||||
}
|
||||
BRepBndLib::Add((*it)->occEdge, testBox);
|
||||
}
|
||||
if (testBox.IsVoid()) {
|
||||
Base::Console().Log("INFO - GO::calcBoundingBox - testBox is void\n");
|
||||
}
|
||||
double xMin,xMax,yMin,yMax,zMin,zMax;
|
||||
testBox.Get(xMin,yMin,zMin,xMax,yMax,zMax);
|
||||
|
||||
Base::BoundBox3d bbox(xMin,yMin,zMin,xMax,yMax,zMax);
|
||||
return bbox;
|
||||
}
|
||||
|
||||
@@ -762,4 +531,3 @@ TopoDS_Shape TechDrawGeometry::scaleShape(const TopoDS_Shape &input,
|
||||
}
|
||||
return transShape;
|
||||
}
|
||||
|
||||
|
||||
@@ -100,21 +100,8 @@ protected:
|
||||
|
||||
void addGeomFromCompound(TopoDS_Shape edgeCompound, edgeClass category, bool visible);
|
||||
|
||||
/// Helper for calcBoundingBox()
|
||||
/*! Note that the name of this function isn't totally accurate due to
|
||||
* TechDraw::Bsplines being composed of BezierSegments.
|
||||
*/
|
||||
Base::BoundBox3d boundingBoxOfBspline(const BSpline *spline) const;
|
||||
|
||||
/// Helper for calcBoundingBox()
|
||||
/*!
|
||||
* AOE = arc of ellipse. Defaults allow this to be used for regular
|
||||
* ellipses as well as arcs.
|
||||
*/
|
||||
Base::BoundBox3d boundingBoxOfAoe(const Ellipse *aoe, double start = 0,
|
||||
double end = 2 * M_PI, bool cw = false) const;
|
||||
|
||||
/// Helper for boundingBoxOf(Aoc|Aoe)()
|
||||
//similar function in Geometry?
|
||||
/*!
|
||||
* Returns true iff angle theta is in [first, last], where the arc goes
|
||||
* clockwise (cw=true) or counterclockwise (cw=false) from first to last.
|
||||
|
||||
@@ -147,11 +147,11 @@ QPainterPath QGIViewPart::drawPainterPath(TechDrawGeometry::BaseGeom *baseGeom)
|
||||
case TechDrawGeometry::ARCOFCIRCLE: {
|
||||
TechDrawGeometry::AOC *geom = static_cast<TechDrawGeometry::AOC *>(baseGeom);
|
||||
|
||||
//double x = geom->center.fX - geom->radius;
|
||||
//double y = geom->center.fY - geom->radius;
|
||||
pathArc(path, geom->radius, geom->radius, 0., geom->largeArc, geom->cw,
|
||||
geom->endPnt.fX, geom->endPnt.fY,
|
||||
geom->startPnt.fX, geom->startPnt.fY);
|
||||
// double x = geom->center.fX - geom->radius;
|
||||
// double y = geom->center.fY - geom->radius;
|
||||
//Base::Console().Message("TRACE -drawPainterPath - making an ARCOFCIRCLE @(%.3f,%.3f) R:%.3f\n",x, y, geom->radius);
|
||||
} break;
|
||||
case TechDrawGeometry::ELLIPSE: {
|
||||
@@ -169,7 +169,7 @@ QPainterPath QGIViewPart::drawPainterPath(TechDrawGeometry::BaseGeom *baseGeom)
|
||||
pathArc(path, geom->major, geom->minor, geom->angle, false, false,
|
||||
startX, startY, endX, endY);
|
||||
|
||||
//Base::Console().Message("TRACE -drawPainterPath - making an ELLIPSE @(%.3f,%.3f) R1:%.3f R2:%.3f\n",x, y, geom->major, geom->minor);
|
||||
//Base::Console().Message("TRACE -drawPainterPath - making an ELLIPSE @(%.3f,%.3f) R1:%.3f R2:%.3f\n",geom->center.fX,geom->center.fY, geom->major, geom->minor);
|
||||
} break;
|
||||
case TechDrawGeometry::ARCOFELLIPSE: {
|
||||
TechDrawGeometry::AOE *geom = static_cast<TechDrawGeometry::AOE *>(baseGeom);
|
||||
@@ -180,6 +180,33 @@ QPainterPath QGIViewPart::drawPainterPath(TechDrawGeometry::BaseGeom *baseGeom)
|
||||
//Base::Console().Message("TRACE -drawPainterPath - making an ARCOFELLIPSE R1:%.3f R2:%.3f From: (%.3f,%.3f) To: (%.3f,%.3f)\n",geom->major, geom->minor,geom->startPnt.fX, geom->startPnt.fY,geom->endPnt.fX, geom->endPnt.fY);
|
||||
|
||||
} break;
|
||||
case TechDrawGeometry::BEZIER: {
|
||||
TechDrawGeometry::BezierSegment *geom = static_cast<TechDrawGeometry::BezierSegment *>(baseGeom);
|
||||
|
||||
// Move painter to the beginning
|
||||
path.moveTo(geom->pnts[0].fX, geom->pnts[0].fY);
|
||||
//Base::Console().Message("TRACE -drawPainterPath - making an BEZIER From: (%.3f,%.3f)\n",geom->pnts[0].fX,geom->pnts[0].fY);
|
||||
|
||||
if ( geom->poles == 2 ) {
|
||||
// Degree 1 bezier = straight line...
|
||||
path.lineTo(geom->pnts[1].fX, geom->pnts[1].fY);
|
||||
|
||||
} else if ( geom->poles == 3 ) {
|
||||
path.quadTo(geom->pnts[1].fX, geom->pnts[1].fY,
|
||||
geom->pnts[2].fX, geom->pnts[2].fY);
|
||||
|
||||
} else if ( geom->poles == 4 ) {
|
||||
path.cubicTo(geom->pnts[1].fX, geom->pnts[1].fY,
|
||||
geom->pnts[2].fX, geom->pnts[2].fY,
|
||||
geom->pnts[3].fX, geom->pnts[3].fY);
|
||||
} else { //can only handle lines,quads,cubes
|
||||
Base::Console().Error("Bad pole count (%d) for BezierSegment\n",geom->poles);
|
||||
auto itBez = geom->pnts.begin() + 1;
|
||||
for (; itBez != geom->pnts.end();itBez++) {
|
||||
path.lineTo((*itBez).fX, (*itBez).fY); //show something for debugging
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case TechDrawGeometry::BSPLINE: {
|
||||
TechDrawGeometry::BSpline *geom = static_cast<TechDrawGeometry::BSpline *>(baseGeom);
|
||||
|
||||
@@ -364,10 +391,10 @@ void QGIViewPart::drawViewPart()
|
||||
}
|
||||
item->setPrettyNormal();
|
||||
//debug a path
|
||||
//QPainterPath edgePath=drawPainterPath(*itEdge);
|
||||
//std::stringstream edgeId;
|
||||
//edgeId << "QGIVP.edgePath" << i;
|
||||
//dumpPath(edgeId.str().c_str(),edgePath);
|
||||
// QPainterPath edgePath=drawPainterPath(*itEdge);
|
||||
// std::stringstream edgeId;
|
||||
// edgeId << "QGIVP.edgePath" << i;
|
||||
// dumpPath(edgeId.str().c_str(),edgePath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -760,7 +787,7 @@ void QGIViewPart::dumpPath(const char* text,QPainterPath path)
|
||||
} else if (elem.isCurveTo()) {
|
||||
typeName = "CurveTo";
|
||||
} else {
|
||||
typeName = "Unknown";
|
||||
typeName = "CurveData";
|
||||
}
|
||||
Base::Console().Message(">>>>> element %d: type:%d/%s pos(%.3f,%.3f) M:%d L:%d C:%d\n",iElem,
|
||||
elem.type,typeName,elem.x,elem.y,elem.isMoveTo(),elem.isLineTo(),elem.isCurveTo());
|
||||
|
||||
Reference in New Issue
Block a user