From a77927df4517b2ad5f55402ea7226a7ada49df18 Mon Sep 17 00:00:00 2001 From: Artem Zhidkov Date: Wed, 13 May 2020 19:04:04 +0300 Subject: [PATCH] Issue #19058: Error in sketch projection when changing parameter Fix crash on Linux, when loading HDF then changing parameter --- src/GeomAlgoAPI/GeomAlgoAPI_NExplode.cpp | 205 +++++++++++++--------- src/GeomAlgoAPI/GeomAlgoAPI_NExplode.h | 25 ++- src/Selector/CMakeLists.txt | 2 + src/Selector/Selector_NExplode.cpp | 211 +++++------------------ src/Selector/Selector_NExplode.h | 10 +- 5 files changed, 185 insertions(+), 268 deletions(-) diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_NExplode.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_NExplode.cpp index 58333bf27..c36623ad0 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_NExplode.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_NExplode.cpp @@ -19,150 +19,176 @@ #include "GeomAlgoAPI_NExplode.h" -#include +#include +#include + +#include #include -#include -#include +#include #include -#include +#include #include -#include -#include -#include -#include +#include +#include -#include #include +#include +#include -static std::pair ShapeToDouble (const TopoDS_Shape& S) +namespace NExplodeTools { - // Computing of CentreOfMass - gp_Pnt GPoint; - double Len; + void dummy(gp_Pnt&) + { + // do nothing (new approach to order shapes) + } - if (S.ShapeType() == TopAbs_VERTEX) { - GPoint = BRep_Tool::Pnt(TopoDS::Vertex(S)); - Len = (double)S.Orientation(); + void pointToDouble(gp_Pnt& thePoint) + { + // old approach to order shapes + double dMidXYZ = thePoint.X() * 999.0 + thePoint.Y() * 99.0 + thePoint.Z() * 0.9; + thePoint.SetCoord(dMidXYZ, 0.0, 0.0); } - else { - GProp_GProps GPr; - if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) { - BRepGProp::LinearProperties(S, GPr); - } - else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) { - BRepGProp::SurfaceProperties(S, GPr); + + std::pair ShapeToDouble(const GeomShapePtr& theShape, + void(*convertPoint)(gp_Pnt&)) + { + // Computing of CentreOfMass + gp_Pnt GPoint; + double Len; + + TopoDS_Shape S = theShape->impl(); + if (S.ShapeType() == TopAbs_VERTEX) { + GPoint = BRep_Tool::Pnt(TopoDS::Vertex(S)); + Len = (double)S.Orientation(); } else { - BRepGProp::VolumeProperties(S, GPr); + GProp_GProps GPr; + if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) { + BRepGProp::LinearProperties(S, GPr); + } + else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) { + BRepGProp::SurfaceProperties(S, GPr); + } + else { + BRepGProp::VolumeProperties(S, GPr); + } + GPoint = GPr.CentreOfMass(); + Len = GPr.Mass(); } - GPoint = GPr.CentreOfMass(); - Len = GPr.Mass(); - } - double dMidXYZ = GPoint.X() * 999.0 + GPoint.Y() * 99.0 + GPoint.Z() * 0.9; - return std::make_pair(dMidXYZ, Len); -} + (*convertPoint)(GPoint); + GeomPointPtr aMidPoint(new GeomAPI_Pnt(GPoint.X(), GPoint.Y(), GPoint.Z())); + return std::make_pair(aMidPoint, Len); + } -/*! -* \brief Sort shapes in the list by their coordinates. -*/ -struct CompareShapes : public std::binary_function -{ - typedef NCollection_DataMap > DataMapOfShapeDouble; + /*! + * \brief Sort shapes in the list by their coordinates. + */ + struct CompareShapes : public std::binary_function + { + typedef std::unordered_map, + GeomAPI_Shape::Hash, + GeomAPI_Shape::Equal > DataMapOfShapeDouble; - CompareShapes(DataMapOfShapeDouble* theCashMap) : myMap(theCashMap) {} + CompareShapes(void(*convertPoint)(gp_Pnt&)) + : myConvertPoint(convertPoint) {} - bool operator() (const TopoDS_Shape& lhs, const TopoDS_Shape& rhs); + bool operator() (const GeomShapePtr& lhs, const GeomShapePtr& rhs); - DataMapOfShapeDouble* myMap; -}; + DataMapOfShapeDouble myMap; + void(*myConvertPoint)(gp_Pnt&); + }; +} -bool CompareShapes::operator() (const TopoDS_Shape& theShape1, - const TopoDS_Shape& theShape2) +bool NExplodeTools::CompareShapes::operator() (const GeomShapePtr& lhs, const GeomShapePtr& rhs) { - if (!myMap->IsBound(theShape1)) { - myMap->Bind(theShape1, ShapeToDouble(theShape1)); + if (myMap.find(lhs) == myMap.end()) { + myMap[lhs] = ShapeToDouble(lhs, myConvertPoint); } - if (!myMap->IsBound(theShape2)) { - myMap->Bind(theShape2, ShapeToDouble(theShape2)); + if (myMap.find(rhs) == myMap.end()) { + myMap[rhs] = ShapeToDouble(rhs, myConvertPoint); } - std::pair val1 = myMap->Find(theShape1); - std::pair val2 = myMap->Find(theShape2); + const std::pair& val1 = myMap.at(lhs); + const std::pair& val2 = myMap.at(rhs); - double tol = Precision::Confusion(); + double tol = 10.0 * Precision::Confusion(); bool exchange = Standard_False; - double dMidXYZ = val1.first - val2.first; - if (dMidXYZ >= tol) { + // compare coordinates of center points + if (val2.first->isLess(val1.first, tol)) { exchange = Standard_True; } - else if (Abs(dMidXYZ) < tol) { + else if (!val1.first->isLess(val2.first, tol)) { double dLength = val1.second - val2.second; if (dLength >= tol) { exchange = Standard_True; } - else if (Abs(dLength) < tol && theShape1.ShapeType() <= TopAbs_FACE) { + else if (Abs(dLength) < tol && lhs->shapeType() <= GeomAPI_Shape::FACE) { // equal values possible on shapes such as two halves of a sphere and // a membrane inside the sphere - Bnd_Box box1,box2; - BRepBndLib::Add(theShape1, box1); + Bnd_Box box1, box2; + BRepBndLib::Add(lhs->impl(), box1); if (!box1.IsVoid()) { - BRepBndLib::Add(theShape2, box2); + BRepBndLib::Add(rhs->impl(), box2); Standard_Real dSquareExtent = box1.SquareExtent() - box2.SquareExtent(); if (dSquareExtent >= tol) { exchange = Standard_True; } else if (Abs(dSquareExtent) < tol) { - Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, val1, val2; + Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, value1, value2; box1.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); - val1 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9; + value1 = (aXmin + aXmax)*999.0 + (aYmin + aYmax)*99.0 + (aZmin + aZmax)*0.9; box2.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); - val2 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9; - if ((val1 - val2) >= tol) { + value2 = (aXmin + aXmax)*999.0 + (aYmin + aYmax)*99.0 + (aZmin + aZmax)*0.9; + if (value1 - value2 >= tol) { exchange = Standard_True; } - else // compare adresses if shapes are geometrically equal - exchange = theShape1.TShape().get() > theShape2.TShape().get(); + else { // compare adresses if shapes are geometrically equal + exchange = lhs->impl().TShape().get() > + rhs->impl().TShape().get(); + } } } - } else // compare adresses if shapes are geometrically equal - exchange = theShape1.TShape().get() > theShape2.TShape().get(); + } + else { // compare adresses if shapes are geometrically equal + exchange = lhs->impl().TShape().get() > + rhs->impl().TShape().get(); + } } //return val1 < val2; return !exchange; } -GeomAlgoAPI_NExplode::GeomAlgoAPI_NExplode( - const GeomShapePtr theContext, const GeomAPI_Shape::ShapeType theShapeType) +GeomAlgoAPI_NExplode::GeomAlgoAPI_NExplode(const GeomShapePtr theContext, + const GeomAPI_Shape::ShapeType theShapeType, + const ShapeOrder theOrder) { - std::vector aShapesVec; - - const TopoDS_Shape& aContext = theContext->impl(); - TopExp_Explorer anExp(aContext, (TopAbs_ShapeEnum)theShapeType); - TopTools_MapOfShape aMapShape; - for(; anExp.More(); anExp.Next()) { - if (aMapShape.Add(anExp.Current())) - aShapesVec.push_back(anExp.Current()); + std::set aMapShape; + GeomAPI_ShapeExplorer anExp(theContext, theShapeType); + for (; anExp.more(); anExp.next()) { + GeomShapePtr aCurrent = anExp.current(); + if (aMapShape.find(aCurrent) == aMapShape.end()) { + mySorted.push_back(aCurrent); + aMapShape.insert(aCurrent); + } } + reorder(theOrder); +} - CompareShapes::DataMapOfShapeDouble aCash; - CompareShapes shComp(&aCash); - std::stable_sort(aShapesVec.begin(), aShapesVec.end(), shComp); - - std::vector::const_iterator anIter = aShapesVec.begin(); - for (; anIter != aShapesVec.end(); ++anIter) { - GeomShapePtr aShapePtr(new GeomAPI_Shape); - aShapePtr->setImpl(new TopoDS_Shape(*anIter)); - mySorted.push_back(aShapePtr); - } +GeomAlgoAPI_NExplode::GeomAlgoAPI_NExplode(const ListOfShape& theShapes, + const ShapeOrder theOrder) + : mySorted(theShapes.begin(), theShapes.end()) +{ + reorder(theOrder); } int GeomAlgoAPI_NExplode::index(const GeomShapePtr theSubShape) { - ListOfShape::iterator anIter = mySorted.begin(); + std::vector::iterator anIter = mySorted.begin(); for(int anIndex = 1; anIter != mySorted.end(); anIter++, anIndex++) { if ((*anIter)->isSame(theSubShape)) return anIndex; @@ -172,10 +198,17 @@ int GeomAlgoAPI_NExplode::index(const GeomShapePtr theSubShape) GeomShapePtr GeomAlgoAPI_NExplode::shape(const int theIndex) { - ListOfShape::iterator anIter = mySorted.begin(); + std::vector::iterator anIter = mySorted.begin(); for(int anIndex = 1; anIter != mySorted.end(); anIter++, anIndex++) { if (anIndex == theIndex) return *anIter; } return GeomShapePtr(); // not found } + +void GeomAlgoAPI_NExplode::reorder(const ShapeOrder theNewOrder) +{ + NExplodeTools::CompareShapes shComp( + theNewOrder == ORDER_BY_HASH_VALUE ? NExplodeTools::pointToDouble : NExplodeTools::dummy); + std::stable_sort(mySorted.begin(), mySorted.end(), shComp); +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_NExplode.h b/src/GeomAlgoAPI/GeomAlgoAPI_NExplode.h index 81870ddaa..006a3fdaf 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_NExplode.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_NExplode.h @@ -24,6 +24,8 @@ #include +#include + /// \class GeomAlgoAPI_NExplode /// \ingroup DataAlgo /// \brief Sort shapes by their centers of mass, using formula X*999 + Y*99 + Z*0.9. @@ -31,18 +33,33 @@ /// Used for getting index of sub0shape in WeakNaming algorithm. class GeomAlgoAPI_NExplode { - public: +public: + /// Different orders of shape explosion + enum ShapeOrder { + ORDER_BY_HASH_VALUE, ///< kept for compatibility + ORDER_BY_MIDDLE_POINT ///< modern approach comparing middle points of shapes + }; + +public: /// \brief Initializes the sorted list of shapes by the context shape and type of sub-shapes. - GEOMALGOAPI_EXPORT GeomAlgoAPI_NExplode( - const GeomShapePtr theContext, const GeomAPI_Shape::ShapeType theShapeType); + GEOMALGOAPI_EXPORT GeomAlgoAPI_NExplode(const GeomShapePtr theContext, + const GeomAPI_Shape::ShapeType theShapeType, + const ShapeOrder theOrder = ORDER_BY_MIDDLE_POINT); + + /// \brief Initializes the sorted list of shapes. + GEOMALGOAPI_EXPORT GeomAlgoAPI_NExplode(const ListOfShape& theShapes, + const ShapeOrder theOrder = ORDER_BY_MIDDLE_POINT); /// Returns an index (started from one) of sub-shape in the sorted list. Returns 0 if not found. GEOMALGOAPI_EXPORT int index(const GeomShapePtr theSubShape); /// Returns a shape by an index (started from one). Returns null if not found. GEOMALGOAPI_EXPORT GeomShapePtr shape(const int theIndex); + /// Reorder the shapes + GEOMALGOAPI_EXPORT void reorder(const ShapeOrder theNewOrder); + protected: - ListOfShape mySorted; + std::vector mySorted; }; #endif diff --git a/src/Selector/CMakeLists.txt b/src/Selector/CMakeLists.txt index ec8d88240..d3ab25d0a 100644 --- a/src/Selector/CMakeLists.txt +++ b/src/Selector/CMakeLists.txt @@ -51,10 +51,12 @@ SET(PROJECT_SOURCES SET(PROJECT_LIBRARIES ${OpenCASCADE_ApplicationFramework_LIBRARIES} GeomAPI + GeomAlgoAPI ) SET(PROJECT_INCLUDES ${OpenCASCADE_INCLUDE_DIR} ../GeomAPI + ../GeomAlgoAPI ) diff --git a/src/Selector/Selector_NExplode.cpp b/src/Selector/Selector_NExplode.cpp index 2a69c2527..9ea2ba8d9 100644 --- a/src/Selector/Selector_NExplode.cpp +++ b/src/Selector/Selector_NExplode.cpp @@ -19,203 +19,70 @@ #include "Selector_NExplode.h" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static void dummy(gp_Pnt& thePoint) -{ - // do nothing (new approach to order shapes) -} - -static void pointToDouble(gp_Pnt& thePoint) +#include +#include + +////#include +////#include +////#include +////#include +////#include +////#include +////#include +////#include +////#include +////#include +////#include + +static GeomAlgoAPI_NExplode::ShapeOrder getOrder(const bool isOld) { - // old approach to order shapes - double dMidXYZ = thePoint.X() * 999.0 + thePoint.Y() * 99.0 + thePoint.Z() * 0.9; - thePoint.SetCoord(dMidXYZ, 0.0, 0.0); -} - -static std::pair ShapeToDouble (const TopoDS_Shape& S, - void (*convertPoint)(gp_Pnt&)) -{ - // Computing of CentreOfMass - gp_Pnt GPoint; - double Len; - - if (S.ShapeType() == TopAbs_VERTEX) { - GPoint = BRep_Tool::Pnt(TopoDS::Vertex(S)); - Len = (double)S.Orientation(); - } - else { - GProp_GProps GPr; - if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) { - BRepGProp::LinearProperties(S, GPr); - } - else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) { - BRepGProp::SurfaceProperties(S, GPr); - } - else { - BRepGProp::VolumeProperties(S, GPr); - } - GPoint = GPr.CentreOfMass(); - Len = GPr.Mass(); - } - - (*convertPoint)(GPoint); - return std::make_pair(GPoint, Len); + return isOld ? GeomAlgoAPI_NExplode::ORDER_BY_HASH_VALUE + : GeomAlgoAPI_NExplode::ORDER_BY_MIDDLE_POINT; } -/*! -* \brief Sort shapes in the list by their coordinates. -*/ -struct CompareShapes : public std::binary_function -{ - typedef NCollection_DataMap > DataMapOfShapeDouble; - - CompareShapes(DataMapOfShapeDouble* theCashMap, void (*convertPoint)(gp_Pnt&)) - : myMap(theCashMap), myConvertPoint(convertPoint) {} - - bool operator() (const TopoDS_Shape& lhs, const TopoDS_Shape& rhs); - - DataMapOfShapeDouble* myMap; - void (*myConvertPoint)(gp_Pnt&); -}; - -bool CompareShapes::operator() (const TopoDS_Shape& theShape1, - const TopoDS_Shape& theShape2) +static GeomShapePtr convertShape(const TopoDS_Shape& theShape) { - if (!myMap->IsBound(theShape1)) { - myMap->Bind(theShape1, ShapeToDouble(theShape1, myConvertPoint)); - } - - if (!myMap->IsBound(theShape2)) { - myMap->Bind(theShape2, ShapeToDouble(theShape2, myConvertPoint)); - } - - const std::pair& val1 = myMap->Find(theShape1); - const std::pair& val2 = myMap->Find(theShape2); - - double tol = 10.0 * Precision::Confusion(); - bool exchange = Standard_False; - - // compare coordinates of center points - GeomPointPtr aPnt1(new GeomAPI_Pnt(val1.first.X(), val1.first.Y(), val1.first.Z())); - GeomPointPtr aPnt2(new GeomAPI_Pnt(val2.first.X(), val2.first.Y(), val2.first.Z())); - if (aPnt2->isLess(aPnt1, tol)) { - exchange = Standard_True; - } - else if (!aPnt1->isLess(aPnt2, tol)) { - double dLength = val1.second - val2.second; - if (dLength >= tol) { - exchange = Standard_True; - } - else if (Abs(dLength) < tol && theShape1.ShapeType() <= TopAbs_FACE) { - // equal values possible on shapes such as two halves of a sphere and - // a membrane inside the sphere -// LCOV_EXCL_START - // this part of code is taken from GEOM module, but can not reproduce in SHAPER - Bnd_Box box1,box2; - BRepBndLib::Add(theShape1, box1); - if (!box1.IsVoid()) { - BRepBndLib::Add(theShape2, box2); - Standard_Real dSquareExtent = box1.SquareExtent() - box2.SquareExtent(); - if (dSquareExtent >= tol) { - exchange = Standard_True; - } - else if (Abs(dSquareExtent) < tol) { - Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, val1, val2; - box1.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); - val1 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9; - box2.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); - val2 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9; - if ((val1 - val2) >= tol) { - exchange = Standard_True; - } - } - } -// LCOV_EXCL_STOP - } else // compare addresses if shapes are geometrically equal - return theShape1.TShape().get() > theShape2.TShape().get(); - } - - //return val1 < val2; - return !exchange; + GeomShapePtr aNewShape(new GeomAPI_Shape); + aNewShape->setImpl(new TopoDS_Shape(theShape)); + return aNewShape; } Selector_NExplode::Selector_NExplode(const TopoDS_ListOfShape& theShapes, const bool theOldOrder) : myToBeReordered(theOldOrder) { - for(TopoDS_ListOfShape::Iterator anIter(theShapes); anIter.More(); anIter.Next()) { - mySorted.push_back(anIter.Value()); - } + ListOfShape aShapes; + for (TopoDS_ListOfShape::Iterator anIt(theShapes); anIt.More(); anIt.Next()) + aShapes.push_back(convertShape(anIt.Value())); - CompareShapes::DataMapOfShapeDouble aCash; - CompareShapes shComp(&aCash, theOldOrder ? pointToDouble : dummy); - std::stable_sort(mySorted.begin(), mySorted.end(), shComp); + mySorted = std::make_shared(aShapes, getOrder(theOldOrder)); } Selector_NExplode::Selector_NExplode(const TopoDS_Shape& theShape, const TopAbs_ShapeEnum theType, const bool theOldOrder) : myToBeReordered(theOldOrder) { - TopTools_MapOfShape anAdded; // to avoid same shapes duplication - for(TopExp_Explorer anExp(theShape, theType); anExp.More(); anExp.Next()) { - if (anAdded.Add(anExp.Current())) - mySorted.push_back(anExp.Current()); - } - - CompareShapes::DataMapOfShapeDouble aCash; - CompareShapes shComp(&aCash, theOldOrder ? pointToDouble : dummy); - std::stable_sort(mySorted.begin(), mySorted.end(), shComp); + GeomShapePtr aShape = convertShape(theShape); + GeomAPI_Shape::ShapeType aType = (GeomAPI_Shape::ShapeType)theType; + mySorted = std::make_shared(aShape, aType, getOrder(theOldOrder)); } int Selector_NExplode::index(const TopoDS_Shape& theSubShape) { - // reorder if necessary - reorder(); - - std::vector::iterator anIter = mySorted.begin(); - for(int anIndex = 1; anIter != mySorted.end(); anIter++, anIndex++) { - if ((*anIter).IsSame(theSubShape)) - return anIndex; - } - return -1; // not found + int anIndex = mySorted->index(convertShape(theSubShape)); + return anIndex > 0 ? anIndex : -1; // -1 if not found } TopoDS_Shape Selector_NExplode::shape(int& theIndex) { - std::vector::iterator anIter = mySorted.begin(); - for(int anIndex = 1; anIter != mySorted.end(); anIter++, anIndex++) { - if (anIndex == theIndex) { - TopoDS_Shape aShape = *anIter; - if (myToBeReordered) - theIndex = index(aShape); - return aShape; + TopoDS_Shape aResult; + GeomShapePtr aShape = mySorted->shape(theIndex); + if (aShape) { + aResult = aShape->impl(); + if (myToBeReordered) { + mySorted->reorder(GeomAlgoAPI_NExplode::ORDER_BY_MIDDLE_POINT); + theIndex = mySorted->index(aShape); } } - return TopoDS_Shape(); // not found -} - -void Selector_NExplode::reorder() -{ - if (!myToBeReordered) - return; - - myToBeReordered = false; - CompareShapes::DataMapOfShapeDouble aCash; - CompareShapes shComp(&aCash, dummy); - std::stable_sort(mySorted.begin(), mySorted.end(), shComp); + return aResult; } diff --git a/src/Selector/Selector_NExplode.h b/src/Selector/Selector_NExplode.h index 412620b8c..21fff0c3f 100644 --- a/src/Selector/Selector_NExplode.h +++ b/src/Selector/Selector_NExplode.h @@ -24,7 +24,9 @@ #include -#include +#include + +class GeomAlgoAPI_NExplode; /// \class Selector_NExplode /// \ingroup DataModel @@ -48,12 +50,8 @@ class Selector_NExplode /// Recompute the index if the old order was used. The value will contain the new ordered index. SELECTOR_EXPORT TopoDS_Shape shape(int& theIndex); -private: - /// Reorder list of shapes. - void reorder(); - protected: - std::vector mySorted; ///< keep the ordered list of shapes + std::shared_ptr mySorted; ///< keep the ordered list of shapes bool myToBeReordered; ///< the list has to be reordered }; -- 2.39.2