X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FBuildPlugin%2FBuildPlugin_Wire.cpp;h=ff29af48add642e820dce8272b15d9ae3b516c50;hb=88ee9b2b81cf93a6324336b57e30cc8a3a487499;hp=99d6bd74ed7cb704e9d5bea0d831852aac9f6f9a;hpb=37bd12bd6f4626fc2bfa7764c8f4927dc5b01b9c;p=modules%2Fshaper.git diff --git a/src/BuildPlugin/BuildPlugin_Wire.cpp b/src/BuildPlugin/BuildPlugin_Wire.cpp index 99d6bd74e..ff29af48a 100644 --- a/src/BuildPlugin/BuildPlugin_Wire.cpp +++ b/src/BuildPlugin/BuildPlugin_Wire.cpp @@ -1,26 +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-2022 CEA/DEN, EDF R&D +// +// 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 +#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() { @@ -30,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()); } //================================================================================================= @@ -46,44 +77,96 @@ void BuildPlugin_Wire::execute() return; } + AttributeBooleanPtr anIntersectAttr = boolean(INTERSECT_ID()); + bool isIntersect = anIntersectAttr->isInitialized() && anIntersectAttr->value(); + // Collect base shapes. - ListOfShape aListOfShapes; + 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()) { - setError("Error: Empty shape selected."); - return; + 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(); + anEdges.push_back(anEdge); + } + } - if(aShape->shapeType() != GeomAPI_Shape::EDGE && aShape->shapeType() != GeomAPI_Shape::WIRE) { - setError("Error: Selected shape has wrong type. Only edges and wires acceptable."); + int aResultIndex = 0; + std::string anError; + + if (!anEdges.empty()) { + // Create wire from the list of edges. + GeomShapePtr aWire; + if (!buildWire(anEdges, aWire, anError)) { + setError(anError); return; } - aListOfShapes.push_back(aShape); + // 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; } - // Create wire. - GeomShapePtr aWire = GeomAlgoAPI_WireBuilder::wire(aListOfShapes); - if(!aWire.get()) { - setError("Error: Result wire is empty. Probably it has disconnected edges or non-manifold."); - return; + // 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; + } } - // Store result. - ResultBodyPtr aResultBody = document()->createBody(data()); - aResultBody->store(aWire); - setResult(aResultBody); + removeResults(aResultIndex); } //================================================================================================= bool BuildPlugin_Wire::customAction(const std::string& theActionId) { - if(theActionId == "add_contour") { + if(theActionId == ADD_CONTOUR_ACTION_ID()) { return addContour(); } else { - Events_Error::send("Error: Feature \"" + getKind() + "\" does not support action \"" + theActionId + "\"."); + std::string aMsg = "Error: Feature \"%1\" does not support action \"%2\"."; + Events_InfoMessage("BuildPlugin_Wire", aMsg).arg(getKind()).arg(theActionId).send(); } return false; @@ -95,7 +178,7 @@ bool BuildPlugin_Wire::addContour() // Get base objects list. AttributeSelectionListPtr aSelectionList = selectionList(BASE_OBJECTS_ID()); if(aSelectionList->size() == 0) { - Events_Error::send("Error: Empty selection list."); + Events_InfoMessage("BuildPlugin_Wire", "Error: Empty selection list.").send(); return false; } @@ -116,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; } @@ -143,38 +228,36 @@ bool BuildPlugin_Wire::addContour() AttributeSelectionPtr aSelection = *aListIt; std::shared_ptr anEdgeInList(new GeomAPI_Edge(aSelection->value())); - ListOfShape::const_iterator anEdgesIt = anAddedEdges.cbegin(); - for(; anEdgesIt != anAddedEdges.cend(); ++anEdgesIt) { - if(anEdgeInList->isEqual(*anEdgesIt)) { - break; - } - } - - ResultConstructionPtr aConstruction = std::dynamic_pointer_cast(aSelection->context()); - std::shared_ptr aPlanarEdges = std::dynamic_pointer_cast(aConstruction->shape()); + ResultConstructionPtr aConstruction = + std::dynamic_pointer_cast(aSelection->context()); - // Iterate on faces and add face with this edge. - std::shared_ptr aFoundFace; + // 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 anExp(aFace, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) { - std::shared_ptr anEdgeOnFace(new GeomAPI_Edge(anExp.current())); - if(anEdgeInList->isEqual(anEdgeOnFace)) { - aFoundFace = aFace; - break; + 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()) { + std::shared_ptr anEdgeOnFace(new GeomAPI_Edge(anExp.current())); + if(anEdgeInList->isEqual(anEdgeOnFace)) { + aFoundWire = aWireOnFace; + break; + } } } - - if(aFoundFace.get()) { + if(aFoundWire.get()) { break; } } - // If face with the same edge found. Add all other edges to list. - if(aFoundFace.get()) { - for(GeomAPI_ShapeExplorer anExp(aFoundFace, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) { + // 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()) { std::shared_ptr anEdgeOnFace(new GeomAPI_Edge(anExp.current())); - anEdgesIt = anAddedEdges.cbegin(); + ListOfShape::const_iterator anEdgesIt = anAddedEdges.cbegin(); for(; anEdgesIt != anAddedEdges.cend(); ++anEdgesIt) { if(anEdgeOnFace->isEqual(*anEdgesIt)) { break; @@ -190,9 +273,163 @@ bool BuildPlugin_Wire::addContour() } if(!isAnyContourAdded) { - Events_Error::send("Error: Contours already closed or no contours found for selected edges."); + 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; }