1 // Copyright (C) 2014-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_Validators.h"
22 #include "SketchPlugin_Arc.h"
23 #include "SketchPlugin_BSpline.h"
24 #include "SketchPlugin_BSplinePeriodic.h"
25 #include "SketchPlugin_Circle.h"
26 #include "SketchPlugin_ConstraintCoincidence.h"
27 #include "SketchPlugin_ConstraintCoincidenceInternal.h"
28 #include "SketchPlugin_ConstraintDistance.h"
29 #include "SketchPlugin_ConstraintRigid.h"
30 #include "SketchPlugin_ConstraintTangent.h"
31 #include "SketchPlugin_Ellipse.h"
32 #include "SketchPlugin_EllipticArc.h"
33 #include "SketchPlugin_Fillet.h"
34 #include "SketchPlugin_CurveFitting.h"
35 #include "SketchPlugin_Line.h"
36 #include "SketchPlugin_MacroArc.h"
37 #include "SketchPlugin_MacroCircle.h"
38 #include "SketchPlugin_MultiRotation.h"
39 #include "SketchPlugin_Offset.h"
40 #include "SketchPlugin_Point.h"
41 #include "SketchPlugin_Sketch.h"
42 #include "SketchPlugin_Trim.h"
43 #include "SketchPlugin_Tools.h"
45 #include "SketcherPrs_Tools.h"
47 #include <Events_InfoMessage.h>
49 #include <Locale_Convert.h>
51 #include <ModelAPI_Data.h>
52 #include <ModelAPI_Validator.h>
53 #include <ModelAPI_AttributeDouble.h>
54 #include <ModelAPI_AttributeInteger.h>
55 #include <ModelAPI_AttributeRefAttr.h>
56 #include <ModelAPI_AttributeRefAttrList.h>
57 #include <ModelAPI_AttributeRefList.h>
58 #include <ModelAPI_AttributeSelectionList.h>
59 #include <ModelAPI_AttributeString.h>
60 #include <ModelAPI_Session.h>
61 #include <ModelAPI_Tools.h>
62 #include <ModelAPI_ResultConstruction.h>
64 #include <ModelGeomAlgo_Point2D.h>
65 #include <ModelGeomAlgo_Shape.h>
67 #include <GeomAlgoAPI_EdgeBuilder.h>
68 #include <GeomAlgoAPI_ShapeTools.h>
70 #include <GeomAPI_BSpline.h>
71 #include <GeomAPI_Circ.h>
72 #include <GeomAPI_Dir2d.h>
73 #include <GeomAPI_Ellipse.h>
74 #include <GeomAPI_Lin.h>
75 #include <GeomAPI_Edge.h>
76 #include <GeomAPI_Vertex.h>
78 #include <GeomDataAPI_Point2D.h>
79 #include <GeomDataAPI_Point2DArray.h>
85 #pragma warning(disable: 4100)
88 const double tolerance = 1.e-7;
90 static bool isSpline(FeaturePtr theFeature)
92 return theFeature && (theFeature->getKind() == SketchPlugin_BSpline::ID() ||
93 theFeature->getKind() == SketchPlugin_BSplinePeriodic::ID());
97 bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribute,
98 const std::list<std::string>& theArguments,
99 Events_InfoMessage& theError) const
101 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
102 theError = "The attribute with the %1 type is not processed";
103 theError.arg(theAttribute->attributeType());
107 // there is a check whether the feature contains a point and a linear edge or two point values
108 std::string aParamA = theArguments.front();
109 SessionPtr aMgr = ModelAPI_Session::get();
110 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
112 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
114 bool isObject = aRefAttr->isObject();
116 // an attribute is a point. A point value is valid always for the distance
119 // 1. check whether the references object is a linear
120 ObjectPtr anObject = aRefAttr->object();
122 const ModelAPI_AttributeValidator* aShapeValidator =
123 dynamic_cast<const ModelAPI_AttributeValidator*>(
124 aFactory->validator("GeomValidators_ShapeType"));
125 std::list<std::string> anArguments;
126 anArguments.push_back("circle");
127 Events_InfoMessage aCircleError;
128 bool aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aCircleError);
129 // the circle line is not a valid case
131 theError = "Circle can not be used in distance constraint";
136 anArguments.push_back("line");
137 Events_InfoMessage aLineError;
138 aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aLineError);
139 // if the attribute value is not a line, that means it is a vertex. A vertex is always valid
141 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
142 // If it is a line then we have to check that first attribute id not a line
143 std::shared_ptr<SketchPlugin_Feature> aSFeature =
144 std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
145 SketchPlugin_Sketch* aSketch = aSFeature->sketch();
146 std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(aSketch);
147 std::shared_ptr<GeomDataAPI_Point2D> aPoint = SketcherPrs_Tools::getFeaturePoint(
148 aFeature->data(), aParamA, aPlane);
150 theError = "One of parameters of distance constraint should be a point";
158 bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute,
159 const std::list<std::string>& theArguments,
160 Events_InfoMessage& theError) const
162 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
163 theError = "The attribute with the %1 type is not processed";
164 theError.arg(theAttribute->attributeType());
168 // there is a check whether the feature contains a point and a linear edge or two point values
169 std::string aParamA = theArguments.front();
171 FeaturePtr anAttributeFeature =
172 std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
173 AttributeRefAttrPtr aRefAttr =
174 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
176 bool isObject = aRefAttr->isObject();
177 ObjectPtr anObject = aRefAttr->object();
178 if (!isObject || !anObject.get()) {
179 theError = "It uses an empty object";
183 FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
185 AttributeRefAttrPtr aOtherAttr = anAttributeFeature->data()->refattr(aParamA);
186 ObjectPtr aOtherObject = aOtherAttr->object();
187 FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
191 if (aRefFea->getKind() == SketchPlugin_Line::ID() &&
192 aOtherFea->getKind() == SketchPlugin_Line::ID()) {
193 theError = "Two segments cannot be tangent";
196 else if (isSpline(aRefFea) && isSpline(aOtherFea)) {
197 theError = "Two B-splines cannot be tangent";
202 bool hasSpline = isSpline(aRefFea);
203 if (!hasSpline && isSpline(aOtherFea)) {
205 std::swap(aRefFea, aOtherFea);
208 auto isApplicableCoincidence = [](FeaturePtr theFeature, const std::string& theAttrName) {
209 AttributeRefAttrPtr aRefAttr = theFeature->refattr(theAttrName);
210 if (aRefAttr->isObject())
212 AttributePtr anAttr = aRefAttr->attr();
213 FeaturePtr anOwner = ModelAPI_Feature::feature(anAttr->owner());
214 AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
216 return anOwner->getKind() == SketchPlugin_BSpline::ID() &&
217 (aPointAttr->id() == SketchPlugin_BSpline::START_ID() ||
218 aPointAttr->id() == SketchPlugin_BSpline::END_ID());
221 AttributePoint2DArrayPtr aPntArray =
222 std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(anAttr);
223 if (aPntArray && anOwner->getKind() == SketchPlugin_BSpline::ID()) {
224 // check index of the pole
225 AttributeIntegerPtr anIndex = theAttrName == SketchPlugin_Constraint::ENTITY_A() ?
226 theFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A()) :
227 theFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
228 return anIndex && (anIndex->value() == 0 || anIndex->value() == aPntArray->size() - 1);
234 AttributePoint2DArrayPtr aBSplinePoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
235 aRefFea->attribute(SketchPlugin_BSplineBase::POLES_ID()));
236 // additional check the B-spline edge and the other edge have a coincident boundary point
237 std::set<FeaturePtr> aCoincidences = SketchPlugin_Tools::findCoincidentConstraints(aRefFea);
238 for (std::set<FeaturePtr>::iterator anIt = aCoincidences.begin();
239 anIt != aCoincidences.end() && !isValid; ++anIt) {
240 std::set<FeaturePtr> aCoinc;
241 if (isApplicableCoincidence(*anIt, SketchPlugin_Constraint::ENTITY_A()))
242 SketchPlugin_Tools::findCoincidences(*anIt, SketchPlugin_Constraint::ENTITY_B(),
244 else if (isApplicableCoincidence(*anIt, SketchPlugin_Constraint::ENTITY_B()))
245 SketchPlugin_Tools::findCoincidences(*anIt, SketchPlugin_Constraint::ENTITY_A(),
248 std::set<FeaturePtr>::iterator aFoundCoinc = aCoinc.find(aOtherFea);
249 if (aFoundCoinc != aCoinc.end()) {
250 // do not take into account internal constraints
251 AttributeReferencePtr aParent =
252 (*aFoundCoinc)->reference(SketchPlugin_SketchEntity::PARENT_ID());
253 isValid = !aParent || !aParent->isInitialized() || aParent->value() != aRefFea;
261 bool SketchPlugin_PerpendicularAttrValidator::isValid(const AttributePtr& theAttribute,
262 const std::list<std::string>& theArguments,
263 Events_InfoMessage& theError) const
265 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
266 theError = "The attribute with the %1 type is not processed";
267 theError.arg(theAttribute->attributeType());
271 std::string aParamA = theArguments.front();
273 FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
274 AttributeRefAttrPtr aRefAttr =
275 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
277 bool isObject = aRefAttr->isObject();
278 ObjectPtr anObject = aRefAttr->object();
279 if (isObject && anObject.get()) {
280 FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
282 AttributeRefAttrPtr aOtherAttr = anOwner->refattr(aParamA);
283 ObjectPtr aOtherObject = aOtherAttr->object();
284 FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
286 // at least one feature should be a line
287 if (aRefFea->getKind() != SketchPlugin_Line::ID() &&
288 aOtherFea && aOtherFea->getKind() != SketchPlugin_Line::ID()) {
289 theError = "At least one feature should be a line";
292 else if (isSpline(aRefFea) || isSpline(aOtherFea)) {
293 theError = "B-spline is not supported";
298 theError = "It uses an empty object";
305 bool SketchPlugin_NotFixedValidator::isValid(const AttributePtr& theAttribute,
306 const std::list<std::string>& theArguments,
307 Events_InfoMessage& theError) const
309 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
310 theError = "The attribute with the %1 type is not processed";
311 theError.arg(theAttribute->attributeType());
315 std::shared_ptr<SketchPlugin_Feature> aFeature =
316 std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
320 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
322 SketchPlugin_Sketch* aSketch = aFeature->sketch();
323 int aNbFeatures = aSketch->numberOfSubs();
324 for (int anInd = 0; anInd < aNbFeatures; anInd++) {
325 FeaturePtr aSubFeature = aSketch->subFeature(anInd);
326 if (aSubFeature->getKind() != SketchPlugin_ConstraintRigid::ID() || aSubFeature == aFeature)
328 AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
329 aSubFeature->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
330 if (aRefAttr->isObject()) {
331 if (aRefAttr->object() == aRAttr->object()) {
332 ObjectPtr anObject = aRefAttr->object();
333 std::wstring aName = anObject.get() ? anObject->data()->name() : L"";
334 theError = "The object %1 has been already fixed.";
339 else if (aRefAttr->attr() == aRAttr->attr()) {
340 AttributePtr anAttribute = aRefAttr->attr();
342 anAttribute.get() ? Locale::Convert::toWString(anAttribute->id()) : L"";
343 theError = "The attribute %1 has been already fixed.";
351 bool SketchPlugin_EqualAttrValidator::isValid(const AttributePtr& theAttribute,
352 const std::list<std::string>& theArguments,
353 Events_InfoMessage& theError) const
355 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
356 theError = "The attribute with the %1 type is not processed";
357 theError.arg(theAttribute->attributeType());
361 std::string aParamA = theArguments.front();
362 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
363 AttributeRefAttrPtr aRefAttr[2];
364 aRefAttr[0] = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
365 aRefAttr[1] = aFeature->data()->refattr(aParamA);
367 if (!aRefAttr[0]->isObject() || !aRefAttr[1]->isObject()) {
368 theError = "Attributes can not be used in equal constraint";
372 std::string aType[2];
373 std::list<std::string> anArguments;
374 for (int i = 0; i < 2; i++) {
375 aFeature = ModelAPI_Feature::feature(aRefAttr[i]->object());
379 aType[i] = aFeature->getKind();
380 if (aFeature->getKind() != SketchPlugin_Line::ID() &&
381 aFeature->getKind() != SketchPlugin_Circle::ID() &&
382 aFeature->getKind() != SketchPlugin_Arc::ID() &&
383 aFeature->getKind() != SketchPlugin_Ellipse::ID() &&
384 aFeature->getKind() != SketchPlugin_EllipticArc::ID()) {
385 theError = "The %1 feature is not supported by the Equal constraint.";
386 theError.arg(aFeature->getKind());
387 // wrong type of attribute
392 bool isOk = aType[0] == aType[1];
394 // circle and arc may be equal
395 isOk = (aType[0] == SketchPlugin_Arc::ID() && aType[1] == SketchPlugin_Circle::ID())
396 || (aType[0] == SketchPlugin_Circle::ID() && aType[1] == SketchPlugin_Arc::ID());
399 // ellipse and elliptic arc may be equal
400 isOk = (aType[0] == SketchPlugin_EllipticArc::ID() && aType[1] == SketchPlugin_Ellipse::ID())
401 || (aType[0] == SketchPlugin_Ellipse::ID() && aType[1] == SketchPlugin_EllipticArc::ID());
404 theError = "Features with kinds %1 and %2 can not be equal.";
405 theError.arg(aType[0]).arg(aType[1]);
411 bool SketchPlugin_MirrorAttrValidator::isValid(const AttributePtr& theAttribute,
412 const std::list<std::string>& theArguments,
413 Events_InfoMessage& theError) const
415 if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
416 theError = "The attribute with the %1 type is not processed";
417 theError.arg(theAttribute->attributeType());
421 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
422 AttributeRefListPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
424 AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
425 aFeature->attribute(SketchPlugin_Constraint::ENTITY_C()));
426 std::list<ObjectPtr> aMirroredObjects = aRefListOfMirrored->list();
428 for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
429 ObjectPtr aSelObject = aSelAttr->object(anInd);
431 // B-splines are not supported in Mirror yet
432 FeaturePtr aSelFeature = ModelAPI_Feature::feature(aSelObject);
433 if (aSelFeature && (aSelFeature->getKind() == SketchPlugin_BSpline::ID() ||
434 aSelFeature->getKind() == SketchPlugin_BSplinePeriodic::ID())) {
435 theError = "Not supported";
439 std::wstring aName = aSelObject.get() ? aSelObject->data()->name() : L"";
440 std::list<ObjectPtr>::iterator aMirIter = aMirroredObjects.begin();
441 for (; aMirIter != aMirroredObjects.end(); aMirIter++)
442 if (aSelObject == *aMirIter) {
443 theError = "The object %1 is a result of mirror";
451 bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttribute,
452 const std::list<std::string>& theArguments,
453 Events_InfoMessage& theError) const
455 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
456 theError = "The attribute with the %1 type is not processed";
457 theError.arg(theAttribute->attributeType());
461 // there is a check whether the feature contains a point and a linear edge or two point values
462 std::string aParamA = theArguments.front();
464 FeaturePtr aConstraint = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
465 AttributeRefAttrPtr aRefAttrA = aConstraint->data()->refattr(aParamA);
467 theError = "The %1 attribute should be %2";
468 theError.arg(aParamA).arg(ModelAPI_AttributeRefAttr::typeId());
472 AttributeRefAttrPtr aRefAttrB =
473 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
475 // first attribute is a point, it may coincide with any object
476 if (!aRefAttrA->isObject())
479 ObjectPtr anObject = aRefAttrA->object();
480 if (!anObject.get()) {
481 theError = "%1 attribute has an empty object";
482 theError.arg(aParamA);
485 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrA->object());
486 if (!aFeature.get()) {
487 theError = "%1 attribute has an empty feature";
488 theError.arg(aParamA);
492 if (aFeature->getKind() == SketchPlugin_Point::ID())
496 // second attribute is a point, it may coincide with any object
497 if (!aRefAttrB->isObject())
500 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrB->object());
502 theError = "%1 attribute has an empty object";
503 theError.arg(theAttribute->id());
506 if (aFeature->getKind() == SketchPlugin_Point::ID())
509 theError = "There is no an attribute filled by a point";
514 bool SketchPlugin_CopyValidator::isValid(const AttributePtr& theAttribute,
515 const std::list<std::string>& theArguments,
516 Events_InfoMessage& theError) const
518 if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
519 theError = "The attribute with the %1 type is not processed";
520 theError.arg(theAttribute->attributeType());
524 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
525 AttributeRefListPtr aSelAttr =
526 std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
527 std::set<ObjectPtr> aSelected;
529 AttributeRefListPtr aRefListOfInitial = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
530 aFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
531 AttributeRefListPtr aRefListOfCopied = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
532 aFeature->attribute(SketchPlugin_Constraint::ENTITY_B()));
533 std::list<ObjectPtr> anInitialObjects = aRefListOfInitial->list();
534 std::list<ObjectPtr> aCopiedObjects = aRefListOfCopied->list();
536 std::list<ObjectPtr>::iterator anObjIter;
537 for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
538 ObjectPtr aSelObject = aSelAttr->object(anInd);
539 if (aSelected.find(aSelObject) != aSelected.end()) {
540 theError = "Error: An object selected twice";
543 aSelected.insert(aSelObject);
545 anObjIter = anInitialObjects.begin();
546 for (; anObjIter != anInitialObjects.end(); anObjIter++)
547 if (aSelObject == *anObjIter)
549 if (anObjIter != anInitialObjects.end())
552 // B-splines are not supported in Copying features
553 FeaturePtr aSelFeature = ModelAPI_Feature::feature(aSelObject);
554 if (aFeature->getKind() != SketchPlugin_Offset::ID() &&
555 aSelFeature && (aSelFeature->getKind() == SketchPlugin_BSpline::ID() ||
556 aSelFeature->getKind() == SketchPlugin_BSplinePeriodic::ID())) {
557 theError = "Not supported";
561 anObjIter = aCopiedObjects.begin();
562 for (; anObjIter != aCopiedObjects.end(); anObjIter++) {
563 bool isFound = aSelObject == *anObjIter;
565 // check in the results of the feature
566 FeaturePtr aCurFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anObjIter);
568 const std::list<ResultPtr>& aResults = aCurFeature->results();
569 for (std::list<ResultPtr>::const_iterator aResIt = aResults.begin();
570 aResIt != aResults.end() && !isFound; ++aResIt) {
571 isFound = aSelObject == *aResIt;
577 aSelObject.get() ? Locale::Convert::toString(aSelObject->data()->name()) : "";
578 theError = "The object %1 is a result of copy";
587 bool SketchPlugin_SolverErrorValidator::isValid(
588 const std::shared_ptr<ModelAPI_Feature>& theFeature,
589 const std::list<std::string>& theArguments,
590 Events_InfoMessage& theError) const
592 AttributeStringPtr aAttributeString = theFeature->string(SketchPlugin_Sketch::SOLVER_ERROR());
594 if (!aAttributeString->value().empty()) {
595 theError = aAttributeString->value();
602 bool SketchPlugin_SolverErrorValidator::isNotObligatory(std::string theFeature,
603 std::string theAttribute)
608 static bool hasSameTangentFeature(const std::set<AttributePtr>& theRefsList,
609 const FeaturePtr theFeature)
611 for(std::set<AttributePtr>::const_iterator
612 anIt = theRefsList.cbegin(); anIt != theRefsList.cend(); ++anIt) {
613 std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
614 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
617 if (aFeature->getKind() == SketchPlugin_ConstraintTangent::ID()) {
618 AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
619 aFeature->attribute(SketchPlugin_ConstraintTangent::ENTITY_A()));
620 AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
621 aFeature->attribute(SketchPlugin_ConstraintTangent::ENTITY_B()));
622 if(anAttrRefA.get()) {
623 ResultPtr aResA = std::dynamic_pointer_cast<ModelAPI_Result>(anAttrRefA->object());
625 DocumentPtr aDoc = aResA->document();
627 FeaturePtr aFeatureA = aDoc->feature(aResA);
628 if(aFeatureA.get() && aFeatureA == theFeature) {
634 if(anAttrRefB.get()) {
635 ResultPtr aResB = std::dynamic_pointer_cast<ModelAPI_Result>(anAttrRefB->object());
637 DocumentPtr aDoc = aResB->document();
639 FeaturePtr aFeatureB = aDoc->feature(aResB);
640 if(aFeatureB.get() && aFeatureB == theFeature) {
651 static bool isPointPointCoincidence(const FeaturePtr& theCoincidence)
653 AttributeRefAttrPtr aRefAttr[2] = {
654 theCoincidence->refattr(SketchPlugin_Constraint::ENTITY_A()),
655 theCoincidence->refattr(SketchPlugin_Constraint::ENTITY_B())
658 bool arePoints = true;
659 for (int i = 0; i < 2 && arePoints; ++i) {
660 if (aRefAttr[i]->isObject()) {
661 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr[i]->object());
662 arePoints = aFeature.get() && aFeature->getKind() == SketchPlugin_Point::ID();
664 arePoints = aRefAttr[i]->attr().get() != NULL;
669 bool SketchPlugin_FilletVertexValidator::isValid(const AttributePtr& theAttribute,
670 const std::list<std::string>& theArguments,
671 Events_InfoMessage& theError) const
673 AttributeRefAttrPtr aPointRefAttr =
674 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
675 if(!aPointRefAttr.get()) {
676 theError = "Error: Point not selected.";
680 AttributePtr aPointAttribute = aPointRefAttr->attr();
681 if (!aPointAttribute.get()) {
682 theError = "Error: Bad point selected.";
685 std::shared_ptr<GeomAPI_Pnt2d> aSelectedPnt =
686 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttribute)->pnt();
688 // Obtain constraint coincidence for the fillet point.
689 const std::set<AttributePtr>& aRefsList = aPointAttribute->owner()->data()->refsToMe();
690 FeaturePtr aConstraintCoincidence;
691 for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin();
692 anIt != aRefsList.cend(); ++anIt) {
693 std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
694 FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
695 if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
696 if (!isPointPointCoincidence(aConstrFeature))
699 AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
700 aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
701 AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
702 aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
704 AttributePtr anAttrA = anAttrRefA->attr();
705 if(aPointAttribute == anAttrA) {
706 aConstraintCoincidence = aConstrFeature;
710 AttributePtr anAttrB = anAttrRefB->attr();
711 if(aPointAttribute == anAttrB) {
712 aConstraintCoincidence = aConstrFeature;
718 if(!aConstraintCoincidence.get()) {
719 theError = "Error: one of the selected point does not have coincidence.";
723 // Get coincides from constraint.
724 std::set<FeaturePtr> aCoinsides;
725 SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
726 SketchPlugin_ConstraintCoincidence::ENTITY_A(),
729 SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
730 SketchPlugin_ConstraintCoincidence::ENTITY_B(),
734 // Remove points and external lines from set of coincides.
735 std::set<FeaturePtr> aNewSetOfCoincides;
736 for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
737 anIt != aCoinsides.end(); ++anIt) {
738 std::shared_ptr<SketchPlugin_SketchEntity> aSketchEntity =
739 std::dynamic_pointer_cast<SketchPlugin_SketchEntity>(*anIt);
740 if(aSketchEntity.get() && (aSketchEntity->isCopy() || aSketchEntity->isExternal())) {
743 if((*anIt)->getKind() != SketchPlugin_Line::ID() &&
744 (*anIt)->getKind() != SketchPlugin_Arc::ID()) {
747 if((*anIt)->getKind() == SketchPlugin_Arc::ID()) {
748 AttributePtr anArcCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
749 std::shared_ptr<GeomAPI_Pnt2d> anArcCenterPnt =
750 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anArcCenter)->pnt();
751 double aDistSelectedArcCenter = aSelectedPnt->distance(anArcCenterPnt);
752 if(aDistSelectedArcCenter < tolerance) {
756 aNewSetOfCoincides.insert(*anIt);
758 aCoinsides = aNewSetOfCoincides;
760 // If we still have more than two coincides remove auxilary entities from set of coincides.
761 if(aCoinsides.size() > 2) {
762 aNewSetOfCoincides.clear();
763 for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
764 anIt != aCoinsides.end(); ++anIt) {
765 if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
766 aNewSetOfCoincides.insert(*anIt);
769 aCoinsides = aNewSetOfCoincides;
772 if(aCoinsides.size() != 2) {
773 theError = "Error: One of the selected points does not have two suitable edges for fillet.";
777 // Check that selected edges don't have tangent constraint.
778 std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
779 FeaturePtr aFirstFeature = *anIt++;
780 FeaturePtr aSecondFeature = *anIt;
781 const std::set<AttributePtr>& aFirstFeatureRefsList = aFirstFeature->data()->refsToMe();
782 if(hasSameTangentFeature(aFirstFeatureRefsList, aSecondFeature)) {
783 theError = "Error: Edges in selected point has tangent constraint.";
787 std::list<ResultPtr> aFirstResults = aFirstFeature->results();
788 for(std::list<ResultPtr>::iterator aResIt = aFirstResults.begin();
789 aResIt != aFirstResults.end(); ++aResIt) {
790 ResultPtr aRes = *aResIt;
791 const std::set<AttributePtr>& aResRefsList = aRes->data()->refsToMe();
792 if(hasSameTangentFeature(aResRefsList, aSecondFeature)) {
793 theError = "Error: Edges in selected point has tangent constraint.";
798 // Check the features are not tangent
799 std::shared_ptr<GeomAPI_Shape> aFirstShape = aFirstFeature->lastResult()->shape();
800 std::shared_ptr<GeomAPI_Shape> aSecondShape = aSecondFeature->lastResult()->shape();
801 if (!aFirstShape || !aFirstShape->isEdge() ||
802 !aSecondShape || !aSecondShape->isEdge()) {
803 theError = "Error: At least on of the features is not an edge";
807 std::shared_ptr<GeomAPI_Edge> anEdge1 = std::dynamic_pointer_cast<GeomAPI_Edge>(aFirstShape);
808 std::shared_ptr<GeomAPI_Edge> anEdge2 = std::dynamic_pointer_cast<GeomAPI_Edge>(aSecondShape);
810 static const double TOL = 1.e-7;
811 if (anEdge1->isLine() && anEdge2->isLine()) {
812 // Check that lines not collinear
813 std::shared_ptr<GeomAPI_Dir> aDir1 = anEdge1->line()->direction();
814 std::shared_ptr<GeomAPI_Dir> aDir2 = anEdge2->line()->direction();
815 double aCross = aDir1->cross(aDir2)->squareModulus();
816 if (aCross < TOL * TOL)
818 } else if (anEdge1->isArc() && anEdge2->isArc()) {
819 // check the circles are not tangent
820 std::shared_ptr<GeomAPI_Circ> aCirc1 = anEdge1->circle();
821 std::shared_ptr<GeomAPI_Circ> aCirc2 = anEdge2->circle();
822 double aDistCC = aCirc1->center()->distance(aCirc2->center());
823 double aRadSum = aCirc1->radius() + aCirc2->radius();
824 double aRadDiff = fabs(aCirc1->radius() - aCirc2->radius());
825 if (fabs(aDistCC - aRadSum) < TOL || fabs(aDistCC - aRadDiff) < TOL)
828 // check whether line and arc are tangent
829 std::shared_ptr<GeomAPI_Circ> aCirc;
830 std::shared_ptr<GeomAPI_Lin> aLine;
831 if (anEdge1->isLine()) {
832 aLine = anEdge1->line();
833 aCirc = anEdge2->circle();
835 aCirc = anEdge1->circle();
836 aLine = anEdge2->line();
839 double aDistCL = aLine->distance(aCirc->center());
840 if (fabs(aDistCL - aCirc->radius()) < TOL)
847 bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttribute,
848 const std::list<std::string>& theArguments,
849 Events_InfoMessage& theError) const
851 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
852 theError = "The attribute with the %1 type is not processed";
853 theError.arg(theAttribute->attributeType());
857 // there is a check whether the feature contains a point and a linear edge or two point values
858 std::string aParamA = theArguments.front();
860 FeaturePtr anAttributeFeature =
861 std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
862 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
863 AttributeRefAttrPtr anOtherAttr = anAttributeFeature->data()->refattr(aParamA);
865 AttributeRefAttrPtr aRefAttrs[2] = {aRefAttr, anOtherAttr};
868 for (int i = 0; i < 2; ++i) {
869 if (!aRefAttrs[i]->isObject())
872 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrs[i]->object());
874 if (aNbPoints + aNbLines != 0)
879 if (aFeature->getKind() == SketchPlugin_Point::ID())
881 else if (aFeature->getKind() == SketchPlugin_Line::ID() ||
882 aFeature->getKind() == SketchPlugin_Arc::ID() ||
883 aFeature->getKind() == SketchPlugin_EllipticArc::ID())
888 if (aNbPoints != 1 || aNbLines != 1) {
889 theError = "Middle point constraint allows points and lines only";
895 bool SketchPlugin_ArcTangentPointValidator::isValid(const AttributePtr& theAttribute,
896 const std::list<std::string>& /*theArguments*/,
897 Events_InfoMessage& theError) const
899 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
900 theError = "The attribute with the %1 type is not processed";
901 theError.arg(theAttribute->attributeType());
904 FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
905 AttributeStringPtr anArcTypeAttr = anOwner->string(SketchPlugin_MacroArc::ARC_TYPE());
906 if (anArcTypeAttr && anArcTypeAttr->value() != SketchPlugin_MacroArc::ARC_TYPE_BY_TANGENT_EDGE())
907 return true; // not applicable for non-tangent arcs
909 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
910 AttributePtr anAttr = aRefAttr->attr();
912 theError = "The attribute %1 should be a point";
913 theError.arg(theAttribute->id());
917 FeaturePtr anAttrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
918 const std::string& aFeatureType = anAttrFeature->getKind();
919 if (aFeatureType == SketchPlugin_Arc::ID()) {
920 // selected point should not be a center of arc
921 const std::string& aPntId = anAttr->id();
922 if (aPntId != SketchPlugin_Arc::START_ID() && aPntId != SketchPlugin_Arc::END_ID()) {
923 theError = "The attribute %1 is not supported";
924 theError.arg(aPntId);
928 else if (aFeatureType == SketchPlugin_Line::ID()) {
929 // selected point should be bound point of line
930 const std::string& aPntId = anAttr->id();
931 if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) {
932 theError = "The attribute %1 is not supported";
933 theError.arg(aPntId);
938 theError = "Unable to build tangent arc on %1";
939 theError.arg(anAttrFeature->getKind());
946 bool SketchPlugin_ArcTransversalPointValidator::isValid(
947 const AttributePtr& theAttribute,
948 const std::list<std::string>& /*theArguments*/,
949 Events_InfoMessage& theError) const
951 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
952 theError = "The attribute with the %1 type is not processed";
953 theError.arg(theAttribute->attributeType());
956 FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
957 AttributeStringPtr anArcTypeAttr = anOwner->string(SketchPlugin_MacroArc::ARC_TYPE());
959 anArcTypeAttr->value() != SketchPlugin_MacroArc::ARC_TYPE_BY_TRANSVERSAL_LINE())
960 return true; // not applicable for non-transversal arcs
962 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
963 AttributePtr anAttr = aRefAttr->attr();
965 theError = "The attribute %1 should be a point";
966 theError.arg(theAttribute->id());
970 FeaturePtr anAttrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
971 const std::string& aFeatureType = anAttrFeature->getKind();
972 if (aFeatureType == SketchPlugin_Line::ID()) {
973 // selected point should be bound point of line
974 const std::string& aPntId = anAttr->id();
975 if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) {
976 theError = "The attribute %1 is not supported";
977 theError.arg(aPntId);
982 theError = "Unable to build perpendicular arc on %1";
983 theError.arg(anAttrFeature->getKind());
990 bool SketchPlugin_IntersectionValidator::isValid(const AttributePtr& theAttribute,
991 const std::list<std::string>& theArguments,
992 Events_InfoMessage& theError) const
994 if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
995 theError = "The attribute with the %1 type is not processed";
996 theError.arg(theAttribute->attributeType());
999 AttributeSelectionPtr anExternalAttr =
1000 std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
1001 std::shared_ptr<GeomAPI_Edge> anEdge;
1002 if (anExternalAttr && anExternalAttr->value() && anExternalAttr->value()->isEdge()) {
1003 anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(anExternalAttr->value()));
1004 } else if(anExternalAttr->context() && anExternalAttr->context()->shape() &&
1005 anExternalAttr->context()->shape()->isEdge()) {
1006 anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(anExternalAttr->context()->shape()));
1010 theError = "The attribute %1 should be an edge";
1011 theError.arg(theAttribute->id());
1016 std::shared_ptr<SketchPlugin_Sketch> aSketch;
1017 std::set<AttributePtr> aRefs = anExternalAttr->owner()->data()->refsToMe();
1018 std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
1019 for (; anIt != aRefs.end(); ++anIt) {
1020 CompositeFeaturePtr aComp =
1021 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
1022 if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
1023 aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
1028 theError = "There is no sketch referring to the current feature";
1032 // check the edge is intersected with sketch plane
1033 std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
1035 std::list<GeomPointPtr> anIntersectionsPoints;
1036 anEdge->intersectWithPlane(aPlane, anIntersectionsPoints);
1037 if (anIntersectionsPoints.empty()) {
1038 theError = "The edge is not intersected with sketch plane";
1044 bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute,
1045 const std::list<std::string>& theArguments,
1046 Events_InfoMessage& theError) const
1048 bool aValid = false;
1050 if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
1051 theError = "The attribute with the %1 type is not processed";
1052 theError.arg(theAttribute->attributeType());
1055 AttributeReferencePtr aFeatureAttr =
1056 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
1057 std::shared_ptr<SketchPlugin_Feature> aSplitFeature =
1058 std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
1060 ObjectPtr anAttrObject = aFeatureAttr->value();
1061 if (!anAttrObject) {
1062 AttributePtr aPreviewAttr = aSplitFeature->attribute(SketchPlugin_Trim::PREVIEW_OBJECT());
1063 aFeatureAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(aPreviewAttr);
1064 anAttrObject = aFeatureAttr->value();
1067 FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttrObject);
1071 // B-splines are not supported by the Split yet
1072 if (anAttrFeature->getKind() == SketchPlugin_BSpline::ID() ||
1073 anAttrFeature->getKind() == SketchPlugin_BSplinePeriodic::ID()) {
1074 theError = "Not supported";
1078 std::set<ResultPtr> anEdgeShapes;
1079 ModelGeomAlgo_Shape::shapesOfType(anAttrFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
1080 if (anEdgeShapes.empty() || anEdgeShapes.size() > 1 /*there case has not existed yet*/)
1083 // coincidences to the feature
1084 std::set<std::shared_ptr<GeomDataAPI_Point2D> > aRefAttributes;
1085 ModelGeomAlgo_Point2D::getPointsOfReference(anAttrFeature,
1086 SketchPlugin_ConstraintCoincidence::ID(),
1087 aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
1089 GeomShapePtr anAttrShape = (*anEdgeShapes.begin())->shape();
1090 std::shared_ptr<SketchPlugin_Feature> aSFeature =
1091 std::dynamic_pointer_cast<SketchPlugin_Feature>(anAttrFeature);
1092 if (!aSFeature || aSFeature->isCopy())
1094 SketchPlugin_Sketch* aSketch = aSFeature->sketch();
1096 std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
1097 std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
1098 aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
1099 std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
1100 aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
1101 std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
1102 aData->attribute(SketchPlugin_Sketch::NORM_ID()));
1103 std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
1105 typedef std::map<std::shared_ptr<GeomAPI_Pnt>,
1106 std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
1107 std::list<std::shared_ptr<ModelAPI_Object> > > > PointToRefsMap;
1108 PointToRefsMap aPointsInfo;
1110 ModelGeomAlgo_Point2D::getPointsInsideShape(anAttrShape, aRefAttributes, aC->pnt(),
1111 aX->dir(), aDirY, aPointsInfo);
1112 int aCoincidentToFeature = (int)aPointsInfo.size();
1113 if (anAttrFeature->getKind() == SketchPlugin_Circle::ID() ||
1114 anAttrFeature->getKind() == SketchPlugin_Ellipse::ID())
1115 aValid = aCoincidentToFeature >= 2;
1117 aValid = aCoincidentToFeature >= 1;
1122 bool SketchPlugin_TrimValidator::isValid(const AttributePtr& theAttribute,
1123 const std::list<std::string>& theArguments,
1124 Events_InfoMessage& theError) const
1126 bool aValid = false;
1128 if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
1129 theError = "The attribute with the %1 type is not processed";
1130 theError.arg(theAttribute->attributeType());
1133 AttributeReferencePtr aBaseObjectAttr =
1134 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
1136 std::shared_ptr<SketchPlugin_Feature> aTrimFeature =
1137 std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
1139 ObjectPtr aBaseObject = aBaseObjectAttr->value();
1141 AttributePtr aPreviewAttr = aTrimFeature->attribute(SketchPlugin_Trim::PREVIEW_OBJECT());
1142 aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(aPreviewAttr);
1143 aBaseObject = aBaseObjectAttr->value();
1146 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject);
1150 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1151 std::dynamic_pointer_cast<SketchPlugin_Feature>(aBaseFeature);
1152 if (!aSketchFeature.get() || aSketchFeature->isCopy())
1155 // B-splines are not supported by the Trim yet
1156 if (aBaseFeature->getKind() == SketchPlugin_BSpline::ID() ||
1157 aBaseFeature->getKind() == SketchPlugin_BSplinePeriodic::ID()) {
1158 theError = "Not supported";
1163 AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1164 aTrimFeature->data()->attribute(SketchPlugin_Trim::PREVIEW_POINT()));
1166 SketchPlugin_Sketch* aSketch = aTrimFeature->sketch();
1168 std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPoint->pnt();
1169 std::shared_ptr<GeomAPI_Pnt> anAttributePnt = aSketch->to3D(anAttributePnt2d->x(),
1170 anAttributePnt2d->y());
1172 std::map<ObjectPtr, std::set<GeomShapePtr> > aCashedShapes;
1173 std::map<ObjectPtr, std::map<std::shared_ptr<GeomAPI_Pnt>,
1174 std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
1175 std::list<std::shared_ptr<ModelAPI_Object> > > > > anObjectToPoints;
1176 SketchPlugin_SegmentationTools::fillObjectShapes(
1177 aTrimFeature.get(), aBaseObject, aCashedShapes, anObjectToPoints);
1178 const std::set<GeomShapePtr>& aShapes = aCashedShapes[aBaseObject];
1180 return aShapes.size() > 1;
1183 bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
1184 const std::list<std::string>& theArguments,
1185 Events_InfoMessage& theError) const
1187 if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
1188 theError = "The attribute with the %1 type is not processed";
1189 theError.arg(theAttribute->attributeType());
1193 AttributeSelectionPtr aFeatureAttr =
1194 std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
1195 std::shared_ptr<GeomAPI_Vertex> aVertex;
1196 std::shared_ptr<GeomAPI_Edge> anEdge;
1197 std::shared_ptr<SketchPlugin_Feature> aSketchFeature;
1198 if (aFeatureAttr.get()) {
1199 GeomShapePtr aVal = aFeatureAttr->value();
1200 ResultPtr aRes = aFeatureAttr->context();
1201 if (aVal && aVal->isVertex())
1202 aVertex = std::shared_ptr<GeomAPI_Vertex>(new GeomAPI_Vertex(aVal));
1203 else if (aVal && aVal->isEdge()) {
1204 anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aVal));
1205 } else if(aRes && aRes->shape()) {
1206 if (aRes->shape()->isVertex())
1207 aVertex = std::shared_ptr<GeomAPI_Vertex>(new GeomAPI_Vertex(aRes->shape()));
1208 else if (aRes->shape()->isEdge())
1209 anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aRes->shape()));
1212 // try to convert result to sketch feature
1215 std::dynamic_pointer_cast<SketchPlugin_Feature>(ModelAPI_Feature::feature(aRes));
1218 if (!aVertex && !anEdge) {
1219 theError = "The attribute %1 should be an edge or vertex";
1220 theError.arg(theAttribute->id());
1225 std::shared_ptr<SketchPlugin_Sketch> aSketch;
1226 std::set<AttributePtr> aRefs = theAttribute->owner()->data()->refsToMe();
1227 std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
1228 for (; anIt != aRefs.end(); ++anIt) {
1229 CompositeFeaturePtr aComp =
1230 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
1231 if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
1232 aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
1237 theError = "There is no sketch referring to the current feature";
1240 if (aSketchFeature && aSketch.get() == aSketchFeature->sketch()) {
1241 theError = "Unable to project feature from the same sketch";
1245 std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
1246 std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
1247 std::shared_ptr<GeomAPI_Pnt> anOrigin = aPlane->location();
1251 aValid = true; // vertex is always could be projected
1252 else if (anEdge->isLine()) {
1253 std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
1254 std::shared_ptr<GeomAPI_Dir> aLineDir = aLine->direction();
1255 double aDot = fabs(aNormal->dot(aLineDir));
1256 aValid = fabs(aDot - 1.0) >= tolerance * tolerance;
1258 theError = "Error: Line is orthogonal to the sketch plane.";
1260 else if (anEdge->isCircle() || anEdge->isArc()) {
1261 std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
1262 std::shared_ptr<GeomAPI_Dir> aCircNormal = aCircle->normal();
1263 double aDot = fabs(aNormal->dot(aCircNormal));
1264 aValid = aDot >= tolerance * tolerance;
1266 theError.arg(anEdge->isCircle() ? "Error: Circle is orthogonal to the sketch plane."
1267 : "Error: Arc is orthogonal to the sketch plane.");
1269 else if (anEdge->isEllipse()) {
1270 std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
1271 std::shared_ptr<GeomAPI_Dir> anEllipseNormal = anEllipse->normal();
1272 double aDot = fabs(aNormal->dot(anEllipseNormal));
1273 aValid = aDot >= tolerance * tolerance;
1275 theError.arg(anEdge->isClosed() ? "Error: Ellipse is orthogonal to the sketch plane."
1276 : "Error: Elliptic Arc is orthogonal to the sketch plane.");
1278 else if (anEdge->isBSpline()) {
1279 // check B-spline is periodic and planar
1280 std::shared_ptr<GeomAPI_Curve> aCurve(new GeomAPI_Curve(anEdge));
1281 std::shared_ptr<GeomAPI_BSpline> aBSpline(new GeomAPI_BSpline(aCurve));
1282 if (aBSpline->isPeriodic()) {
1283 GeomPlanePtr aBSplinePlane = GeomAlgoAPI_ShapeTools::findPlane(ListOfShape(1, anEdge));
1284 if (aBSplinePlane) {
1285 std::shared_ptr<GeomAPI_Dir> aBSplineNormal = aBSplinePlane->direction();
1286 double aDot = fabs(aNormal->dot(aBSplineNormal));
1287 aValid = aDot > tolerance * tolerance;
1289 // B-spline's plane is orthogonal to the sketch plane,
1290 // thus, need to check whether B-spline is planar.
1291 std::list<GeomPointPtr> aPoles = aBSpline->poles();
1292 for (std::list<GeomPointPtr>::iterator it = aPoles.begin();
1293 it != aPoles.end() && !aValid; ++it) {
1294 if (aBSplinePlane->distance(*it) > tolerance)
1295 aValid = true; // non-planar B-spline curve
1298 theError = "Error: Periodic B-spline is orthogonal to the sketch plane.";
1308 static std::set<FeaturePtr> common(const std::set<FeaturePtr>& theSet1,
1309 const std::set<FeaturePtr>& theSet2)
1311 std::set<FeaturePtr> aCommon;
1312 if (theSet1.empty() || theSet2.empty())
1315 std::set<FeaturePtr>::const_iterator anIt2 = theSet2.begin();
1316 for (; anIt2 != theSet2.end(); ++anIt2)
1317 if (theSet1.find(*anIt2) != theSet1.end())
1318 aCommon.insert(*anIt2);
1322 bool SketchPlugin_DifferentReferenceValidator::isValid(
1323 const AttributePtr& theAttribute,
1324 const std::list<std::string>& theArguments,
1325 Events_InfoMessage& theError) const
1327 FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1329 int aNbFeaturesReferred = 0;
1330 int aNbAttributesReferred = 0;
1331 std::set<FeaturePtr> aCommonReferredFeatures;
1333 // find all features referred by attributes listed in theArguments
1334 std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1335 for (; anArgIt != theArguments.end(); ++anArgIt) {
1336 AttributeRefAttrPtr aRefAttr = anOwner->refattr(*anArgIt);
1340 std::set<FeaturePtr> aCoincidentFeatures;
1341 if (aRefAttr->isObject()) {
1342 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1344 aCoincidentFeatures.insert(aFeature);
1345 aNbFeaturesReferred += 1;
1348 AttributePoint2DPtr aPoint =
1349 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1351 aCoincidentFeatures = SketchPlugin_Tools::findFeaturesCoincidentToPoint(aPoint);
1352 aNbAttributesReferred += 1;
1356 if (aCommonReferredFeatures.empty())
1357 aCommonReferredFeatures = aCoincidentFeatures;
1359 aCommonReferredFeatures = common(aCommonReferredFeatures, aCoincidentFeatures);
1361 if (aCommonReferredFeatures.empty())
1365 bool isOk = aNbFeaturesReferred < 1;
1366 if (aNbFeaturesReferred == 1) {
1367 if (aCommonReferredFeatures.size() == 1) {
1368 FeaturePtr aFeature = *aCommonReferredFeatures.begin();
1369 isOk = aNbAttributesReferred <= 1 ||
1370 aFeature->getKind() == SketchPlugin_Circle::ID() ||
1371 aFeature->getKind() == SketchPlugin_Arc::ID();
1377 theError = "Attributes are referred to the same feature";
1381 bool SketchPlugin_DifferentPointReferenceValidator::isValid(
1382 const AttributePtr& theAttribute,
1383 const std::list<std::string>& theArguments,
1384 Events_InfoMessage& theError) const
1386 FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1387 std::set<AttributePoint2DPtr> aReferredCoincidentPoints;
1389 // find all points referred by attributes listed in theArguments
1390 bool hasRefsToPoints = false;
1391 std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1392 for (; anArgIt != theArguments.end(); ++anArgIt) {
1393 AttributeRefAttrPtr aRefAttr = anOwner->refattr(*anArgIt);
1397 if (!aRefAttr->isObject()) {
1398 AttributePoint2DPtr aPoint =
1399 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1400 if (aReferredCoincidentPoints.empty())
1401 aReferredCoincidentPoints = SketchPlugin_Tools::findPointsCoincidentToPoint(aPoint);
1402 else if (aReferredCoincidentPoints.find(aPoint) == aReferredCoincidentPoints.end())
1403 return true; // non-coincident point has been found
1405 hasRefsToPoints = true;
1409 if (hasRefsToPoints)
1410 theError = "Attributes are referred to the same point";
1411 return !hasRefsToPoints;
1414 bool SketchPlugin_CirclePassedPointValidator::isValid(
1415 const AttributePtr& theAttribute,
1416 const std::list<std::string>&,
1417 Events_InfoMessage& theError) const
1419 static const std::string aErrorMessage(
1420 "Passed point refers to the same feature as a center point");
1422 FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1424 AttributeRefAttrPtr aCenterRef =
1425 anOwner->refattr(SketchPlugin_MacroCircle::CENTER_POINT_REF_ID());
1426 AttributeRefAttrPtr aPassedRef =
1427 anOwner->refattr(SketchPlugin_MacroCircle::PASSED_POINT_REF_ID());
1429 if (!aPassedRef->isObject())
1432 FeaturePtr aPassedFeature = ModelAPI_Feature::feature(aPassedRef->object());
1433 if (!aPassedFeature)
1436 if (aCenterRef->isObject()) {
1437 if (aCenterRef->object() == aPassedRef->object()) {
1438 theError = aErrorMessage;
1442 AttributePoint2DPtr aCenterPoint =
1443 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCenterRef->attr());
1445 std::set<FeaturePtr> aCoincidentFeatures =
1446 SketchPlugin_Tools::findFeaturesCoincidentToPoint(aCenterPoint);
1447 // check one of coincident features is a feature referred by passed point
1448 std::set<FeaturePtr>::const_iterator anIt = aCoincidentFeatures.begin();
1449 for(; anIt != aCoincidentFeatures.end(); ++anIt)
1450 if (*anIt == aPassedFeature) {
1451 theError = aErrorMessage;
1459 bool SketchPlugin_ThirdPointValidator::isValid(
1460 const AttributePtr& theAttribute,
1461 const std::list<std::string>& theArguments,
1462 Events_InfoMessage& theError) const
1464 FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1465 return arePointsNotOnLine(anOwner, theError) &&
1466 arePointsNotSeparated(anOwner, theArguments, theError);
1469 static std::shared_ptr<GeomAPI_Pnt2d> toPoint(const FeaturePtr& theMacroCircle,
1470 const std::string& thePointAttrName,
1471 const std::string& theRefPointAttrName)
1473 AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1474 theMacroCircle->attribute(thePointAttrName));
1475 AttributeRefAttrPtr aRefAttr = theMacroCircle->refattr(theRefPointAttrName);
1477 std::shared_ptr<GeomAPI_Pnt2d> aPoint = aPointAttr->pnt();
1479 if (aRefAttr->isObject()) {
1480 // project a point onto selected feature
1481 std::shared_ptr<SketchPlugin_Feature> aFeature =
1482 std::dynamic_pointer_cast<SketchPlugin_Feature>(
1483 ModelAPI_Feature::feature(aRefAttr->object()));
1485 SketchPlugin_Sketch* aSketch = aFeature->sketch();
1486 std::shared_ptr<GeomAPI_Edge> anEdge =
1487 std::dynamic_pointer_cast<GeomAPI_Edge>(aFeature->lastResult()->shape());
1489 std::shared_ptr<GeomAPI_Pnt> aPoint3D = aSketch->to3D(aPoint->x(), aPoint->y());
1490 if (anEdge->isLine())
1491 aPoint3D = anEdge->line()->project(aPoint3D);
1492 else if (anEdge->isCircle())
1493 aPoint3D = anEdge->circle()->project(aPoint3D);
1495 aPoint = aSketch->to2D(aPoint3D);
1499 AttributePoint2DPtr anOtherPoint =
1500 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1502 aPoint = anOtherPoint->pnt(); // the reference point is much more precise, use it
1509 static void threePointsOfFeature(const FeaturePtr& theMacroFeature,
1510 std::shared_ptr<GeomAPI_Pnt2d> thePoints[3])
1512 if (theMacroFeature->getKind() == SketchPlugin_MacroCircle::ID()) {
1513 thePoints[0] = toPoint(theMacroFeature,
1514 SketchPlugin_MacroCircle::FIRST_POINT_ID(),
1515 SketchPlugin_MacroCircle::FIRST_POINT_REF_ID());
1516 thePoints[1] = toPoint(theMacroFeature,
1517 SketchPlugin_MacroCircle::SECOND_POINT_ID(),
1518 SketchPlugin_MacroCircle::SECOND_POINT_REF_ID());
1519 thePoints[2] = toPoint(theMacroFeature,
1520 SketchPlugin_MacroCircle::THIRD_POINT_ID(),
1521 SketchPlugin_MacroCircle::THIRD_POINT_REF_ID());
1522 } else if (theMacroFeature->getKind() == SketchPlugin_MacroArc::ID()) {
1523 thePoints[0] = toPoint(theMacroFeature,
1524 SketchPlugin_MacroArc::START_POINT_2_ID(),
1525 SketchPlugin_MacroArc::START_POINT_REF_ID());
1526 thePoints[1] = toPoint(theMacroFeature,
1527 SketchPlugin_MacroArc::END_POINT_2_ID(),
1528 SketchPlugin_MacroArc::END_POINT_REF_ID());
1529 thePoints[2] = toPoint(theMacroFeature,
1530 SketchPlugin_MacroArc::PASSED_POINT_ID(),
1531 SketchPlugin_MacroArc::PASSED_POINT_REF_ID());
1535 static bool isPointsOnLine(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint1,
1536 const std::shared_ptr<GeomAPI_Pnt2d>& thePoint2,
1537 const std::shared_ptr<GeomAPI_Pnt2d>& thePoint3)
1539 static const double aTolerance = 1.e-7;
1540 if (thePoint1->distance(thePoint2) < aTolerance ||
1541 thePoint1->distance(thePoint3) < aTolerance)
1544 std::shared_ptr<GeomAPI_Dir2d> aDirP1P2(new GeomAPI_Dir2d(thePoint2->x() - thePoint1->x(),
1545 thePoint2->y() - thePoint1->y()));
1546 std::shared_ptr<GeomAPI_Dir2d> aDirP1P3(new GeomAPI_Dir2d(thePoint3->x() - thePoint1->x(),
1547 thePoint3->y() - thePoint1->y()));
1548 return fabs(aDirP1P2->cross(aDirP1P3)) < aTolerance;
1551 static bool isOnSameSide(const std::shared_ptr<GeomAPI_Lin>& theLine,
1552 const std::shared_ptr<GeomAPI_Pnt>& thePoint1,
1553 const std::shared_ptr<GeomAPI_Pnt>& thePoint2)
1555 static const double aTolerance = 1.e-7;
1556 std::shared_ptr<GeomAPI_Dir> aLineDir = theLine->direction();
1557 std::shared_ptr<GeomAPI_XYZ> aLineLoc = theLine->location()->xyz();
1559 std::shared_ptr<GeomAPI_XYZ> aVec1 = thePoint1->xyz()->decreased(aLineLoc);
1560 // the first point is on the line
1561 if (aVec1->squareModulus() < aTolerance * aTolerance)
1563 std::shared_ptr<GeomAPI_Dir> aDirP1L(new GeomAPI_Dir(aVec1));
1564 std::shared_ptr<GeomAPI_XYZ> aVec2 = thePoint2->xyz()->decreased(aLineLoc);
1565 // the second point is on the line
1566 if (aVec2->squareModulus() < aTolerance * aTolerance)
1568 std::shared_ptr<GeomAPI_Dir> aDirP2L(new GeomAPI_Dir(aVec2));
1570 return aLineDir->cross(aDirP1L)->dot(aLineDir->cross(aDirP2L)) > -aTolerance;
1573 static bool isOnSameSide(const std::shared_ptr<GeomAPI_Circ>& theCircle,
1574 const std::shared_ptr<GeomAPI_Pnt>& thePoint1,
1575 const std::shared_ptr<GeomAPI_Pnt>& thePoint2)
1577 static const double aTolerance = 1.e-7;
1578 std::shared_ptr<GeomAPI_Pnt> aCenter = theCircle->center();
1579 double aDistP1C = thePoint1->distance(aCenter);
1580 double aDistP2C = thePoint2->distance(aCenter);
1581 return (aDistP1C - theCircle->radius()) * (aDistP2C - theCircle->radius()) > -aTolerance;
1584 bool SketchPlugin_ThirdPointValidator::arePointsNotOnLine(
1585 const FeaturePtr& theMacroFeature,
1586 Events_InfoMessage& theError) const
1588 static const std::string aErrorPointsOnLine(
1589 "Selected points are on the same line");
1591 std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
1592 threePointsOfFeature(theMacroFeature, aPoints);
1594 if (isPointsOnLine(aPoints[0], aPoints[1], aPoints[2])) {
1595 theError = aErrorPointsOnLine;
1601 bool SketchPlugin_ThirdPointValidator::arePointsNotSeparated(
1602 const FeaturePtr& theMacroFeature,
1603 const std::list<std::string>& theArguments,
1604 Events_InfoMessage& theError) const
1606 static const std::string aErrorPointsApart(
1607 "Selected entity is lying between first two points");
1609 AttributeRefAttrPtr aThirdPointRef = theMacroFeature->refattr(theArguments.front());
1610 FeaturePtr aRefByThird;
1611 if (aThirdPointRef->isObject())
1612 aRefByThird = ModelAPI_Feature::feature(aThirdPointRef->object());
1616 std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
1617 threePointsOfFeature(theMacroFeature, aPoints);
1619 std::shared_ptr<GeomAPI_Edge> aThirdShape =
1620 std::dynamic_pointer_cast<GeomAPI_Edge>(aRefByThird->lastResult()->shape());
1624 SketchPlugin_Sketch* aSketch =
1625 std::dynamic_pointer_cast<SketchPlugin_Feature>(theMacroFeature)->sketch();
1626 std::shared_ptr<GeomAPI_Pnt> aFirstPnt3D = aSketch->to3D(aPoints[0]->x(), aPoints[0]->y());
1627 std::shared_ptr<GeomAPI_Pnt> aSecondPnt3D = aSketch->to3D(aPoints[1]->x(), aPoints[1]->y());
1630 if (aThirdShape->isLine())
1631 isOk = isOnSameSide(aThirdShape->line(), aFirstPnt3D, aSecondPnt3D);
1632 else if (aThirdShape->isCircle() || aThirdShape->isArc())
1633 isOk = isOnSameSide(aThirdShape->circle(), aFirstPnt3D, aSecondPnt3D);
1636 theError = aErrorPointsApart;
1640 bool SketchPlugin_ArcEndPointValidator::isValid(
1641 const AttributePtr& theAttribute,
1642 const std::list<std::string>& theArguments,
1643 Events_InfoMessage& theError) const
1645 FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
1646 AttributeRefAttrPtr anEndPointRef = aFeature->refattr(theArguments.front());
1648 if(!anEndPointRef.get()) {
1652 ObjectPtr anObject = anEndPointRef->object();
1653 AttributePtr anAttr = anEndPointRef->attr();
1654 if(!anObject.get() && !anAttr.get()) {
1658 if(anEndPointRef->attr().get()) {
1662 ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1664 GeomShapePtr aShape = aResult->shape();
1665 if(aShape.get() && aShape->isVertex()) {
1670 aFeature = ModelAPI_Feature::feature(anObject);
1671 if(aFeature.get()) {
1672 if(aFeature->getKind() == SketchPlugin_Point::ID()) {
1680 static GeomShapePtr toInfiniteEdge(const GeomShapePtr theShape)
1682 if(!theShape.get()) {
1686 if(!theShape->isEdge()) {
1690 std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(theShape));
1696 if(anEdge->isLine()) {
1697 std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
1698 GeomShapePtr aShape = GeomAlgoAPI_EdgeBuilder::line(aLine);
1702 if(anEdge->isCircle() || anEdge->isArc()) {
1703 std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
1704 GeomShapePtr aShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCircle);
1711 bool SketchPlugin_ArcEndPointIntersectionValidator::isValid(
1712 const AttributePtr& theAttribute,
1713 const std::list<std::string>& theArguments,
1714 Events_InfoMessage& theError) const
1716 std::shared_ptr<SketchPlugin_MacroArc> anArcFeature =
1717 std::dynamic_pointer_cast<SketchPlugin_MacroArc>(theAttribute->owner());
1718 AttributeRefAttrPtr anEndPointRef = anArcFeature->refattr(theArguments.front());
1720 if(!anEndPointRef.get()) {
1724 GeomShapePtr anArcShape = toInfiniteEdge(anArcFeature->getArcShape(false));
1726 if(!anArcShape.get() || anArcShape->isNull()) {
1730 ObjectPtr anObject = anEndPointRef->object();
1731 AttributePtr anAttr = anEndPointRef->attr();
1732 if(!anObject.get() && !anAttr.get()) {
1736 ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1738 GeomShapePtr aShape = aResult->shape();
1739 if (!aShape->isEdge())
1741 aShape = toInfiniteEdge(aShape);
1742 if(aShape.get() && !aShape->isNull()) {
1743 if(anArcShape->isIntersect(aShape)) {
1749 FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(anObject);
1750 if(aSelectedFeature.get()) {
1751 std::list<ResultPtr> aResults = aSelectedFeature->results();
1752 for(std::list<ResultPtr>::const_iterator anIt = aResults.cbegin();
1753 anIt != aResults.cend();
1756 GeomShapePtr aShape = (*anIt)->shape();
1757 if (!aShape->isEdge())
1759 aShape = toInfiniteEdge(aShape);
1760 if(aShape.get() && !aShape->isNull()) {
1761 if(anArcShape->isIntersect(aShape)) {
1771 bool SketchPlugin_HasNoConstraint::isValid(const AttributePtr& theAttribute,
1772 const std::list<std::string>& theArguments,
1773 Events_InfoMessage& theError) const
1775 std::set<std::string> aFeatureKinds;
1776 for (std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1777 anArgIt != theArguments.end(); anArgIt++) {
1778 aFeatureKinds.insert(*anArgIt);
1781 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
1782 theError = "The attribute with the %1 type is not processed";
1783 theError.arg(theAttribute->attributeType());
1787 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
1789 bool isObject = aRefAttr->isObject();
1791 theError = "It uses an empty object";
1794 ObjectPtr anObject = aRefAttr->object();
1795 FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
1796 if (!aFeature.get()) {
1797 theError = "The feature of the checked attribute is empty";
1801 FeaturePtr aCurrentFeature = ModelAPI_Feature::feature(aRefAttr->owner());
1803 std::set<AttributePtr> aRefsList = anObject->data()->refsToMe();
1804 std::set<AttributePtr>::const_iterator anIt = aRefsList.begin();
1805 for (; anIt != aRefsList.end(); anIt++) {
1806 FeaturePtr aRefFeature = ModelAPI_Feature::feature((*anIt)->owner());
1807 if (aRefFeature.get() && aCurrentFeature != aRefFeature &&
1808 aFeatureKinds.find(aRefFeature->getKind()) != aFeatureKinds.end())
1809 return false; // constraint is found, that means that the check is not valid
1814 bool SketchPlugin_ReplicationReferenceValidator::isValid(
1815 const AttributePtr& theAttribute,
1816 const std::list<std::string>& theArguments,
1817 Events_InfoMessage& theError) const
1819 AttributeRefAttrPtr aRefAttr =
1820 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
1823 theError = "Incorrect attribute";
1828 if (aRefAttr->isObject())
1829 anOwner = aRefAttr->object();
1832 AttributePtr anAttr = aRefAttr->attr();
1833 anOwner = anAttr->owner();
1835 FeaturePtr anAttrOwnerFeature = ModelAPI_Feature::feature(anOwner);
1836 if (!anAttrOwnerFeature)
1838 AttributeBooleanPtr aCopyAttr = anAttrOwnerFeature->boolean(SketchPlugin_SketchEntity::COPY_ID());
1839 if (!aCopyAttr || !aCopyAttr->value())
1840 return true; // feature is not a copy, thus valid
1842 FeaturePtr aMultiFeature = ModelAPI_Feature::feature(theAttribute->owner());
1843 // Collect original entities
1844 std::set<FeaturePtr> anOriginalFeatures;
1845 if (theArguments.size() > 1) {
1846 AttributeRefListPtr anOrigList = aMultiFeature->reflist(theArguments.back());
1847 for (int i = 0; i < anOrigList->size(); ++i)
1849 FeaturePtr aFeature = ModelAPI_Feature::feature(anOrigList->object(i));
1850 if (aFeature == anAttrOwnerFeature)
1855 // check the copy feature is already referred by the "Multi" feature
1856 AttributeRefListPtr aRefList = aMultiFeature->reflist(theArguments.front());
1857 for (int i = 0; i < aRefList->size(); ++i)
1859 FeaturePtr aRefOwner = ModelAPI_Feature::feature(aRefList->object(i));
1860 if (aRefOwner == anAttrOwnerFeature)
1862 theError = "Attribute refers to the object generated by this feature";
1870 bool SketchPlugin_SketchFeatureValidator::isValid(const AttributePtr& theAttribute,
1871 const std::list<std::string>& theArguments,
1872 Events_InfoMessage& theError) const
1874 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId() &&
1875 theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
1876 theError = "The attribute with the %1 type is not processed";
1877 theError.arg(theAttribute->attributeType());
1881 // check the attribute refers to a sketch feature
1882 bool isSketchFeature = false;
1883 AttributeRefAttrPtr aRefAttr =
1884 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
1886 isSketchFeature = aRefAttr->isObject();
1887 if (isSketchFeature) {
1888 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1889 isSketchFeature = aFeature.get() != NULL;
1890 if (isSketchFeature) {
1891 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1892 std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
1893 isSketchFeature = aSketchFeature.get() != NULL;
1898 AttributeReferencePtr aReference =
1899 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
1901 FeaturePtr aFeature = ModelAPI_Feature::feature(aReference->value());
1902 isSketchFeature = aFeature.get() && aFeature->getKind() == SketchPlugin_Sketch::ID();
1906 if (!isSketchFeature)
1907 theError = "The object selected is not a sketch feature";
1908 return isSketchFeature;
1911 bool SketchPlugin_MultiRotationAngleValidator::isValid(const AttributePtr& theAttribute,
1912 const std::list<std::string>& theArguments,
1913 Events_InfoMessage& theError) const
1915 if (theAttribute->attributeType() != ModelAPI_AttributeDouble::typeId()) {
1916 theError = "The attribute with the %1 type is not processed";
1917 theError.arg(theAttribute->attributeType());
1921 AttributeDoublePtr anAngleAttr =
1922 std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
1924 FeaturePtr aMultiRotation = ModelAPI_Feature::feature(theAttribute->owner());
1925 AttributeStringPtr anAngleType =
1926 aMultiRotation->string(SketchPlugin_MultiRotation::ANGLE_TYPE());
1927 AttributeIntegerPtr aNbCopies =
1928 aMultiRotation->integer(SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID());
1930 if (anAngleType->value() != "FullAngle")
1932 double aFullAngleValue = anAngleAttr->value() * (aNbCopies->value() - 1);
1933 if (aFullAngleValue < -1.e-7 || aFullAngleValue > 359.9999999)
1935 theError = "Rotation single angle should produce full angle less than 360 degree";
1941 double aFullAngleValue = anAngleAttr->value();
1942 if (aFullAngleValue < -1.e-7 || aFullAngleValue > 360.0000001)
1944 theError = "Rotation full angle should be in range [0, 360]";
1952 bool SketchPlugin_BSplineValidator::isValid(const AttributePtr& theAttribute,
1953 const std::list<std::string>& theArguments,
1954 Events_InfoMessage& theError) const
1956 AttributePoint2DArrayPtr aPolesArray =
1957 std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
1961 if (aPolesArray->size() < 2) {
1962 theError = "Number of B-spline poles should be 2 or more";
1969 bool SketchPlugin_CurveFittingValidator::isValid(const FeaturePtr& theFeature,
1970 const std::list<std::string>& theArguments,
1971 Events_InfoMessage& theError) const
1973 AttributeRefAttrListPtr aRefAttrList =
1974 theFeature->refattrlist(SketchPlugin_CurveFitting::POINTS_ID());
1975 AttributeBooleanPtr aPeriodicAttr =
1976 theFeature->boolean(SketchPlugin_CurveFitting::PERIODIC_ID());
1978 // check number of selected entities
1979 int aMinNbPoints = aPeriodicAttr->value() ? 3 : 2;
1980 if (aRefAttrList->size() < aMinNbPoints) {
1981 theError = "Not enough points selected. Need at least %1 points.";
1982 theError.arg(aMinNbPoints);