]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchPlugin/SketchPlugin_Offset.cpp
Salome HOME
Sketcher Offset: Select wire, debug.
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Offset.cpp
1 // Copyright (C) 2020  CEA/DEN, EDF R&D
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include <SketchPlugin_Offset.h>
21
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>
28
29 #include <Events_InfoMessage.h>
30
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>
36
37 #include <GeomAlgoAPI_Offset.h>
38 #include <GeomAlgoAPI_ShapeTools.h>
39 #include <GeomAlgoAPI_WireBuilder.h>
40
41 #include <GeomAPI_Edge.h>
42 #include <GeomAPI_Circ.h>
43
44 #include <GeomDataAPI_Point2D.h>
45
46 #include <iostream>
47
48 SketchPlugin_Offset::SketchPlugin_Offset()
49   : SketchPlugin_SketchEntity()
50 {
51 }
52
53 void SketchPlugin_Offset::initDerivedClassAttributes()
54 {
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());
59 }
60
61 void SketchPlugin_Offset::execute()
62 {
63   std::cout << "   !!!   ***   SketchPlugin_Offset::execute()" << std::endl;
64
65   ModelAPI_Tools::removeFeaturesAndReferences(myCreatedFeatures);
66
67   SketchPlugin_Sketch* aSketch = sketch();
68   if (!aSketch) return;
69
70   // 1. Sketch plane
71   std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
72
73   // 2. Offset value
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;
79
80   // 2.a. Reversed?
81   AttributeBooleanPtr aReversedAttr = boolean(REVERSED_ID());
82   if (!aReversedAttr->isInitialized()) return;
83   if (aReversedAttr->value()) aValue = -aValue; // reverse offset direction
84
85   // 3. List of all selected edges
86   AttributeRefListPtr aSelectedEdges = reflist(EDGES_ID());
87   std::list<ObjectPtr> anEdgesList = aSelectedEdges->list();
88
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);
94     if (aFeature) {
95       anEdgesSet.insert(aFeature);
96     }
97   }
98
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())
104         continue;
105
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;
111
112       std::list<FeaturePtr> aChain;
113       aChain.push_back(aFeature);
114       bool isClosed = findWireOneWay(aFeature, aFeature, aStartPoint, anEdgesSet, aChain);
115       if (!isClosed)
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);
120
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);
128         }
129       }
130       GeomShapePtr anEdgeOrWire = GeomAlgoAPI_WireBuilder::wire(aTopoChain);
131
132       // 6. Make offset for each wire or edge
133       std::shared_ptr<GeomAPI_Shape> anOffsetShape =
134         GeomAlgoAPI_Offset::OffsetInPlane(aPlane, anEdgeOrWire, aValue);
135
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);
140     }
141   }
142 }
143
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)
149 {
150   // Find coincident edges at Start Point
151   if (!theEndPoint) return false;
152
153   FeaturePtr aNextEdgeFeature;
154   int nbFound = 0;
155
156   std::set<AttributePoint2DPtr> aCoincPoints =
157     SketchPlugin_Tools::findPointsCoincidentToPoint(theEndPoint);
158
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());
163
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());
169         }
170         if (isInSet) {
171           aNextEdgeFeature = aCoincFeature;
172           nbFound++;
173         }
174       }
175     }
176   }
177
178   if (nbFound == 1) {
179     if (aNextEdgeFeature == theFirstEdge)
180       // Closed chain found
181       return true;
182
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);
190     }
191
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;
204       }
205
206       return findWireOneWay (theFirstEdge, aNextEdgeFeature, aNextEndPoint, theEdgesSet, theChain);
207     }
208   }
209
210   return false;
211 }
212
213 void SketchPlugin_Offset::addToSketch(const std::shared_ptr<GeomAPI_Shape>& anOffsetShape)
214 {
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) {
221       // Add new feature
222       FeaturePtr aResFeature;
223       std::shared_ptr<GeomAPI_Edge> aResEdge (new GeomAPI_Edge(aResShape));
224
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);
231       }
232
233       if (aResEdge->isLine()) {
234         aResFeature = sketch()->addFeature(SketchPlugin_Line::ID());
235
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);
240       }
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);
245
246         aResFeature = sketch()->addFeature(SketchPlugin_Arc::ID());
247
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);
256       }
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);
261
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());
266       }
267       else {
268       }
269
270       if (aResFeature.get()) {
271         myCreatedFeatures.insert(aResFeature);
272
273         aResFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue
274           (boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value());
275         aResFeature->execute();
276       }
277     }
278   }
279 }
280
281 void SketchPlugin_Offset::attributeChanged(const std::string& theID)
282 {
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;
288 }
289
290 bool SketchPlugin_Offset::customAction(const std::string& theActionId)
291 {
292   std::cout << "   !!!   ***   SketchPlugin_Offset::customAction()" << std::endl;
293   bool isOk = false;
294   if (theActionId == ADD_WIRE_ACTION_ID()) {
295     isOk = findWires();
296   }
297   else {
298     std::string aMsg = "Error: Feature \"%1\" does not support action \"%2\".";
299     Events_InfoMessage("SketchPlugin_Offset", aMsg).arg(getKind()).arg(theActionId).send();
300   }
301   return isOk;
302 }
303
304 bool SketchPlugin_Offset::findWires()
305 {
306   AttributeRefListPtr aSelectedEdges = reflist(EDGES_ID());
307   std::list<ObjectPtr> anEdgesList = aSelectedEdges->list();
308
309   // Empty set
310   std::set<FeaturePtr> anEdgesSet;
311
312   // Processed set
313   std::set<FeaturePtr> anEdgesSet1;
314
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);
320     if (aFeature) {
321       aSelectedSet.insert(aFeature);
322     }
323   }
324
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())
330         continue;
331       anEdgesSet1.insert(aFeature);
332
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;
338
339       std::list<FeaturePtr> aChain;
340       aChain.push_back(aFeature);
341       bool isClosed = findWireOneWay(aFeature, aFeature, aStartPoint, anEdgesSet, aChain);
342       if (!isClosed)
343         findWireOneWay(aFeature, aFeature, anEndPoint, anEdgesSet, aChain);
344
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());
352         }
353       }
354     }
355   }
356   // TODO: hilight selection in the viewer
357
358   return true;
359 }