]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketcherPrs/SketcherPrs_PositionMgr.cpp
Salome HOME
65b1d045166f3044044e2917d7f1119f52af0e71
[modules/shaper.git] / src / SketcherPrs / SketcherPrs_PositionMgr.cpp
1 // Copyright (C) 2014-2017  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
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include "SketcherPrs_PositionMgr.h"
22 #include "SketcherPrs_Tools.h"
23
24 #include <GeomAPI_Edge.h>
25 #include <GeomAPI_Curve.h>
26 #include <GeomAPI_Vertex.h>
27 #include <GeomAPI_Dir.h>
28 #include <GeomAPI_Ax3.h>
29 #include <GeomAPI_Circ.h>
30
31 #include <GeomDataAPI_Point2D.h>
32
33 #include <SketchPlugin_Line.h>
34 #include <SketchPlugin_Circle.h>
35 #include <SketchPlugin_Arc.h>
36 #include <SketchPlugin_ConstraintTangent.h>
37 #include <SketchPlugin_ConstraintPerpendicular.h>
38
39 #include <BRepExtrema_ExtPC.hxx>
40 #include <TopoDS_Vertex.hxx>
41 #include <Geom_Curve.hxx>
42 #include <TColGeom_SequenceOfCurve.hxx>
43 #include <gp_Dir.hxx>
44
45 #include <array>
46
47 static SketcherPrs_PositionMgr* MyPosMgr = NULL;
48
49 #define PI 3.1415926535897932
50
51 // The class is implemented as a singlton
52 SketcherPrs_PositionMgr* SketcherPrs_PositionMgr::get()
53 {
54   if (MyPosMgr == NULL)
55     MyPosMgr = new SketcherPrs_PositionMgr();
56   return MyPosMgr;
57 }
58
59 SketcherPrs_PositionMgr::SketcherPrs_PositionMgr()
60 {
61 }
62
63
64 int SketcherPrs_PositionMgr::getPositionIndex(ObjectPtr theLine,
65                                               const SketcherPrs_SymbolPrs* thePrs)
66 {
67   if (myShapes.count(theLine) == 1) {
68     // Find the map and add new [Presentation - Index] pair
69     PositionsMap& aPosMap = myShapes[theLine];
70     if (aPosMap.count(thePrs) == 1) {
71       // return existing index
72       return aPosMap[thePrs];
73     } else {
74       // Add a new [Presentation - Index] pair
75       int aInd = int(aPosMap.size());
76       aPosMap[thePrs] = aInd;
77       return aInd;
78     }
79   } else {
80     // Create a new map with initial index
81     PositionsMap aPosMap;
82     aPosMap[thePrs] = 0;
83     myShapes[theLine] = aPosMap;
84     return 0;
85   }
86 }
87
88
89 bool SketcherPrs_PositionMgr::isPntConstraint(const std::string& theName)
90 {
91   static std::list<std::string> aConstraints;
92   if (aConstraints.size() == 0) {
93     aConstraints.push_back(SketchPlugin_ConstraintTangent::ID());
94     aConstraints.push_back(SketchPlugin_ConstraintPerpendicular::ID());
95   }
96   std::list<std::string>::const_iterator aIt;
97   for (aIt = aConstraints.cbegin(); aIt != aConstraints.cend(); ++aIt) {
98     if ((*aIt) == theName)
99       return true;
100   }
101   return false;
102 }
103
104 bool containsPoint(const FeaturePtr& theFeature, GeomPnt2dPtr thePnt2d, GeomPointPtr thePos)
105 {
106   if (theFeature->getKind() == SketchPlugin_Line::ID()) {
107     AttributePoint2DPtr aSPnt1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
108       theFeature->data()->attribute(SketchPlugin_Line::START_ID()));
109     AttributePoint2DPtr aSPnt2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
110       theFeature->data()->attribute(SketchPlugin_Line::END_ID()));
111
112     GeomPnt2dPtr aPnt1 = aSPnt1->pnt();
113     GeomPnt2dPtr aPnt2 = aSPnt2->pnt();
114
115     if (aPnt1->isEqual(thePnt2d) || aPnt2->isEqual(thePnt2d))
116       return true;
117   } else if ((theFeature->getKind() == SketchPlugin_Circle::ID()) ||
118              (theFeature->getKind() == SketchPlugin_Arc::ID())) {
119     GeomCurvePtr aCurve;
120     ObjectPtr aResObj;
121     std::list<ResultPtr> aResults = theFeature->results();
122     std::list<ResultPtr>::const_iterator aIt;
123     for (aIt = aResults.cbegin(); aIt != aResults.cend(); aIt++) {
124       GeomShapePtr aShp = SketcherPrs_Tools::getShape((*aIt));
125       if (aShp->isEdge()) {
126         aResObj = (*aIt);
127         aCurve = std::shared_ptr<GeomAPI_Curve>(new GeomAPI_Curve(aShp));
128         break;
129       }
130     }
131     if (aCurve.get()) {
132       double aStart = aCurve->startParam();
133       double aEnd = aCurve->endParam();
134       GeomCirclePtr  aCircle = GeomCirclePtr(new GeomAPI_Circ(aCurve));
135       double aParam;
136       if (aCircle->parameter(thePos, 1.e-4, aParam) && (aParam >= aStart) && (aParam <= aEnd))
137         return true;
138     }
139   }
140   return false;
141 }
142
143 const std::array<int, 2>& SketcherPrs_PositionMgr::getPositionIndex(GeomPointPtr thePos,
144                                               const SketcherPrs_SymbolPrs* thePrs)
145 {
146   if (myPntShapes.count(thePrs->feature()) == 0) {
147     // Renumerate positions around the specified constraint point for all constraints
148     GeomAx3Ptr aAx3 = thePrs->plane();
149     ModelAPI_CompositeFeature* aOwner = thePrs->sketcher();
150     GeomPnt2dPtr aPnt2d = thePos->to2D(aAx3->origin(), aAx3->dirX(), aAx3->dirY());
151
152     int aNbSubs = aOwner->numberOfSubs();
153     int aId = 0;
154     std::list<const ModelAPI_Feature*> aFeaList;
155     for (int i = 0; i < aNbSubs; i++) {
156       FeaturePtr aFeature = aOwner->subFeature(i);
157
158       if (myPntShapes.count(aFeature.get()) == 1) {
159         myPntShapes[aFeature.get()][0] = aId;
160         aId++;
161         aFeaList.push_back(aFeature.get());
162       } else {
163         if (isPntConstraint(aFeature->getKind())) {
164           DataPtr aData = aFeature->data();
165           AttributeRefAttrPtr aObjRef = aData->refattr(SketchPlugin_Constraint::ENTITY_A());
166           FeaturePtr aObj = ModelAPI_Feature::feature(aObjRef->object());
167           bool aContains = false;
168           if (containsPoint(aObj, aPnt2d, thePos)) {
169             aContains = true;
170           } else {
171             aObjRef = aData->refattr(SketchPlugin_Constraint::ENTITY_B());
172             aObj = ModelAPI_Feature::feature(aObjRef->object());
173             if (containsPoint(aObj, aPnt2d, thePos)) {
174               aContains = true;
175             }
176           }
177           if (aContains) {
178             myPntShapes[aFeature.get()][0] = aId;
179             aId++;
180             aFeaList.push_back(aFeature.get());
181           }
182         }
183       }
184     }
185     int aSize = (int) aFeaList.size();
186     std::list<const ModelAPI_Feature*>::const_iterator aIt;
187     for (aIt = aFeaList.cbegin(); aIt != aFeaList.cend(); aIt++) {
188       myPntShapes[*aIt][1] = aSize;
189     }
190   }
191   return myPntShapes[thePrs->feature()];
192 }
193
194 //*****************************************************************
195 gp_Vec getVector(ObjectPtr theShape, GeomDirPtr theDir, gp_Pnt theP)
196 {
197   gp_Vec aVec;
198   std::shared_ptr<GeomAPI_Shape> aShape = SketcherPrs_Tools::getShape(theShape);
199   if (aShape->isEdge()) {
200     std::shared_ptr<GeomAPI_Curve> aCurve =
201       std::shared_ptr<GeomAPI_Curve>(new GeomAPI_Curve(aShape));
202
203     if (aCurve->isCircle()) {
204       GeomEdgePtr aEdgePtr(new GeomAPI_Edge(aShape));
205       GeomVertexPtr aVertexPtr(new GeomAPI_Vertex(theP.X(), theP.Y(), theP.Z()));
206       BRepExtrema_ExtPC aExtrema(aVertexPtr->impl<TopoDS_Vertex>(),
207                                  aEdgePtr->impl<TopoDS_Edge>());
208       int aNb = aExtrema.NbExt();
209       if (aNb > 0) {
210         for (int i = 1; i <= aNb; i++) {
211           if (aExtrema.IsMin(i)) {
212             double aParam = aExtrema.Parameter(i);
213             Handle(Geom_Curve) aCurv = aCurve->impl<Handle_Geom_Curve>();
214             gp_Pnt aP;
215             aCurv->D1(aParam, aP, aVec);
216             break;
217           }
218         }
219       }
220     } else {
221       GeomPointPtr aPnt1 = aCurve->getPoint(aCurve->endParam());
222       GeomPointPtr aPnt2 = aCurve->getPoint(aCurve->startParam());
223
224       gp_Pnt aPn2 = aPnt2->impl<gp_Pnt>();
225       if (aPn2.IsEqual(theP, Precision::Confusion()))
226         aVec = gp_Vec(aPn2, aPnt1->impl<gp_Pnt>());
227       else
228         aVec = gp_Vec(aPnt1->impl<gp_Pnt>(), aPn2);
229     }
230   } else {
231     aVec = gp_Vec(theDir->impl<gp_Dir>());
232   }
233   return aVec;
234 }
235
236 //*****************************************************************
237 gp_Pnt SketcherPrs_PositionMgr::getPosition(ObjectPtr theShape,
238                                             const SketcherPrs_SymbolPrs* thePrs,
239                                             double theStep, GeomPointPtr thePnt)
240 {
241   std::shared_ptr<GeomAPI_Shape> aShape = SketcherPrs_Tools::getShape(theShape);
242   gp_Pnt aP; // Central point
243
244   if (thePnt.get()) {
245     return getPointPosition(theShape, thePrs, theStep, thePnt);
246   } else {
247     if (aShape->isEdge()) {
248       std::shared_ptr<GeomAPI_Curve> aCurve =
249         std::shared_ptr<GeomAPI_Curve>(new GeomAPI_Curve(aShape));
250       // this is a circle or arc
251       double aMidParam = (aCurve->startParam() + aCurve->endParam()) / 2.;
252       std::shared_ptr<GeomAPI_Pnt> aPnt = aCurve->getPoint(aMidParam);
253       aP = aPnt->impl<gp_Pnt>();
254     } else {
255       // This is a point
256       std::shared_ptr<GeomAPI_Vertex> aVertex =
257         std::shared_ptr<GeomAPI_Vertex>(new GeomAPI_Vertex(aShape));
258       std::shared_ptr<GeomAPI_Pnt> aPnt = aVertex->point();
259       aP = aPnt->impl<gp_Pnt>();
260     }
261   }
262   // main vector
263   gp_Vec aVec1 = getVector(theShape, thePrs->plane()->dirX(), aP);
264
265   // Compute shifting vector for a one symbol
266   gp_Vec aShift = aVec1.Crossed(thePrs->plane()->normal()->impl<gp_Dir>());
267   aShift.Normalize();
268   aShift.Multiply(theStep * 0.8);
269
270   // Shift the position coordinate according to position index
271   int aPos = getPositionIndex(theShape, thePrs);
272   int aM = 1;
273   if ((aPos % 2) == 0) {
274     // Even position
275     aP.Translate(aShift);
276     if (aPos > 0) {
277       if (aPos % 4 == 0)
278         aM = aPos / 4;
279       else
280         aM = -(aPos + 2) / 4;
281     }
282   } else {
283     // Odd position
284     aP.Translate(-aShift);
285     if (aPos > 1) {
286       if ((aPos - 1) % 4 == 0)
287         aM = (aPos - 1) / 4;
288       else
289         aM = -(aPos + 1) / 4;
290     }
291   }
292   if (aPos > 1) {
293     // Normalize vector along the line
294     aVec1.Normalize();
295     aVec1.Multiply(theStep);
296     aP.Translate(aVec1.Multiplied(aM));
297   }
298   return aP;
299 }
300
301
302 //*****************************************************************
303 //! Returns curves connected to the given point
304 std::list<ObjectPtr> getCurves(const GeomPointPtr& thePnt, const SketcherPrs_SymbolPrs* thePrs)
305 {
306   std::list<ObjectPtr> aList;
307   GeomAx3Ptr aAx3 = thePrs->plane();
308   ModelAPI_CompositeFeature* aOwner = thePrs->sketcher();
309   GeomPnt2dPtr aPnt2d = thePnt->to2D(aAx3->origin(), aAx3->dirX(), aAx3->dirY());
310
311   int aNbSubs = aOwner->numberOfSubs();
312   for (int i = 0; i < aNbSubs; i++) {
313     FeaturePtr aFeature = aOwner->subFeature(i);
314     if (!aFeature->firstResult().get()) // There is no result
315       continue;
316
317     if (aFeature->getKind() == SketchPlugin_Line::ID()) {
318       AttributePoint2DPtr aSPnt1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
319         aFeature->data()->attribute(SketchPlugin_Line::START_ID()));
320       AttributePoint2DPtr aSPnt2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
321         aFeature->data()->attribute(SketchPlugin_Line::END_ID()));
322
323       GeomPnt2dPtr aPnt1 = aSPnt1->pnt();
324       GeomPnt2dPtr aPnt2 = aSPnt2->pnt();
325
326       if (aPnt1->isEqual(aPnt2d) || aPnt2->isEqual(aPnt2d)) {
327         GeomShapePtr aShp = SketcherPrs_Tools::getShape(aFeature->firstResult());
328         GeomCurvePtr aCurv = std::shared_ptr<GeomAPI_Curve>(new GeomAPI_Curve(aShp));
329         aList.push_back(aFeature->firstResult());
330       }
331     } else if ((aFeature->getKind() == SketchPlugin_Circle::ID()) ||
332               (aFeature->getKind() == SketchPlugin_Arc::ID())) {
333       GeomCurvePtr aCurve;
334       ObjectPtr aResObj;
335       std::list<ResultPtr> aResults = aFeature->results();
336       std::list<ResultPtr>::const_iterator aIt;
337       for (aIt = aResults.cbegin(); aIt != aResults.cend(); aIt++) {
338         GeomShapePtr aShp = SketcherPrs_Tools::getShape((*aIt));
339         if (aShp->isEdge()) {
340           aResObj = (*aIt);
341           aCurve = std::shared_ptr<GeomAPI_Curve>(new GeomAPI_Curve(aShp));
342           break;
343         }
344       }
345       if (aCurve.get()) {
346         double aStart = aCurve->startParam();
347         double aEnd = aCurve->endParam();
348         GeomCirclePtr  aCircle = GeomCirclePtr(new GeomAPI_Circ(aCurve));
349         double aParam;
350         if (aCircle->parameter(thePnt, 1.e-4, aParam) && (aParam >= aStart) && (aParam <= aEnd))
351           aList.push_back(aResObj);
352       }
353     }
354   }
355   return aList;
356 }
357
358 //*****************************************************************
359 gp_Pnt SketcherPrs_PositionMgr::getPointPosition(
360   ObjectPtr theLine, const SketcherPrs_SymbolPrs* thePrs,
361   double theStep, GeomPointPtr thePnt)
362 {
363   gp_Pnt aP = thePnt->impl<gp_Pnt>();
364   GeomDirPtr aNormal = thePrs->plane()->normal();
365   gp_Dir aNormDir = aNormal->impl<gp_Dir>();
366
367   std::list<ObjectPtr> aCurves = getCurves(thePnt, thePrs);
368   std::list<ObjectPtr>::const_iterator aItCurv;
369   std::list<gp_Vec> aVectorsList;
370   // Calculate all vectors
371   for (aItCurv = aCurves.cbegin(); aItCurv != aCurves.cend(); aItCurv++) {
372     aVectorsList.push_back(getVector((*aItCurv), thePrs->plane()->dirX(), aP));
373   }
374
375   // Position of the symbol
376   const std::array<int, 2>& aPos = getPositionIndex(thePnt, thePrs);
377
378   // Angle size of a symbol
379   double aAngleStep = PI * 50./180.;
380
381   std::list<gp_Vec>::const_iterator aItVec;
382   std::list<double> aAngles;
383   std::list<gp_Vec> aVectors;
384   // Select closest vectors and calculate angles between base vector and closest vector
385   for (aItVec = aVectorsList.cbegin(); aItVec != aVectorsList.cend(); aItVec++) {
386     std::list<gp_Vec>::const_iterator aIt;
387     double aMinAng = 0;
388     gp_Vec aVec = *aItVec;
389     for (aIt = aVectorsList.cbegin(); aIt != aVectorsList.cend(); aIt++) {
390       double aAng = aVec.AngleWithRef(*aIt, aNormDir);
391       if (aAng != 0) {
392         if (aAng < 0)
393           aAng = 2 * PI + aAng;
394
395         if (aMinAng == 0)
396           aMinAng = aAng;
397         else if (aAng < aMinAng) {
398           aMinAng = aAng;
399         }
400       }
401     }
402     aVectors.push_back(aVec);
403     aAngles.push_back(aMinAng);
404   }
405
406   int aPosCount = 0;
407   double aAng;
408   std::list<double>::const_iterator aItAng;
409
410   double aAngPos;
411   gp_Vec aVecPos;
412   bool aHasPlace = false;
413   int aIntId = 0; // a position inside a one sector
414   while (aPosCount < aPos[1]) {
415     for (aItAng = aAngles.cbegin(), aItVec = aVectors.cbegin();
416          aItAng != aAngles.cend(); ++aItAng, ++aItVec) {
417       aAng = (*aItAng);
418       int Nb = int(aAng / aAngleStep);
419       aPosCount += Nb;
420
421       if ((!aHasPlace) && (aPosCount >= (aPos[0] + 1))) {
422         aHasPlace = true;
423         aAngPos = (*aItAng);
424         aVecPos = (*aItVec);
425         aIntId = aPos[0] - (aPosCount - Nb);
426       }
427     }
428     if (aPosCount < aPos[1]) {
429       aAngleStep -= 0.1;
430       aHasPlace = false;
431       aPosCount = 0;
432     }
433   }
434
435   gp_Ax1 aRotAx(aP, aNormDir);
436   if (aHasPlace) {
437     // rotate base vector on a necessary angle
438     gp_Vec aShift = aVecPos.Rotated(aRotAx, aAngleStep + aAngleStep * aIntId);
439     aShift.Normalize();
440     aShift.Multiply(theStep * 1.5);
441     return aP.Translated(aShift);
442   }
443   return aP;
444 }
445
446 //*****************************************************************
447 void SketcherPrs_PositionMgr::deleteConstraint(const SketcherPrs_SymbolPrs* thePrs)
448 {
449   std::map<ObjectPtr, PositionsMap>::iterator aIt;
450   std::list<ObjectPtr> aToDel;
451   // Clear map for deleted presentation
452   for (aIt = myShapes.begin(); aIt != myShapes.end(); ++aIt) {
453     PositionsMap& aPosMap = aIt->second;
454     if (aPosMap.count(thePrs) > 0) {
455       // Erase index
456       aPosMap.erase(aPosMap.find(thePrs));
457       if (aPosMap.size() == 0)
458         // Delete the map
459         aToDel.push_back(aIt->first);
460       else {
461         // Reindex objects positions in order to avoid spaces
462         PositionsMap::iterator aIt;
463         int i = 0;
464         for (aIt = aPosMap.begin(); aIt != aPosMap.end(); aIt++, i++)
465           aIt->second = i;
466       }
467     }
468   }
469   std::list<ObjectPtr>::const_iterator aListIt;
470   for (aListIt = aToDel.cbegin(); aListIt != aToDel.cend(); ++aListIt) {
471     myShapes.erase(*aListIt);
472   }
473 }