Create outline of 3D shape

This commit is contained in:
WandererFan
2016-11-05 12:05:40 -04:00
parent 06e8c6734d
commit dc66106683
11 changed files with 668 additions and 388 deletions

View File

@@ -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)