Salome HOME
updated copyright message
[modules/shaper.git] / src / ModelGeomAlgo / ModelGeomAlgo_Point2D.cpp
1 // Copyright (C) 2014-2023  CEA, EDF
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 "ModelGeomAlgo_Point2D.h"
21
22 #include <ModelAPI_Feature.h>
23 #include <ModelAPI_Result.h>
24 #include <ModelAPI_AttributeRefAttr.h>
25 #include <ModelAPI_CompositeFeature.h>
26 #include <ModelAPI_Tools.h>
27
28 #include <ModelGeomAlgo_Shape.h>
29
30 #include <GeomAPI_ShapeIterator.h>
31
32 #include <GeomAlgoAPI_ShapeTools.h>
33 #include <GeomDataAPI_Point2D.h>
34
35 #include <GeomAPI_Pnt.h>
36 #include <GeomAPI_Pnt2d.h>
37 #include <GeomAPI_Vertex.h>
38 #include <GeomAPI_Dir.h>
39 #include <GeomAPI_Edge.h>
40 #include <GeomAPI_Lin.h>
41 #include <GeomAPI_Circ.h>
42 #include <GeomAPI_ShapeExplorer.h>
43
44 //#define DEBUG_POINT_INSIDE_SHAPE
45 #ifdef DEBUG_POINT_INSIDE_SHAPE
46 #include <iostream>
47 #endif
48
49 #ifdef WIN32
50 #pragma warning(disable : 4996) // for sprintf
51 #endif
52
53 std::shared_ptr<GeomDataAPI_Point2D> ModelGeomAlgo_Point2D::getPointOfRefAttr(
54                                                   ModelAPI_Feature* theFeature,
55                                                   const std::string& theAttribute,
56                                                   const std::string& theObjectFeatureKind,
57                                                   const std::string& theObjectFeatureAttribute)
58 {
59   std::shared_ptr<GeomDataAPI_Point2D> aPointAttr;
60
61   /// essential check as it is called in openGl thread
62   if (!theFeature || !theFeature->data().get() || !theFeature->data()->isValid())
63     return std::shared_ptr<GeomDataAPI_Point2D>();
64
65   FeaturePtr aFeature;
66   std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = std::dynamic_pointer_cast<
67       ModelAPI_AttributeRefAttr>(theFeature->data()->attribute(theAttribute));
68   if(anAttr.get() && anAttr->isInitialized()) {
69     aFeature = ModelAPI_Feature::feature(anAttr->object());
70     if (aFeature.get()) {
71       bool aFeatureOfObjectKind = !theObjectFeatureKind.empty() &&
72                                   !theObjectFeatureAttribute.empty() &&
73                                   aFeature->getKind() == theObjectFeatureKind;
74       if(aFeatureOfObjectKind)
75           aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
76                                   aFeature->data()->attribute(theObjectFeatureAttribute));
77       else if (anAttr->attr())
78         aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
79     }
80   }
81   return aPointAttr;
82 }
83
84 void ModelGeomAlgo_Point2D::getPointsOfReference(
85                             const std::shared_ptr<ModelAPI_Object>& theObject,
86                             const std::string& theReferenceFeatureKind,
87                             std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theAttributes,
88                             const std::string& theObjectFeatureKind,
89                             const std::string& theObjectFeatureAttribute,
90                             const bool isSkipFeatureAttributes)
91 {
92   // find by feature
93   FeaturePtr aSourceFeature = ModelAPI_Feature::feature(theObject);
94
95   const std::set<AttributePtr>& aRefsList = theObject->data()->refsToMe();
96   std::set<AttributePtr>::const_iterator aIt;
97   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
98     std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
99     FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
100     if (aRefFeature->getKind() == theReferenceFeatureKind) {
101       std::list<AttributePtr> anAttributes =
102                         aRefFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
103       std::list<AttributePtr>::iterator anIter = anAttributes.begin(), aLast = anAttributes.end();
104       bool isSkippedAttribute = false;
105       if (isSkipFeatureAttributes) {
106         for(anIter = anAttributes.begin(); anIter != aLast && !isSkippedAttribute; anIter++) {
107           AttributeRefAttrPtr aRefAttribute =
108             std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
109           if (aRefAttribute.get() && !aRefAttribute->isObject()) {
110             std::shared_ptr<GeomDataAPI_Point2D> aPointAttr =
111                             std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttribute->attr());
112             FeaturePtr anAttributeFeature = ModelAPI_Feature::feature(aPointAttr->owner());
113             isSkippedAttribute = aSourceFeature == anAttributeFeature;
114           }
115         }
116       }
117       if (isSkippedAttribute)
118         continue;
119
120       // it searches the first point of AttributeRefAtt
121       std::shared_ptr<GeomDataAPI_Point2D> aPointAttr;
122       for(anIter = anAttributes.begin(); anIter != aLast && !aPointAttr.get(); anIter++) {
123         AttributeRefAttrPtr aRefAttribute =
124           std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
125         if (aRefAttribute.get()) {
126           aPointAttr = getPointOfRefAttr(aRefFeature.get(), aRefAttribute->id(),
127                         theObjectFeatureKind, theObjectFeatureAttribute);
128         }
129       }
130       if (aPointAttr.get()) {
131         theAttributes.insert(aPointAttr);
132       }
133     }
134   }
135   // find by results
136   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
137   if (aFeature.get()) {
138     const std::list<std::shared_ptr<ModelAPI_Result> > aResults = aFeature->results();
139     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
140     for (; aRIter != aResults.cend(); aRIter++) {
141       ResultPtr aResult = *aRIter;
142       getPointsOfReference(aResult, theReferenceFeatureKind, theAttributes, theObjectFeatureKind,
143                             theObjectFeatureAttribute);
144     }
145   }
146 }
147
148 void appendPoint(const std::shared_ptr<GeomAPI_Pnt>& thePoint,
149                    const std::shared_ptr<ModelAPI_Result>& theResult,
150                    ModelGeomAlgo_Point2D::PointToRefsMap& thePointToAttributeOrObject)
151 {
152   bool aPointFound = false;
153   FeaturePtr aPointFeature = ModelAPI_Feature::feature(theResult);
154   // check if the given point is already in the container in attribute list
155   for (ModelGeomAlgo_Point2D::PointToRefsMap::const_iterator
156                   anIt = thePointToAttributeOrObject.begin();
157                   anIt != thePointToAttributeOrObject.end() && !aPointFound; anIt++) {
158     std::shared_ptr<GeomAPI_Pnt> aPoint = anIt->first;
159     if (aPoint->isEqual(thePoint)) {
160       std::list<std::shared_ptr<GeomDataAPI_Point2D> > anAttributes = anIt->second.first;
161       for (std::list<AttributePoint2DPtr>::const_iterator anAttrIt = anAttributes.begin();
162           anAttrIt != anAttributes.end() && !aPointFound; anAttrIt++) {
163         AttributePtr anAttribute = *anAttrIt;
164         aPointFound = ModelAPI_Feature::feature(anAttribute->owner()) == aPointFeature;
165       }
166     }
167   }
168
169   if (!aPointFound) {
170     if (thePointToAttributeOrObject.find(thePoint) != thePointToAttributeOrObject.end())
171       thePointToAttributeOrObject.at(thePoint).second.push_back(theResult);
172     else {
173       std::list<std::shared_ptr<GeomDataAPI_Point2D> > anAttributes;
174       std::list<std::shared_ptr<ModelAPI_Object> > anObjects;
175       anObjects.push_back(theResult);
176       thePointToAttributeOrObject[thePoint] = std::make_pair(anAttributes, anObjects);
177     }
178 #ifdef DEBUG_POINT_INSIDE_SHAPE
179     std::cout << "["<< thePoint->x() << ", " << thePoint->y() << "," << thePoint->z() << "]";
180 #endif
181   }
182 }
183
184 void appendShapePoints(const GeomShapePtr& theShape,
185                        const std::shared_ptr<ModelAPI_Result>& theResult,
186                        ModelGeomAlgo_Point2D::PointToRefsMap& thePointToAttributeOrObject)
187 {
188   if (!theShape.get())
189     return;
190
191   switch (theShape->shapeType()) {
192     case GeomAPI_Shape::VERTEX: {
193       std::shared_ptr<GeomAPI_Vertex> aVertex =
194         std::shared_ptr<GeomAPI_Vertex>(new GeomAPI_Vertex(theShape));
195       std::shared_ptr<GeomAPI_Pnt> aPnt = aVertex->point();
196       appendPoint(aPnt, theResult, thePointToAttributeOrObject);
197     }
198     break;
199     case GeomAPI_Shape::EDGE: {
200       std::shared_ptr<GeomAPI_Edge> anEdge =
201         std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(theShape));
202       appendPoint(anEdge->firstPoint(), theResult, thePointToAttributeOrObject);
203       appendPoint(anEdge->lastPoint(), theResult, thePointToAttributeOrObject);
204     }
205     break;
206     case GeomAPI_Shape::COMPOUND: {
207       for(GeomAPI_ShapeIterator anIt(theShape); anIt.more(); anIt.next()) {
208         appendShapePoints(anIt.current(), theResult, thePointToAttributeOrObject);
209       }
210     }
211     break;
212     default: break;
213   }
214 }
215
216 void ModelGeomAlgo_Point2D::getPointsIntersectedShape(
217                         const std::shared_ptr<ModelAPI_Feature>& theBaseFeature,
218                         const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
219                         PointToRefsMap& thePointToAttributeOrObject)
220 {
221 #ifdef DEBUG_POINT_INSIDE_SHAPE
222   std::cout << "ModelGeomAlgo_Point2D::getPointsIntersectedShape" << std::endl;
223 #endif
224   GeomShapePtr aFeatureShape;
225   {
226     std::set<ResultPtr> anEdgeShapes;
227     ModelGeomAlgo_Shape::shapesOfType(theBaseFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
228     if (anEdgeShapes.empty())
229       return;
230     aFeatureShape = (*anEdgeShapes.begin())->shape();
231   }
232
233   std::list<std::shared_ptr<ModelAPI_Feature> >::const_iterator anIt = theFeatures.begin(),
234                                                                 aLast = theFeatures.end();
235   for (; anIt != aLast; anIt++) {
236     FeaturePtr aFeature = *anIt;
237     if (aFeature.get() == theBaseFeature.get())
238       continue;
239     if (aFeature.get()) {
240       std::set<ResultPtr> anEdgeShapes;
241       ModelGeomAlgo_Shape::shapesOfType(aFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
242       if (anEdgeShapes.empty())
243         ModelGeomAlgo_Shape::shapesOfType(aFeature, GeomAPI_Shape::VERTEX, anEdgeShapes);
244
245       if (anEdgeShapes.empty())
246         continue;
247       ResultPtr aResult = *anEdgeShapes.begin();
248       GeomShapePtr aShape = aResult->shape();
249
250       GeomShapePtr aShapeOfIntersection = aFeatureShape->intersect(aShape);
251 #ifdef DEBUG_POINT_INSIDE_SHAPE
252       int aPrevSize = thePointToAttributeOrObject.size();
253 #endif
254       appendShapePoints(aShapeOfIntersection, aResult, thePointToAttributeOrObject);
255 #ifdef DEBUG_POINT_INSIDE_SHAPE
256       if (aPrevSize != thePointToAttributeOrObject.size())
257         std::cout << " <- appendShapePoints"
258                   << thePointToAttributeOrObject.size() - aPrevSize << std::endl;
259 #endif
260     }
261   }
262 }
263
264 std::list<std::shared_ptr<GeomAPI_Pnt> > ModelGeomAlgo_Point2D::getSetOfPntIntersectedShape(
265                   const std::shared_ptr<ModelAPI_Feature>& theBaseFeature,
266                   const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures)
267 {
268   std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
269
270   PointToRefsMap aRefsMap;
271   getPointsIntersectedShape(theBaseFeature, theFeatures, aRefsMap);
272
273   for (PointToRefsMap::const_iterator aPointIt = aRefsMap.begin();
274        aPointIt != aRefsMap.end(); aPointIt++)
275     aPoints.push_back(aPointIt->first);
276
277   return aPoints;
278 }
279
280 void ModelGeomAlgo_Point2D::getPointsInsideShape(
281                         const std::shared_ptr<GeomAPI_Shape> theBaseShape,
282                         const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theAttributes,
283                         const std::shared_ptr<GeomAPI_Pnt>& theOrigin,
284                         const std::shared_ptr<GeomAPI_Dir>& theDirX,
285                         const std::shared_ptr<GeomAPI_Dir>& theDirY,
286                         PointToRefsMap& thePointToAttributeOrObject)
287 {
288 #ifdef DEBUG_POINT_INSIDE_SHAPE
289   std::cout << "ModelGeomAlgo_Point2D::getPointsInsideShape:" << std::endl;
290 #endif
291   std::set<std::shared_ptr<GeomDataAPI_Point2D> >::const_iterator anIt = theAttributes.begin(),
292                                                           aLast = theAttributes.end();
293   for (; anIt != aLast; anIt++) {
294     std::shared_ptr<GeomDataAPI_Point2D> anAttribute = *anIt;
295     std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = anAttribute->pnt();
296     std::shared_ptr<GeomAPI_Pnt> aPoint = aPnt2d->to3D(theOrigin, theDirX, theDirY);
297     std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
298     if (isInnerPointOnEdge(theBaseShape, aPoint, aProjectedPoint)) {
299       if (thePointToAttributeOrObject.find(aProjectedPoint) != thePointToAttributeOrObject.end())
300         thePointToAttributeOrObject.at(aProjectedPoint).first.push_back(anAttribute);
301       else {
302         std::list<std::shared_ptr<GeomDataAPI_Point2D> > anAttributes;
303         std::list<std::shared_ptr<ModelAPI_Object> > anObjects;
304         anAttributes.push_back(anAttribute);
305         thePointToAttributeOrObject[aProjectedPoint] = std::make_pair(anAttributes, anObjects);
306       }
307 #ifdef DEBUG_POINT_INSIDE_SHAPE
308       std::cout << "  " << anAttribute->owner()->data()->name() << ": " << anAttribute->id()
309                 << "[" << aPoint->x() << ", " << aPoint->y() << ", " << aPoint->z() << "]"
310                 << std::endl;
311 #endif
312     }
313     else {
314 #ifdef DEBUG_POINT_INSIDE_SHAPE
315       std::cout << "  " << anAttribute->owner()->data()->name() << ": " << anAttribute->id()
316                 << "OUT of shape" << std::endl;
317 #endif
318     }
319   }
320 }
321
322 void ModelGeomAlgo_Point2D::getPointsInsideShape_p(
323                             const std::shared_ptr<GeomAPI_Shape> theBaseShape,
324                             const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theAttributes,
325                             const std::shared_ptr<GeomAPI_Pnt>& theOrigin,
326                             const std::shared_ptr<GeomAPI_Dir>& theDirX,
327                             const std::shared_ptr<GeomAPI_Dir>& theDirY,
328                             std::list<std::shared_ptr<GeomAPI_Pnt> >& thePoints,
329                             std::map<std::shared_ptr<GeomDataAPI_Point2D>,
330                                      std::shared_ptr<GeomAPI_Pnt> >& theAttributeToPoint)
331 {
332   std::set<std::shared_ptr<GeomDataAPI_Point2D> >::const_iterator anIt = theAttributes.begin(),
333                                                           aLast = theAttributes.end();
334   for (; anIt != aLast; anIt++) {
335     std::shared_ptr<GeomDataAPI_Point2D> anAttribute = *anIt;
336     std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = anAttribute->pnt();
337     std::shared_ptr<GeomAPI_Pnt> aPoint = aPnt2d->to3D(theOrigin, theDirX, theDirY);
338     std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
339     if (isInnerPointOnEdge(theBaseShape, aPoint, aProjectedPoint)) {
340       thePoints.push_back(aProjectedPoint);
341       theAttributeToPoint[anAttribute] = aProjectedPoint;
342     }
343   }
344 }
345
346 bool ModelGeomAlgo_Point2D::isPointOnEdge(const std::shared_ptr<GeomAPI_Shape> theBaseShape,
347                      const std::shared_ptr<GeomAPI_Pnt>& thePoint,
348                      std::shared_ptr<GeomAPI_Pnt>& theProjectedPoint)
349 {
350   bool isInside = false;
351   if (theBaseShape->shapeType() == GeomAPI_Shape::EDGE) {
352     GeomCurvePtr aCurve(new GeomAPI_Curve(theBaseShape->edge()));
353     theProjectedPoint = aCurve->project(thePoint);
354     if (theProjectedPoint.get()) {
355       std::shared_ptr<GeomAPI_Vertex> aVertexShape(new GeomAPI_Vertex(theProjectedPoint->x(),
356                                                 theProjectedPoint->y(), theProjectedPoint->z()));
357       isInside = GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(aVertexShape, theBaseShape);
358     }
359   }
360   return isInside;
361 }
362
363
364 bool ModelGeomAlgo_Point2D::isInnerPointOnEdge(const std::shared_ptr<GeomAPI_Shape> theBaseShape,
365                      const std::shared_ptr<GeomAPI_Pnt>& thePoint,
366                      std::shared_ptr<GeomAPI_Pnt>& theProjectedPoint)
367 {
368   bool isInside = isPointOnEdge(theBaseShape, thePoint, theProjectedPoint);
369   if (isInside) {
370     std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(theBaseShape));
371     if (!anEdge->isClosed()) {
372       // check the point is not on the boundary
373       GeomVertexPtr aVertex(new GeomAPI_Vertex(theProjectedPoint->x(),
374           theProjectedPoint->y(), theProjectedPoint->z()));
375       GeomAPI_ShapeExplorer anExp(anEdge, GeomAPI_Shape::VERTEX);
376       for (; anExp.more(); anExp.next()) {
377         GeomVertexPtr aCurV = anExp.current()->vertex();
378         isInside = !GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(aVertex, aCurV);
379       }
380     }
381   }
382   return isInside;
383 }
384
385 std::string doubleToString(double theValue)
386 {
387   std::string aValueStr;
388   char aBuf[50];
389   sprintf(aBuf, "%g", theValue);
390   aValueStr = std::string(aBuf);
391   return aValueStr;
392 }
393
394 #ifdef _DEBUG
395 std::string ModelGeomAlgo_Point2D::getPontAttributesInfo(
396                     const std::shared_ptr<ModelAPI_Feature>& theFeature,
397                     const std::set<std::shared_ptr<ModelAPI_Attribute> >& theAttributesOnly)
398 {
399   std::string anInfo;
400
401   std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
402                                                           GeomDataAPI_Point2D::typeId());
403   std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
404
405   for(; anIt != aLast; anIt++) {
406     AttributePtr anAttribute = *anIt;
407     if (anAttribute.get() && (theAttributesOnly.empty() ||
408         theAttributesOnly.find(anAttribute) != theAttributesOnly.end())) {
409     if (!anInfo.empty()) {
410       anInfo.append(", ");
411       anInfo.append("\n");
412     }
413     anInfo.append("    " + getPointAttributeInfo(anAttribute));
414     }
415   }
416   return anInfo;
417 }
418
419 std::string ModelGeomAlgo_Point2D::getPointAttributeInfo(
420                               const std::shared_ptr<ModelAPI_Attribute>& theAttribute)
421 {
422   std::string anInfo;
423   std::string aValue = "not defined";
424   std::string aType = theAttribute->attributeType();
425   if (aType == GeomDataAPI_Point2D::typeId()) {
426     std::shared_ptr<GeomDataAPI_Point2D> aPoint =
427       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
428     if (aPoint.get() && aPoint->isInitialized()) {
429       aValue = std::string("(" + doubleToString(aPoint->x()) + ", "+
430                             doubleToString(aPoint->y()) + ")");
431     }
432   }
433   anInfo.append(theAttribute->id() + ": " + aValue);
434
435   return anInfo;
436 }
437 #endif