X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FBuildPlugin%2FBuildPlugin_Wire.cpp;h=f39e30d513dca5b4adfabc2f61aa9b519defb8fd;hb=06e7f5859095193fc7f498bd89a7d28009794f53;hp=4b7231a721a7589295d12e63f319b81d07310f3b;hpb=f98f887290d4e2b4bd6618389911e82b6b9674f3;p=modules%2Fshaper.git diff --git a/src/BuildPlugin/BuildPlugin_Wire.cpp b/src/BuildPlugin/BuildPlugin_Wire.cpp index 4b7231a72..f39e30d51 100644 --- a/src/BuildPlugin/BuildPlugin_Wire.cpp +++ b/src/BuildPlugin/BuildPlugin_Wire.cpp @@ -1,25 +1,54 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: BuildPlugin_Wire.cpp -// Created: 14 April 2016 -// Author: Dmitry Bobylev +// Copyright (C) 2014-2023 CEA, EDF +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// #include "BuildPlugin_Wire.h" +#include #include #include #include +#include +#include #include #include #include +#include -#include +#include +#include +#include +#include #include +#include + #include +static bool buildSketchWires(FeaturePtr theSketchFeature, GeomShapePtr theSketchShape, + bool isIntersect, + ListOfShape& theWires, GeomMakeShapePtr& theAlgo, + std::string& theError); + +static bool buildWire(const ListOfShape& theEdges, GeomShapePtr& theWire, std::string& theError); + //================================================================================================= BuildPlugin_Wire::BuildPlugin_Wire() { @@ -29,6 +58,9 @@ BuildPlugin_Wire::BuildPlugin_Wire() void BuildPlugin_Wire::initAttributes() { data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId()); + + data()->addAttribute(INTERSECT_ID(), ModelAPI_AttributeBoolean::typeId()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), INTERSECT_ID()); } //================================================================================================= @@ -45,13 +77,25 @@ void BuildPlugin_Wire::execute() return; } + AttributeBooleanPtr anIntersectAttr = boolean(INTERSECT_ID()); + bool isIntersect = anIntersectAttr->isInitialized() && anIntersectAttr->value(); + // Collect base shapes. ListOfShape anEdges; + std::list< std::pair > aSketches; for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) { AttributeSelectionPtr aSelection = aSelectionList->value(anIndex); GeomShapePtr aShape = aSelection->value(); if(!aShape.get()) { aShape = aSelection->context()->shape(); + + std::shared_ptr aSketchShape = + std::dynamic_pointer_cast(aShape); + if (aSketchShape) { + FeaturePtr aSketchFeature = ModelAPI_Feature::feature(aSelection->context()); + aSketches.push_back(std::pair(aSketchFeature, aSketchShape)); + continue; + } } for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) { GeomShapePtr anEdge = anExp.current(); @@ -59,27 +103,60 @@ void BuildPlugin_Wire::execute() } } - // Create wire. - GeomShapePtr aWire = GeomAlgoAPI_WireBuilder::wire(anEdges); - if(!aWire.get()) { - setError("Error: Result wire is empty. Probably it has disconnected edges or non-manifold."); - return; - } + int aResultIndex = 0; + std::string anError; - // Store result. - ResultBodyPtr aResultBody = document()->createBody(data()); - aResultBody->store(aWire); - for(GeomAPI_ShapeExplorer anExp(aWire, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) { - GeomShapePtr anEdgeInResult = anExp.current(); - for(ListOfShape::const_iterator anIt = anEdges.cbegin(); anIt != anEdges.cend(); ++anIt) { - std::shared_ptr anEdgeInList(new GeomAPI_Edge(*anIt)); - if(anEdgeInList->isEqual(anEdgeInResult)) { - aResultBody->modified(anEdgeInList, anEdgeInResult, "Edge"); - break; + if (!anEdges.empty()) { + // Create wire from the list of edges. + GeomShapePtr aWire; + if (!buildWire(anEdges, aWire, anError)) { + setError(anError); + return; + } + + // Store result. + ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex); + aResultBody->store(aWire); + for (GeomAPI_ShapeExplorer anExp(aWire, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) { + GeomShapePtr anEdgeInResult = anExp.current(); + for (ListOfShape::const_iterator anIt = anEdges.cbegin(); anIt != anEdges.cend(); ++anIt) { + std::shared_ptr anEdgeInList(new GeomAPI_Edge(*anIt)); + if (anEdgeInList->isEqual(anEdgeInResult)) { + if (anEdgeInList->isSame(anEdgeInResult)) + aResultBody->generated(anEdgeInResult, "Edge"); + else + aResultBody->modified(anEdgeInList, anEdgeInResult); + break; + } } } + setResult(aResultBody, aResultIndex); + ++aResultIndex; } - setResult(aResultBody); + + // create wires from sketches + for (std::list >::iterator anIt = aSketches.begin(); + anIt != aSketches.end(); ++anIt) { + ListOfShape aWires; + GeomMakeShapePtr aMakeShapeList; + if (!buildSketchWires(anIt->first, anIt->second, isIntersect, + aWires, aMakeShapeList, anError)) { + setError(anError); + return; + } + + for (ListOfShape::iterator aWIt = aWires.begin(); aWIt != aWires.end(); ++aWIt) { + ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex); + ListOfShape aSketch; + aSketch.push_back(anIt->second); + aResultBody->storeModified(aSketch, *aWIt, aMakeShapeList); + aResultBody->loadModifiedShapes(aMakeShapeList, anIt->second, GeomAPI_Shape::EDGE); + setResult(aResultBody, aResultIndex); + ++aResultIndex; + } + } + + removeResults(aResultIndex); } //================================================================================================= @@ -122,12 +199,14 @@ bool BuildPlugin_Wire::addContour() // Check that it is edge on sketch. ResultPtr aContext = aSelection->context(); - ResultConstructionPtr aConstruction = std::dynamic_pointer_cast(aContext); + ResultConstructionPtr aConstruction = + std::dynamic_pointer_cast(aContext); if(!aConstruction.get()) { continue; } GeomShapePtr aContextShape = aConstruction->shape(); - std::shared_ptr aPlanarEdges = std::dynamic_pointer_cast(aContextShape); + std::shared_ptr aPlanarEdges = + std::dynamic_pointer_cast(aContextShape); if(!aPlanarEdges.get()) { continue; } @@ -149,15 +228,18 @@ bool BuildPlugin_Wire::addContour() AttributeSelectionPtr aSelection = *aListIt; std::shared_ptr anEdgeInList(new GeomAPI_Edge(aSelection->value())); - ResultConstructionPtr aConstruction = std::dynamic_pointer_cast(aSelection->context()); + ResultConstructionPtr aConstruction = + std::dynamic_pointer_cast(aSelection->context()); // Iterate on wires and add wire with this edge. std::shared_ptr aFoundWire; for(int anIndex = 0; anIndex < aConstruction->facesNum(); ++anIndex) { std::shared_ptr aFace = aConstruction->face(anIndex); - for(GeomAPI_ShapeExplorer aWireExp(aFace, GeomAPI_Shape::WIRE); aWireExp.more(); aWireExp.next()) { + for(GeomAPI_ShapeExplorer + aWireExp(aFace, GeomAPI_Shape::WIRE); aWireExp.more(); aWireExp.next()) { GeomShapePtr aWireOnFace = aWireExp.current(); - for(GeomAPI_ShapeExplorer anExp(aWireOnFace, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) { + for(GeomAPI_ShapeExplorer + anExp(aWireOnFace, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) { std::shared_ptr anEdgeOnFace(new GeomAPI_Edge(anExp.current())); if(anEdgeInList->isEqual(anEdgeOnFace)) { aFoundWire = aWireOnFace; @@ -172,7 +254,8 @@ bool BuildPlugin_Wire::addContour() // If wire with the same edge found. Add all other edges to list. if(aFoundWire.get()) { - for(GeomAPI_ShapeExplorer anExp(aFoundWire, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) { + for(GeomAPI_ShapeExplorer + anExp(aFoundWire, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) { std::shared_ptr anEdgeOnFace(new GeomAPI_Edge(anExp.current())); ListOfShape::const_iterator anEdgesIt = anAddedEdges.cbegin(); for(; anEdgesIt != anAddedEdges.cend(); ++anEdgesIt) { @@ -190,10 +273,163 @@ bool BuildPlugin_Wire::addContour() } if(!isAnyContourAdded) { - Events_InfoMessage("BuildPlugin_Wire", + Events_InfoMessage("BuildPlugin_Wire", "Error: Contours already closed or no contours found for selected edges.").send(); return false; } return true; } + + + +// ===================== Auxiliary functions ============================================== + +bool buildWire(const ListOfShape& theEdges, GeomShapePtr& theWire, std::string& theError) +{ + theWire = GeomAlgoAPI_WireBuilder::wire(theEdges); + if (!theWire.get()) { + theError = "Error: Result wire is empty. Probably it has disconnected edges or non-manifold."; + return false; + } + return true; +} + +bool buildSketchWires(FeaturePtr theSketchFeature, GeomShapePtr theSketchShape, bool isIntersect, + ListOfShape& theWires, GeomMakeShapePtr& theAlgo, std::string& theError) +{ + ListOfShape aSketchEdges = + std::dynamic_pointer_cast(theSketchShape)->getEdges(); + + std::shared_ptr anAlgoList(new GeomAlgoAPI_MakeShapeList); + if (isIntersect) { + std::set aProcessedEdges; + // perform sketch builder first + AttributePointPtr anOrigin = std::dynamic_pointer_cast( + theSketchFeature->attribute(SketchPlugin_Sketch::ORIGIN_ID())); + AttributeDirPtr aNormal = std::dynamic_pointer_cast( + theSketchFeature->attribute(SketchPlugin_Sketch::NORM_ID())); + AttributeDirPtr aDirX = std::dynamic_pointer_cast( + theSketchFeature->attribute(SketchPlugin_Sketch::DIRX_ID())); + std::shared_ptr aSketchBuilder(new GeomAlgoAPI_SketchBuilder( + anOrigin->pnt(), aDirX->dir(), aNormal->dir(), theSketchShape)); + + anAlgoList->appendAlgo(aSketchBuilder); + + // collect wires from faces + const ListOfShape& aFaces = aSketchBuilder->faces(); + for (ListOfShape::const_iterator anIt = aFaces.begin(); anIt != aFaces.end(); ++anIt) { + for (GeomAPI_ShapeExplorer aWExp(*anIt, GeomAPI_Shape::WIRE); aWExp.more(); aWExp.next()) { + // skip the wire if at least one its edge was already processed + GeomAPI_ShapeExplorer aEExp(aWExp.current(), GeomAPI_Shape::EDGE); + for (; aEExp.more(); aEExp.next()) { + if (aProcessedEdges.find(aEExp.current()) != aProcessedEdges.end()) + break; // wire is already processed + } + if (aEExp.more()) + continue; + // mark edges as processed + for (aEExp.init(aWExp.current(), GeomAPI_Shape::EDGE); aEExp.more(); aEExp.next()) + aProcessedEdges.insert(aEExp.current()); + // store the wire + theWires.push_back(aWExp.current()); + } + } + + // collect unused edges + ListOfShape aCopy; + for (ListOfShape::iterator anIt = aSketchEdges.begin(); anIt != aSketchEdges.end(); ++anIt) { + ListOfShape anImages; + aSketchBuilder->modified(*anIt, anImages); + for (ListOfShape::iterator anEdge = anImages.begin(); anEdge != anImages.end(); ++anEdge) + if (aProcessedEdges.find(*anEdge) == aProcessedEdges.end()) + aCopy.push_back(*anEdge); + } + + if (aCopy.size() > 1) { + // split these edges + std::shared_ptr aGeneralFuse(new GeomAlgoAPI_PaveFiller(aCopy)); + if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed( + aGeneralFuse, BuildPlugin_Wire::ID(), theError)) + return false; + anAlgoList->appendAlgo(aGeneralFuse); + + // collect edges after the split + aSketchEdges.clear(); + for (GeomAPI_ShapeExplorer anExp(aGeneralFuse->shape(), GeomAPI_Shape::EDGE); + anExp.more(); anExp.next()) + aSketchEdges.push_back(anExp.current()); + } + else + aSketchEdges = aCopy; + } + + // connect least edges to wires + typedef std::list ListOfWires; + ListOfWires aNewWires; + typedef std::map MapVertexWire; + MapVertexWire aMapVW; + for (ListOfShape::iterator aEIt = aSketchEdges.begin(); aEIt != aSketchEdges.end(); ++aEIt) { + GeomEdgePtr anEdge = (*aEIt)->edge(); + GeomVertexPtr aStartV, aEndV; + anEdge->vertices(aStartV, aEndV); + MapVertexWire::iterator aFoundStart = aMapVW.find(aStartV); + MapVertexWire::iterator aFoundEnd = aMapVW.find(aEndV); + if (aFoundStart == aMapVW.end()) { + if (aFoundEnd == aMapVW.end()) { + // new wire + aNewWires.push_back(ListOfShape()); + ListOfWires::iterator aNewW = --aNewWires.end(); + aNewW->push_back(anEdge); + aMapVW[aStartV] = aNewW; + aMapVW[aEndV] = aNewW; + continue; + } + } + else { + if (aFoundEnd == aMapVW.end()) { + // swap found vertices for correct further processing + aFoundEnd = aFoundStart; + aStartV = aEndV; + } + else { + // both vertices are found + aFoundStart->second->push_back(anEdge); + if (aFoundStart->second == aFoundEnd->second) + aMapVW.erase(aFoundStart); + else { + // different wires => merge segments + aFoundStart->second->insert(aFoundStart->second->end(), + aFoundEnd->second->begin(), aFoundEnd->second->end()); + for (MapVertexWire::iterator it = aMapVW.begin(); it != aMapVW.end(); ++it) + if (it != aFoundEnd && it->second == aFoundEnd->second) { + // another boundary of the wire, change link to the whole result + it->second = aFoundStart->second; + break; + } + aNewWires.erase(aFoundEnd->second); + aMapVW.erase(aFoundStart); + aMapVW.erase(aFoundEnd); + } + continue; + } + } + // add edge to existing wire, substitute the connection point + // by the other boundary point of the edge + aFoundEnd->second->push_back(anEdge); + aMapVW[aStartV] = aFoundEnd->second; + aMapVW.erase(aFoundEnd); + } + + // generate new wires from the sets of edges + for (ListOfWires::iterator anIt = aNewWires.begin(); anIt != aNewWires.end(); ++anIt) { + GeomShapePtr aWire; + if (!buildWire(*anIt, aWire, theError)) + return false; + theWires.push_back(aWire); + } + + theAlgo = anAlgoList; + return true; +}