std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(
attribute(RESULT_VALUES_ID()))->setSize(0);
}
- if (theID != RESULT_ID()) {
+ else if (theID != RESULT_ID() &&
+ theID != RESULT_VALUES_ID()) {
std::string aKind = string(MEASURE_KIND())->value();
if (aKind == MEASURE_LENGTH())
computeLength();
else if (aKind == MEASURE_DISTANCE())
computeDistance();
+ else if (aKind == MEASURE_PROXIMITY())
+ computeProximity();
else if (aKind == MEASURE_RADIUS())
computeRadius();
else if (aKind == MEASURE_ANGLE())
aValues->setValue(0, aDistance);
}
+void FeaturesPlugin_Measurement::computeProximity()
+{
+ AttributeSelectionPtr aFirstFeature = selection(DISTANCE_FROM_OBJECT_ID());
+ GeomShapePtr aShape1;
+ if (aFirstFeature && aFirstFeature->isInitialized()) {
+ aShape1 = aFirstFeature->value();
+ if (!aShape1 && aFirstFeature->context())
+ aShape1 = aFirstFeature->context()->shape();
+ }
+
+ AttributeSelectionPtr aSecondFeature = selection(DISTANCE_TO_OBJECT_ID());
+ GeomShapePtr aShape2;
+ if (aSecondFeature && aSecondFeature->isInitialized()) {
+ aShape2 = aSecondFeature->value();
+ if (!aShape2 && aSecondFeature->context())
+ aShape2 = aSecondFeature->context()->shape();
+ }
+
+ if (!aShape1 || !aShape2) {
+ string(RESULT_ID())->setValue("");
+ return;
+ }
+
+ double aDistance = GeomAlgoAPI_ShapeTools::shapeProximity(aShape1, aShape2);
+
+ std::ostringstream anOutput;
+ anOutput << "Proximity = " << std::setprecision(10) << aDistance;
+ string(RESULT_ID())->setValue(anOutput.str());
+
+ AttributeDoubleArrayPtr aValues =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(attribute(RESULT_VALUES_ID()));
+ aValues->setSize(1);
+ aValues->setValue(0, aDistance);
+}
+
void FeaturesPlugin_Measurement::computeRadius()
{
AttributeSelectionPtr aSelectedFeature = selection(CIRCULAR_OBJECT_ID());
# reference data
REF_DATA = [(model.selection("VERTEX", "PartSet/Origin"),
model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]"),
- 122.4744871),
+ 122.4744871,
+ "NA"),
(model.selection("EDGE", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]"),
model.selection("VERTEX", "Sketch_2/SketchArc_1"),
- 36.94403089),
+ 36.94403089,
+ "NA"),
(model.selection("EDGE", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/From_Face]"),
model.selection("EDGE", "([Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/From_Face])([Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face])([Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/From_Face])([Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face])"),
- 0),
+ 0,
+ 60),
(model.selection("EDGE", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/From_Face]"),
model.selection("EDGE", "[Extrusion_2_1/Generated_Face&Sketch_2/SketchArc_1_2][Extrusion_2_1/To_Face]"),
- 16.00781059),
+ 16.00781059,
+ 176.710217655),
(model.selection("EDGE", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/From_Face]"),
model.selection("FACE", "Extrusion_2_1/Generated_Face&Sketch_2/SketchArc_1_2"),
- 8.412291828),
+ 8.412291828,
+ 165.748725311),
(model.selection("VERTEX", "Sketch_1/SketchCircle_1_2__cc"),
model.selection("FACE", "Plane_1"),
- 35.35533906),
+ 35.35533906,
+ "NA"),
(model.selection("FACE", "Extrusion_2_2/From_Face"),
model.selection("FACE", "Extrusion_2_2/To_Face"),
+ 100,
100),
(model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2"),
model.selection("FACE", "Extrusion_2_1/Generated_Face&Sketch_2/SketchArc_1_2"),
- 0),
+ 0,
+ 165.748725311),
(model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2"),
model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_5"),
- 27.63932023),
+ 27.63932023,
+ 27.61462299114),
(model.selection("SOLID", "Extrusion_1_1"),
model.selection("FACE", "Extrusion_2_1/To_Face"),
- 12.5),
+ 12.5,
+ "NA"),
(model.selection("SOLID", "Extrusion_1_1"),
model.selection("SOLID", "Extrusion_2_1"),
- 0),
+ 0,
+ "NA"),
(model.selection("SOLID", "Extrusion_1_1"),
model.selection("SOLID", "Extrusion_2_2"),
- 87.5)
+ 87.5,
+ "NA")
]
for ref in REF_DATA:
dist = model.measureDistance(Part_1_doc, ref[0], ref[1])
assert(math.fabs(dist - ref[2]) < TOLERANCE), "Distance {} differs from expected value {}".format(dist, ref[2])
+ if ref[3] != "NA":
+ prox = model.shapeProximity(Part_1_doc, ref[0], ref[1])
+ assert(math.fabs(prox - ref[3]) < TOLERANCE), "Proximity {} differs from expected value {}".format(prox, ref[3])
model.end()
#include <BRepCheck_Analyzer.hxx>
#include <BRepExtrema_DistShapeShape.hxx>
#include <BRepExtrema_ExtCF.hxx>
+#include <BRepExtrema_ShapeProximity.hxx>
#include <BRepGProp.hxx>
+#include <BRepMesh_IncrementalMesh.hxx>
#include <BRepTools.hxx>
#include <BRepTools_WireExplorer.hxx>
#include <BRepTopAdaptor_FClass2d.hxx>
#include <BOPAlgo_Builder.hxx>
+#include <Extrema_GenLocateExtCS.hxx>
+#include <Extrema_GenLocateExtSS.hxx>
+#include <Extrema_LocateExtCC.hxx>
+
#include <Geom2d_Curve.hxx>
#include <Geom2d_Curve.hxx>
aDist.Perform();
return aDist;
};
+
+static void tessellateShape(const TopoDS_Shape& theShape)
+{
+ Standard_Boolean isTessellate = Standard_False;
+ TopLoc_Location aLoc;
+ for (TopExp_Explorer anExp(theShape, TopAbs_FACE); anExp.More() && !isTessellate; anExp.Next()) {
+ Handle(Poly_Triangulation) aTria = BRep_Tool::Triangulation(TopoDS::Face(anExp.Value()), aLoc);
+ isTessellate = aTria.IsNull();
+ }
+ for (TopExp_Explorer anExp(theShape, TopAbs_EDGE); anExp.More() && !isTessellate; anExp.Next()) {
+ Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D(TopoDS::Edge(anExp.Value()), aLoc);
+ isTessellate = aPoly.IsNull();
+ }
+
+ if (isTessellate) {
+ BRepMesh_IncrementalMesh aMesher(theShape, 0.1);
+ Standard_ProgramError_Raise_if(!aMesher.IsDone(), "Meshing failed");
+ }
+}
+
+static Standard_Real paramOnCurve(const BRepAdaptor_Curve& theCurve,
+ const gp_Pnt& thePoint,
+ const Standard_Real theTol)
+{
+ Extrema_ExtPC aParamSearch(thePoint,
+ theCurve,
+ theCurve.FirstParameter(),
+ theCurve.LastParameter());
+ if (aParamSearch.IsDone()) {
+ Standard_Integer anIndMin = 0, aNbExt = aParamSearch.NbExt();
+ Standard_Real aSqDistMin = RealLast();
+ for (Standard_Integer i = 1; i <= aNbExt; ++i) {
+ if (aParamSearch.SquareDistance(i) < aSqDistMin) {
+ anIndMin = i;
+ aSqDistMin = aParamSearch.SquareDistance(i);
+ }
+ }
+ if (anIndMin != 0 && aSqDistMin <= theTol * theTol)
+ return aParamSearch.Point(anIndMin).Parameter();
+ }
+ return 0.5 * (theCurve.FirstParameter() + theCurve.LastParameter());
}
+static void paramsOnSurf(const BRepAdaptor_Surface& theSurf,
+ const gp_Pnt& thePoint,
+ const Standard_Real theTol,
+ Standard_Real& theU,
+ Standard_Real& theV)
+{
+ Extrema_ExtPS aParamSearch(thePoint, theSurf, Precision::PConfusion(), Precision::PConfusion());
+ if (aParamSearch.IsDone()) {
+ Standard_Integer anIndMin = 0, aNbExt = aParamSearch.NbExt();
+ Standard_Real aSqDistMin = RealLast();
+ for (Standard_Integer i = 1; i <= aNbExt; ++i) {
+ if (aParamSearch.SquareDistance(i) < aSqDistMin) {
+ anIndMin = i;
+ aSqDistMin = aParamSearch.SquareDistance(i);
+ }
+ }
+ if (anIndMin != 0 && aSqDistMin <= theTol * theTol)
+ return aParamSearch.Point(anIndMin).Parameter(theU, theV);
+ }
+ theU = 0.5 * (theSurf.FirstUParameter() + theSurf.LastUParameter());
+ theV = 0.5 * (theSurf.FirstVParameter() + theSurf.LastVParameter());
+}
+
+static Standard_Real extremaEE(const TopoDS_Edge& theEdge1,
+ const TopoDS_Edge& theEdge2,
+ const gp_Pnt& thePoint1,
+ const gp_Pnt& thePoint2)
+{
+ BRepAdaptor_Curve aCurve1(theEdge1);
+ BRepAdaptor_Curve aCurve2(theEdge2);
+
+ Standard_Real aU1 = paramOnCurve(aCurve1, thePoint1, BRep_Tool::Tolerance(theEdge1));
+ Standard_Real aU2 = paramOnCurve(aCurve2, thePoint2, BRep_Tool::Tolerance(theEdge2));
+
+ Standard_Real aValue = -1.0;
+ Extrema_LocateExtCC anExtr(aCurve1, aCurve2, aU1, aU2);
+ if (anExtr.IsDone() && aValue > Precision::Confusion())
+ aValue = Sqrt(anExtr.SquareDistance());
+ return aValue;
+}
+
+static Standard_Real extremaEF(const TopoDS_Edge& theEdge,
+ const TopoDS_Face& theFace,
+ const gp_Pnt& thePonE,
+ const gp_Pnt& thePonF)
+{
+ BRepAdaptor_Curve aCurve(theEdge);
+ BRepAdaptor_Surface aSurf(theFace);
+
+ Standard_Real aP = paramOnCurve(aCurve, thePonE, BRep_Tool::Tolerance(theEdge));
+ Standard_Real aU, aV;
+ paramsOnSurf(aSurf, thePonF, BRep_Tool::Tolerance(theFace), aU, aV);
+
+ Standard_Real aValue = -1.0;
+ Extrema_GenLocateExtCS anExtr(aCurve, aSurf, aP, aU, aV, Precision::PConfusion(), Precision::PConfusion());
+ if (anExtr.IsDone() && aValue > Precision::Confusion())
+ aValue = Sqrt(anExtr.SquareDistance());
+ return aValue;
+}
+
+static Standard_Real extremaFF(const TopoDS_Face& theFace1,
+ const TopoDS_Face& theFace2,
+ const gp_Pnt& thePoint1,
+ const gp_Pnt& thePoint2)
+{
+ BRepAdaptor_Surface aSurf1(theFace1);
+ BRepAdaptor_Surface aSurf2(theFace2);
+
+ Standard_Real aU1, aV1;
+ paramsOnSurf(aSurf1, thePoint1, BRep_Tool::Tolerance(theFace1), aU1, aV1);
+ Standard_Real aU2, aV2;
+ paramsOnSurf(aSurf2, thePoint2, BRep_Tool::Tolerance(theFace2), aU2, aV2);
+
+ Standard_Real aValue = -1.0;
+ Extrema_GenLocateExtSS anExtr(aSurf1, aSurf2, aU1, aV1, aU2, aV2, Precision::PConfusion(), Precision::PConfusion());
+ if (anExtr.IsDone() && aValue > Precision::Confusion())
+ aValue = Sqrt(anExtr.SquareDistance());
+ return aValue;
+}
+
+} // namespace
+
double GeomAlgoAPI_ShapeTools::minimalDistance(const GeomShapePtr& theShape1,
const GeomShapePtr& theShape2)
{
return aDist.IsDone() ? aDist.Value() : Precision::Infinite();
}
+//==================================================================================================
+double GeomAlgoAPI_ShapeTools::shapeProximity(const GeomShapePtr& theShape1,
+ const GeomShapePtr& theShape2)
+{
+ double aResult = Precision::Infinite();
+ if (!theShape1.get() || !theShape2.get())
+ return aResult;
+
+ const TopoDS_Shape& aShape1 = theShape1->impl<TopoDS_Shape>();
+ const TopoDS_Shape& aShape2 = theShape2->impl<TopoDS_Shape>();
+
+ TopAbs_ShapeEnum aType1 = aShape1.ShapeType();
+ TopAbs_ShapeEnum aType2 = aShape2.ShapeType();
+
+ // tessellate shapes if there is no mesh exists
+ tessellateShape(aShape1);
+ tessellateShape(aShape2);
+
+ BRepExtrema_ShapeProximity aDist (aShape1, aShape2);
+ aDist.Perform();
+ if (aDist.IsDone()) {
+ aResult = aDist.Proximity();
+
+ // refine the result
+ const gp_Pnt& aPonS1 = aDist.ProximityPoint1();
+ const gp_Pnt& aPonS2 = aDist.ProximityPoint2();
+
+ double anExtrema = -1.0;
+ if (aType1 == TopAbs_EDGE)
+ {
+ if (aType2 == TopAbs_EDGE)
+ anExtrema = extremaEE(TopoDS::Edge(aShape1), TopoDS::Edge(aShape2), aPonS1, aPonS2);
+ else if (aType2 == TopAbs_FACE)
+ anExtrema = extremaEF(TopoDS::Edge(aShape1), TopoDS::Face(aShape2), aPonS1, aPonS2);
+ }
+ else if (aType1 == TopAbs_FACE)
+ {
+ if (aType2 == TopAbs_EDGE)
+ anExtrema = extremaEF(TopoDS::Edge(aShape2), TopoDS::Face(aShape1), aPonS2, aPonS1);
+ else if (aType2 == TopAbs_FACE)
+ anExtrema = extremaFF(TopoDS::Face(aShape1), TopoDS::Face(aShape2), aPonS1, aPonS2);
+ }
+ if (anExtrema > 0.0)
+ aResult = anExtrema;
+ }
+ return aResult;
+}
+
//==================================================================================================
std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
const std::shared_ptr<GeomAPI_Shape> theCompound,