1 // Copyright (C) 2020 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include <SketchPlugin_Offset.h>
22 #include <SketchPlugin_Sketch.h>
23 #include <SketchPlugin_Line.h>
24 #include <SketchPlugin_Point.h>
25 #include <SketchPlugin_Arc.h>
26 #include <SketchPlugin_Circle.h>
27 #include <SketchPlugin_Tools.h>
29 #include <Events_InfoMessage.h>
31 #include <ModelAPI_AttributeBoolean.h>
32 #include <ModelAPI_AttributeDouble.h>
33 #include <ModelAPI_AttributeRefList.h>
34 #include <ModelAPI_ResultConstruction.h>
35 #include <ModelAPI_Tools.h>
37 #include <GeomAlgoAPI_Offset.h>
38 #include <GeomAlgoAPI_ShapeTools.h>
39 #include <GeomAlgoAPI_WireBuilder.h>
41 #include <GeomAPI_Edge.h>
42 #include <GeomAPI_Circ.h>
44 #include <GeomDataAPI_Point2D.h>
48 SketchPlugin_Offset::SketchPlugin_Offset()
49 : SketchPlugin_SketchEntity()
53 void SketchPlugin_Offset::initDerivedClassAttributes()
55 std::cout << " !!! *** SketchPlugin_Offset::initDerivedClassAttributes()" << std::endl;
56 data()->addAttribute(EDGES_ID(), ModelAPI_AttributeRefList::typeId());
57 data()->addAttribute(VALUE_ID(), ModelAPI_AttributeDouble::typeId());
58 data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId());
61 void SketchPlugin_Offset::execute()
63 std::cout << " !!! *** SketchPlugin_Offset::execute()" << std::endl;
65 ModelAPI_Tools::removeFeaturesAndReferences(myCreatedFeatures);
67 SketchPlugin_Sketch* aSketch = sketch();
71 std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
74 AttributeDoublePtr aValueAttr = real(VALUE_ID());
75 if (!aValueAttr->isInitialized()) return;
76 double aValue = aValueAttr->value();
77 const double tolerance = 1.e-7;
78 if (aValue < tolerance) return;
81 AttributeBooleanPtr aReversedAttr = boolean(REVERSED_ID());
82 if (!aReversedAttr->isInitialized()) return;
83 if (aReversedAttr->value()) aValue = -aValue; // reverse offset direction
85 // 3. List of all selected edges
86 AttributeRefListPtr aSelectedEdges = reflist(EDGES_ID());
87 std::list<ObjectPtr> anEdgesList = aSelectedEdges->list();
89 // 4. Put all selected edges in a set to pass them into findWireOneWay() below
90 std::set<FeaturePtr> anEdgesSet;
91 std::list<ObjectPtr>::const_iterator anEdgesIt = anEdgesList.begin();
92 for (; anEdgesIt != anEdgesList.end(); anEdgesIt++) {
93 FeaturePtr aFeature = ModelAPI_Feature::feature(*anEdgesIt);
95 anEdgesSet.insert(aFeature);
99 // 5. Gather chains of edges
100 for (anEdgesIt = anEdgesList.begin(); anEdgesIt != anEdgesList.end(); anEdgesIt++) {
101 FeaturePtr aFeature = ModelAPI_Feature::feature(*anEdgesIt);
102 if (aFeature.get()) {
103 if (anEdgesSet.find(aFeature) == anEdgesSet.end())
106 // End points (if any)
107 std::shared_ptr<GeomDataAPI_Point2D> aStartPoint, anEndPoint;
108 SketchPlugin_SegmentationTools::getFeaturePoints(aFeature, aStartPoint, anEndPoint);
109 std::cout << "aStartPoint = (" << aStartPoint->x() << ", " << aStartPoint->y() << ")" << std::endl;
110 std::cout << "anEndPoint = (" << anEndPoint->x() << ", " << anEndPoint->y() << ")" << std::endl;
112 std::list<FeaturePtr> aChain;
113 aChain.push_back(aFeature);
114 bool isClosed = findWireOneWay(aFeature, aFeature, aStartPoint, anEdgesSet, aChain);
116 findWireOneWay(aFeature, aFeature, anEndPoint, anEdgesSet, aChain);
117 std::set<FeaturePtr>::iterator aPos = anEdgesSet.find(aFeature);
118 if (aPos != anEdgesSet.end())
119 anEdgesSet.erase(aPos);
121 ListOfShape aTopoChain;
122 std::list<FeaturePtr>::iterator aChainIt = aChain.begin();
123 for (; aChainIt != aChain.end(); ++aChainIt) {
124 FeaturePtr aChainFeature = (*aChainIt);
125 GeomShapePtr aTopoEdge = aChainFeature->lastResult()->shape();
126 if (aTopoEdge->shapeType() == GeomAPI_Shape::EDGE) {
127 aTopoChain.push_back(aTopoEdge);
130 GeomShapePtr anEdgeOrWire = GeomAlgoAPI_WireBuilder::wire(aTopoChain);
132 // 6. Make offset for each wire or edge
133 std::shared_ptr<GeomAPI_Shape> anOffsetShape =
134 GeomAlgoAPI_Offset::OffsetInPlane(aPlane, anEdgeOrWire, aValue);
136 // 7. Store offset results
137 // Create sketch feature for each edge of anOffsetShape,
138 // and also store created features in list to remove them on next execute()
139 addToSketch(anOffsetShape);
144 bool SketchPlugin_Offset::findWireOneWay (const FeaturePtr& theFirstEdge,
145 const FeaturePtr& theEdge,
146 const std::shared_ptr<GeomDataAPI_Point2D>& theEndPoint,
147 std::set<FeaturePtr>& theEdgesSet,
148 std::list<FeaturePtr>& theChain)
150 // Find coincident edges at Start Point
151 if (!theEndPoint) return false;
153 FeaturePtr aNextEdgeFeature;
156 std::set<AttributePoint2DPtr> aCoincPoints =
157 SketchPlugin_Tools::findPointsCoincidentToPoint(theEndPoint);
159 std::set<AttributePoint2DPtr>::iterator aPointsIt = aCoincPoints.begin();
160 for (; aPointsIt != aCoincPoints.end(); aPointsIt++) {
161 AttributePoint2DPtr aP = (*aPointsIt);
162 FeaturePtr aCoincFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aP->owner());
164 if (aCoincFeature->getKind() != SketchPlugin_Point::ID()) {
165 if (aCoincFeature != theEdge) {
166 bool isInSet = true; // empty set means all sketch edges
167 if (theEdgesSet.size()) {
168 isInSet = (theEdgesSet.find(aCoincFeature) != theEdgesSet.end());
171 aNextEdgeFeature = aCoincFeature;
179 if (aNextEdgeFeature == theFirstEdge)
180 // Closed chain found
183 // continue the chain
184 theChain.push_back(aNextEdgeFeature);
185 // remove from the set, if the set is used
186 if (theEdgesSet.size()) {
187 std::set<FeaturePtr>::iterator aPos = theEdgesSet.find(aNextEdgeFeature);
188 if (aPos != theEdgesSet.end())
189 theEdgesSet.erase(aPos);
192 std::shared_ptr<GeomDataAPI_Point2D> aNextStartPoint, aNextEndPoint;
193 SketchPlugin_SegmentationTools::getFeaturePoints(aNextEdgeFeature, aNextStartPoint, aNextEndPoint);
194 if (aNextStartPoint && aNextEndPoint) {
195 std::cout << "theEndPoint = (" << theEndPoint->x() << ", " << theEndPoint->y() << ")" << std::endl;
196 std::cout << "aNextStartPoint = (" << aNextStartPoint->x() << ", " << aNextStartPoint->y() << ")" << std::endl;
197 std::cout << "aNextEndPoint = (" << aNextEndPoint->x() << ", " << aNextEndPoint->y() << ")" << std::endl;
198 // Check which end of aNextEdgeFeature should be used to find a next edge
199 std::shared_ptr<GeomAPI_Pnt2d> anEndPnt = theEndPoint->pnt();
200 std::shared_ptr<GeomAPI_Pnt2d> aNextEndPnt = aNextEndPoint->pnt();
201 if (aNextEndPnt->isEqual(anEndPnt)) {
202 std::cout << "aNextEndPoint == theEndPoint" << std::endl;
203 aNextEndPoint = aNextStartPoint;
206 return findWireOneWay (theFirstEdge, aNextEdgeFeature, aNextEndPoint, theEdgesSet, theChain);
213 void SketchPlugin_Offset::addToSketch(const std::shared_ptr<GeomAPI_Shape>& anOffsetShape)
215 //GeomAPI_ShapeExplorer::GeomAPI_ShapeExplorer
216 ListOfShape aResEdges = GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(anOffsetShape);
217 std::list<GeomShapePtr>::const_iterator aResEdgesIt = aResEdges.begin();
218 for (; aResEdgesIt != aResEdges.end(); aResEdgesIt++) {
219 GeomShapePtr aResShape = (*aResEdgesIt);
220 if (aResShape->shapeType() == GeomAPI_Shape::EDGE) {
222 FeaturePtr aResFeature;
223 std::shared_ptr<GeomAPI_Edge> aResEdge (new GeomAPI_Edge(aResShape));
225 std::shared_ptr<GeomAPI_Pnt2d> aFP, aLP;
226 std::shared_ptr<GeomAPI_Pnt> aFP3d = aResEdge->firstPoint();
227 std::shared_ptr<GeomAPI_Pnt> aLP3d = aResEdge->lastPoint();
228 if (aFP3d.get() && aLP3d.get()) {
229 aFP = sketch()->to2D(aFP3d);
230 aLP = sketch()->to2D(aLP3d);
233 if (aResEdge->isLine()) {
234 aResFeature = sketch()->addFeature(SketchPlugin_Line::ID());
236 std::dynamic_pointer_cast<GeomDataAPI_Point2D>
237 (aResFeature->attribute(SketchPlugin_Line::START_ID()))->setValue(aFP);
238 std::dynamic_pointer_cast<GeomDataAPI_Point2D>
239 (aResFeature->attribute(SketchPlugin_Line::END_ID()))->setValue(aLP);
241 else if (aResEdge->isArc()) {
242 std::shared_ptr<GeomAPI_Circ> aCircEdge = aResEdge->circle();
243 std::shared_ptr<GeomAPI_Pnt> aCP3d = aCircEdge->center();
244 std::shared_ptr<GeomAPI_Pnt2d> aCP = sketch()->to2D(aCP3d);
246 aResFeature = sketch()->addFeature(SketchPlugin_Arc::ID());
248 bool aWasBlocked = aResFeature->data()->blockSendAttributeUpdated(true);
249 std::dynamic_pointer_cast<GeomDataAPI_Point2D>
250 (aResFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(aCP);
251 std::dynamic_pointer_cast<GeomDataAPI_Point2D>
252 (aResFeature->attribute(SketchPlugin_Arc::START_ID()))->setValue(aFP);
253 std::dynamic_pointer_cast<GeomDataAPI_Point2D>
254 (aResFeature->attribute(SketchPlugin_Arc::END_ID()))->setValue(aLP);
255 aResFeature->data()->blockSendAttributeUpdated(aWasBlocked);
257 else if (aResEdge->isCircle()) {
258 std::shared_ptr<GeomAPI_Circ> aCircEdge = aResEdge->circle();
259 std::shared_ptr<GeomAPI_Pnt> aCP3d = aCircEdge->center();
260 std::shared_ptr<GeomAPI_Pnt2d> aCP = sketch()->to2D(aCP3d);
262 aResFeature = sketch()->addFeature(SketchPlugin_Circle::ID());
263 std::dynamic_pointer_cast<GeomDataAPI_Point2D>
264 (aResFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(aCP);
265 aResFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aCircEdge->radius());
270 if (aResFeature.get()) {
271 myCreatedFeatures.insert(aResFeature);
273 aResFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue
274 (boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value());
275 aResFeature->execute();
281 void SketchPlugin_Offset::attributeChanged(const std::string& theID)
283 std::cout << " !!! *** SketchPlugin_Offset::attributeChanged() myCreatedFeatures.size() 1 = "
284 << myCreatedFeatures.size() << std::endl;
285 ModelAPI_Tools::removeFeaturesAndReferences(myCreatedFeatures);
286 std::cout << " !!! *** SketchPlugin_Offset::attributeChanged() myCreatedFeatures.size() 2 = "
287 << myCreatedFeatures.size() << std::endl;
290 bool SketchPlugin_Offset::customAction(const std::string& theActionId)
292 std::cout << " !!! *** SketchPlugin_Offset::customAction()" << std::endl;
294 if (theActionId == ADD_WIRE_ACTION_ID()) {
298 std::string aMsg = "Error: Feature \"%1\" does not support action \"%2\".";
299 Events_InfoMessage("SketchPlugin_Offset", aMsg).arg(getKind()).arg(theActionId).send();
304 bool SketchPlugin_Offset::findWires()
306 AttributeRefListPtr aSelectedEdges = reflist(EDGES_ID());
307 std::list<ObjectPtr> anEdgesList = aSelectedEdges->list();
310 std::set<FeaturePtr> anEdgesSet;
313 std::set<FeaturePtr> anEdgesSet1;
315 // Put all selected edges in a set to pass them into findWireOneWay() below
316 std::set<FeaturePtr> aSelectedSet;
317 std::list<ObjectPtr>::const_iterator anEdgesIt = anEdgesList.begin();
318 for (; anEdgesIt != anEdgesList.end(); anEdgesIt++) {
319 FeaturePtr aFeature = ModelAPI_Feature::feature(*anEdgesIt);
321 aSelectedSet.insert(aFeature);
325 // Gather chains of edges
326 for (anEdgesIt = anEdgesList.begin(); anEdgesIt != anEdgesList.end(); anEdgesIt++) {
327 FeaturePtr aFeature = ModelAPI_Feature::feature(*anEdgesIt);
328 if (aFeature.get()) {
329 if (anEdgesSet1.find(aFeature) != anEdgesSet1.end())
331 anEdgesSet1.insert(aFeature);
333 // End points (if any)
334 std::shared_ptr<GeomDataAPI_Point2D> aStartPoint, anEndPoint;
335 SketchPlugin_SegmentationTools::getFeaturePoints(aFeature, aStartPoint, anEndPoint);
336 std::cout << "aStartPoint = (" << aStartPoint->x() << ", " << aStartPoint->y() << ")" << std::endl;
337 std::cout << "anEndPoint = (" << anEndPoint->x() << ", " << anEndPoint->y() << ")" << std::endl;
339 std::list<FeaturePtr> aChain;
340 aChain.push_back(aFeature);
341 bool isClosed = findWireOneWay(aFeature, aFeature, aStartPoint, anEdgesSet, aChain);
343 findWireOneWay(aFeature, aFeature, anEndPoint, anEdgesSet, aChain);
345 std::list<FeaturePtr>::iterator aChainIt = aChain.begin();
346 for (; aChainIt != aChain.end(); ++aChainIt) {
347 FeaturePtr aChainFeature = (*aChainIt);
348 anEdgesSet1.insert(aChainFeature);
349 if (aSelectedSet.find(aChainFeature) == aSelectedSet.end()) {
350 std::cout << " !!! *** SketchPlugin_Offset::findWires() - Add an edge" << std::endl;
351 aSelectedEdges->append(aChainFeature->lastResult());
356 // TODO: hilight selection in the viewer