]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchPlugin/SketchPlugin_BSplineBase.cpp
Salome HOME
Merge branch 'master' into occ/bsplines
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_BSplineBase.cpp
1 // Copyright (C) 2019-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_BSplineBase.h>
21
22 #include <SketchPlugin_ConstraintCoincidenceInternal.h>
23 #include <SketchPlugin_Line.h>
24 #include <SketchPlugin_MacroBSpline.h>
25 #include <SketchPlugin_Sketch.h>
26
27 #include <Events_InfoMessage.h>
28
29 #include <GeomAlgoAPI_EdgeBuilder.h>
30
31 #include <GeomAPI_BSpline2d.h>
32 #include <GeomAPI_Pnt2d.h>
33
34 #include <GeomDataAPI_Point2D.h>
35 #include <GeomDataAPI_Point2DArray.h>
36
37 #include <ModelAPI_AttributeDouble.h>
38 #include <ModelAPI_AttributeDoubleArray.h>
39 #include <ModelAPI_AttributeIntArray.h>
40 #include <ModelAPI_AttributeInteger.h>
41 #include <ModelAPI_ResultConstruction.h>
42 #include <ModelAPI_Session.h>
43 #include <ModelAPI_Validator.h>
44
45
46 SketchPlugin_BSplineBase::SketchPlugin_BSplineBase()
47   : SketchPlugin_SketchEntity()
48 {
49 }
50
51 void SketchPlugin_BSplineBase::initDerivedClassAttributes()
52 {
53   data()->addAttribute(POLES_ID(), GeomDataAPI_Point2DArray::typeId());
54   data()->addAttribute(WEIGHTS_ID(), ModelAPI_AttributeDoubleArray::typeId());
55   data()->addAttribute(KNOTS_ID(), ModelAPI_AttributeDoubleArray::typeId());
56   data()->addAttribute(MULTS_ID(), ModelAPI_AttributeIntArray::typeId());
57   data()->addAttribute(DEGREE_ID(), ModelAPI_AttributeInteger::typeId());
58
59   data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
60   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
61 }
62
63 void SketchPlugin_BSplineBase::execute()
64 {
65   SketchPlugin_Sketch* aSketch = sketch();
66   if(!aSketch) {
67     return;
68   }
69
70   AttributePoint2DArrayPtr aPolesArray =
71       std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
72   AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID());
73   AttributeDoubleArrayPtr aKnotsArray = data()->realArray(KNOTS_ID());
74   AttributeIntArrayPtr aMultsArray = data()->intArray(MULTS_ID());
75   AttributeIntegerPtr aDegreeAttr = data()->integer(DEGREE_ID());
76
77   // collect poles
78   std::list<GeomPnt2dPtr> aPoles2D;
79   for (int anIndex = 0; anIndex < aPolesArray->size(); ++anIndex) {
80     GeomPnt2dPtr aPole = aPolesArray->pnt(anIndex);
81     aPoles2D.push_back(aPole);
82   }
83   // collect weights
84   std::list<double> aWeights;
85   for (int anIndex = 0; anIndex < aWeightsArray->size(); ++anIndex)
86     aWeights.push_back(aWeightsArray->value(anIndex));
87   // collect knots
88   std::list<double> aKnots;
89   for (int anIndex = 0; anIndex < aKnotsArray->size(); ++anIndex)
90     aKnots.push_back(aKnotsArray->value(anIndex));
91   // collect multiplicities
92   std::list<int> aMults;
93   for (int anIndex = 0; anIndex < aMultsArray->size(); ++anIndex)
94     aMults.push_back(aMultsArray->value(anIndex));
95
96   // create result B-spline curve
97   GeomShapePtr anEdge = GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(aSketch->coordinatePlane(),
98       aPoles2D, aWeights, aKnots, aMults, aDegreeAttr->value(), isPeriodic());
99
100   ResultConstructionPtr aResult = document()->createConstruction(data(), 0);
101   aResult->setShape(anEdge);
102   aResult->setIsInHistory(false);
103   setResult(aResult, 0);
104 }
105
106 bool SketchPlugin_BSplineBase::isFixed() {
107   return data()->selection(EXTERNAL_ID())->context().get() != NULL;
108 }
109
110 void SketchPlugin_BSplineBase::attributeChanged(const std::string& theID) {
111   // the second condition for unability to move external segments anywhere
112   if (theID == EXTERNAL_ID() || isFixed()) {
113     std::shared_ptr<GeomAPI_Shape> aSelection = data()->selection(EXTERNAL_ID())->value();
114     if (!aSelection) {
115       // empty shape in selection shows that the shape is equal to context
116       ResultPtr anExtRes = selection(EXTERNAL_ID())->context();
117       if (anExtRes)
118         aSelection = anExtRes->shape();
119     }
120 ////    // update arguments due to the selection value
121 ////    if (aSelection && !aSelection->isNull() && aSelection->isEdge()) {
122 ////      std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aSelection));
123 ////      std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
124 ////
125 ////      bool aWasBlocked = data()->blockSendAttributeUpdated(true);
126 ////      std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
127 ////        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
128 ////      aCenterAttr->setValue(sketch()->to2D(anEllipse->center()));
129 ////
130 ////      std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
131 ////        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FIRST_FOCUS_ID()));
132 ////      aFocusAttr->setValue(sketch()->to2D(anEllipse->firstFocus()));
133 ////
134 ////      std::shared_ptr<GeomDataAPI_Point2D> aStartAttr =
135 ////        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_ID()));
136 ////      aStartAttr->setValue(sketch()->to2D(anEdge->firstPoint()));
137 ////
138 ////      std::shared_ptr<GeomDataAPI_Point2D> aEndAttr =
139 ////        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_ID()));
140 ////      aEndAttr->setValue(sketch()->to2D(anEdge->lastPoint()));
141 ////
142 ////      real(MAJOR_RADIUS_ID())->setValue(anEllipse->majorRadius());
143 ////      real(MINOR_RADIUS_ID())->setValue(anEllipse->minorRadius());
144 ////
145 ////      double aStartParam, aMidParam, aEndParam;
146 ////      anEllipse->parameter(anEdge->firstPoint(), tolerance, aStartParam);
147 ////      anEllipse->parameter(anEdge->middlePoint(), tolerance, aMidParam);
148 ////      anEllipse->parameter(anEdge->lastPoint(), tolerance, aEndParam);
149 ////      if (aEndParam < aStartParam)
150 ////        aEndParam += 2.0 * PI;
151 ////      if (aMidParam < aStartParam)
152 ////        aMidParam += 2.0 * PI;
153 ////      boolean(REVERSED_ID())->setValue(aMidParam > aEndParam);
154 ////
155 ////      data()->blockSendAttributeUpdated(aWasBlocked, false);
156 ////
157 ////      fillCharacteristicPoints();
158 ////    }
159   }
160 }
161
162 bool SketchPlugin_BSplineBase::customAction(const std::string& theActionId)
163 {
164   // parse for the action and an index divided by '#'
165   std::string anAction;
166   int anIndex = -1;
167   size_t pos = theActionId.find('#');
168   if (pos != std::string::npos) {
169     anAction = theActionId.substr(0, pos);
170     anIndex = std::stoi(theActionId.substr(pos + 1));
171   }
172
173   if (anAction == ADD_POLE_ACTION_ID()) {
174     return addPole(anIndex);
175   }
176
177   std::string aMsg = "Error: Feature \"%1\" does not support action \"%2\".";
178   Events_InfoMessage("SketchPlugin_BSplineBase", aMsg).arg(getKind()).arg(anAction).send();
179   return false;
180 }
181
182 bool SketchPlugin_BSplineBase::addPole(const int theAfter)
183 {
184   AttributePoint2DArrayPtr aPolesArray =
185       std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
186   AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID());
187
188   int anAfter = (!isPeriodic() && theAfter == aPolesArray->size() - 1) ? theAfter - 1 : theAfter;
189
190   // find internal coincidences applied to the poles with greater indices
191   std::list<AttributeIntegerPtr> aCoincidentPoleIndex;
192   bool hasAuxSegment = false;
193   const std::set<AttributePtr>& aRefs = data()->refsToMe();
194   for (std::set<AttributePtr>::iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) {
195     FeaturePtr aFeature = ModelAPI_Feature::feature((*anIt)->owner());
196     if (aFeature->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
197       AttributeIntegerPtr anIndex;
198       if ((*anIt)->id() == SketchPlugin_ConstraintCoincidenceInternal::ENTITY_A())
199         anIndex = aFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A());
200       else if ((*anIt)->id() == SketchPlugin_ConstraintCoincidenceInternal::ENTITY_B())
201         anIndex = aFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
202
203       if (anIndex && anIndex->isInitialized()) {
204         if (anIndex->value() > anAfter)
205           aCoincidentPoleIndex.push_back(anIndex);
206         else if (anIndex->value() == anAfter && !hasAuxSegment) {
207           // check the constrained object is a segment of the control polygon
208           const std::string& anOtherAttr =
209               (*anIt)->id() == SketchPlugin_ConstraintCoincidenceInternal::ENTITY_A() ?
210                                SketchPlugin_ConstraintCoincidenceInternal::ENTITY_B() :
211                                SketchPlugin_ConstraintCoincidenceInternal::ENTITY_A();
212           AttributeRefAttrPtr aRefAttr = aFeature->refattr(anOtherAttr);
213           if (aRefAttr && !aRefAttr->isObject() &&
214               aRefAttr->attr()->id() == SketchPlugin_Line::START_ID()) {
215             hasAuxSegment = true;
216             aCoincidentPoleIndex.push_back(anIndex);
217           }
218         }
219       }
220     }
221   }
222
223   bool aWasBlocked = data()->blockSendAttributeUpdated(true);
224
225   // add new pole and default weight
226   std::list<GeomPnt2dPtr> aPoles;
227   aPolesArray->setSize(aPolesArray->size() + 1);
228   aPolesArray->setPnt(aPolesArray->size() - 1, aPolesArray->pnt(0)); // for periodic spline
229   for (int i = aPolesArray->size() - 2; i > anAfter; --i) {
230     aPoles.push_front(aPolesArray->pnt(i));
231     aPolesArray->setPnt(i + 1, aPoles.front());
232   }
233
234   GeomPnt2dPtr aCurPole = aPolesArray->pnt(anAfter);
235   GeomPnt2dPtr aNextPole = aPolesArray->pnt(anAfter + 1);
236   aPolesArray->setPnt(anAfter + 1, (aCurPole->x() + aNextPole->x()) * 0.5,
237                                    (aCurPole->y() + aNextPole->y()) * 0.5);
238   for (int i = anAfter + 1; i >= 0; --i)
239     aPoles.push_front(aPolesArray->pnt(i));
240
241   std::list<double> aWeights;
242   for (int i = 0; i < aWeightsArray->size(); ++i) {
243     aWeights.push_back(aWeightsArray->value(i));
244     if (i == anAfter)
245       aWeights.push_back(1.0); // default weight
246   }
247   aWeightsArray->setSize(aWeightsArray->size() + 1);
248   std::list<double>::iterator aWIt = aWeights.begin();
249   for (int i = 0; i < aWeightsArray->size(); ++i, ++aWIt)
250     aWeightsArray->setValue(i, *aWIt);
251
252   // recalculate knots and multiplicities
253   std::shared_ptr<GeomAPI_BSpline2d> aBSplineCurve(
254       new GeomAPI_BSpline2d(aPoles, aWeights, isPeriodic()));
255
256   integer(DEGREE_ID())->setValue(aBSplineCurve->degree());
257
258   AttributeDoubleArrayPtr aKnotsAttr = data()->realArray(SketchPlugin_BSplineBase::KNOTS_ID());
259   std::list<double> aKnots = aBSplineCurve->knots();
260   int aSize = (int)aKnots.size();
261   aKnotsAttr->setSize(aSize);
262   std::list<double>::iterator aKIt = aKnots.begin();
263   for (int index = 0; index < aSize; ++index, ++aKIt)
264     aKnotsAttr->setValue(index, *aKIt);
265
266   AttributeIntArrayPtr aMultsAttr = data()->intArray(SketchPlugin_BSplineBase::MULTS_ID());
267   std::list<int> aMults = aBSplineCurve->mults();
268   aSize = (int)aMults.size();
269   aMultsAttr->setSize(aSize);
270   std::list<int>::iterator aMIt = aMults.begin();
271   for (int index = 0; index < aSize; ++index, ++aMIt)
272     aMultsAttr->setValue(index, *aMIt);
273
274   data()->blockSendAttributeUpdated(aWasBlocked, true);
275
276   // update indices of internal coincidences
277   for (std::list<AttributeIntegerPtr>::iterator aCIt = aCoincidentPoleIndex.begin();
278        aCIt != aCoincidentPoleIndex.end(); ++aCIt)
279     (*aCIt)->setValue((*aCIt)->value() + 1);
280
281   // create auxiliary segment and pole updating the control polygon
282   SketchPlugin_MacroBSpline::createAuxiliaryPole(aPolesArray, anAfter + 1);
283   if (hasAuxSegment)
284     SketchPlugin_MacroBSpline::createAuxiliarySegment(aPolesArray, anAfter, anAfter + 1);
285
286   return true;
287 }