1 // Copyright (C) 2014-2023 CEA, EDF
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 FeaturePtr anEdge1, anEdge2;
674 return isValidVertex(theAttribute, theError, anEdge1, anEdge2);
677 bool SketchPlugin_FilletVertexValidator::isValidVertex(const AttributePtr& theAttribute,
678 Events_InfoMessage& theError,
679 FeaturePtr& theEdge1,
680 FeaturePtr& theEdge2)
682 AttributeRefAttrPtr aPointRefAttr =
683 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
684 if(!aPointRefAttr.get()) {
685 theError = "Error: Point not selected.";
689 AttributePtr aPointAttribute = aPointRefAttr->attr();
690 if (!aPointAttribute.get()) {
691 theError = "Error: Bad point selected.";
694 std::shared_ptr<GeomAPI_Pnt2d> aSelectedPnt =
695 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttribute)->pnt();
697 // Obtain constraint coincidence for the fillet point.
698 const std::set<AttributePtr>& aRefsList = aPointAttribute->owner()->data()->refsToMe();
699 FeaturePtr aConstraintCoincidence;
700 for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin();
701 anIt != aRefsList.cend(); ++anIt) {
702 std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
703 FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
704 if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
705 if (!isPointPointCoincidence(aConstrFeature))
708 AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
709 aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
710 AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
711 aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
713 AttributePtr anAttrA = anAttrRefA->attr();
714 if(aPointAttribute == anAttrA) {
715 aConstraintCoincidence = aConstrFeature;
719 AttributePtr anAttrB = anAttrRefB->attr();
720 if(aPointAttribute == anAttrB) {
721 aConstraintCoincidence = aConstrFeature;
727 if(!aConstraintCoincidence.get()) {
728 theError = "Error: one of the selected point does not have coincidence.";
732 // Get coincides from constraint.
733 std::set<FeaturePtr> aCoinsides;
734 SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
735 SketchPlugin_ConstraintCoincidence::ENTITY_A(),
738 SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
739 SketchPlugin_ConstraintCoincidence::ENTITY_B(),
743 // Remove points and external lines from set of coincides.
744 std::set<FeaturePtr> aNewSetOfCoincides;
745 for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
746 anIt != aCoinsides.end(); ++anIt) {
747 std::shared_ptr<SketchPlugin_SketchEntity> aSketchEntity =
748 std::dynamic_pointer_cast<SketchPlugin_SketchEntity>(*anIt);
749 if(aSketchEntity.get() && (aSketchEntity->isCopy() || aSketchEntity->isExternal())) {
752 if((*anIt)->getKind() != SketchPlugin_Line::ID() &&
753 (*anIt)->getKind() != SketchPlugin_Arc::ID()) {
756 if((*anIt)->getKind() == SketchPlugin_Arc::ID()) {
757 AttributePtr anArcCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
758 std::shared_ptr<GeomAPI_Pnt2d> anArcCenterPnt =
759 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anArcCenter)->pnt();
760 double aDistSelectedArcCenter = aSelectedPnt->distance(anArcCenterPnt);
761 if(aDistSelectedArcCenter < tolerance) {
765 aNewSetOfCoincides.insert(*anIt);
767 aCoinsides = aNewSetOfCoincides;
769 // If we still have more than two coincides remove auxilary entities from set of coincides.
770 if(aCoinsides.size() > 2) {
771 aNewSetOfCoincides.clear();
772 for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
773 anIt != aCoinsides.end(); ++anIt) {
774 if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
775 aNewSetOfCoincides.insert(*anIt);
778 aCoinsides = aNewSetOfCoincides;
781 if(aCoinsides.size() != 2) {
782 theError = "Error: One of the selected points does not have two suitable edges for fillet.";
787 std::set<FeaturePtr>::iterator aFIt = aCoinsides.begin();
789 theEdge2 = *(++aFIt);
791 // Check that selected edges don't have tangent constraint.
792 std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
793 FeaturePtr aFirstFeature = *anIt++;
794 FeaturePtr aSecondFeature = *anIt;
795 const std::set<AttributePtr>& aFirstFeatureRefsList = aFirstFeature->data()->refsToMe();
796 if(hasSameTangentFeature(aFirstFeatureRefsList, aSecondFeature)) {
797 theError = "Error: Edges in selected point has tangent constraint.";
801 std::list<ResultPtr> aFirstResults = aFirstFeature->results();
802 for(std::list<ResultPtr>::iterator aResIt = aFirstResults.begin();
803 aResIt != aFirstResults.end(); ++aResIt) {
804 ResultPtr aRes = *aResIt;
805 const std::set<AttributePtr>& aResRefsList = aRes->data()->refsToMe();
806 if(hasSameTangentFeature(aResRefsList, aSecondFeature)) {
807 theError = "Error: Edges in selected point has tangent constraint.";
812 // Check the features are not tangent
813 std::shared_ptr<GeomAPI_Shape> aFirstShape = aFirstFeature->lastResult()->shape();
814 std::shared_ptr<GeomAPI_Shape> aSecondShape = aSecondFeature->lastResult()->shape();
815 if (!aFirstShape || !aFirstShape->isEdge() ||
816 !aSecondShape || !aSecondShape->isEdge()) {
817 theError = "Error: At least on of the features is not an edge";
821 std::shared_ptr<GeomAPI_Edge> anEdge1 = std::dynamic_pointer_cast<GeomAPI_Edge>(aFirstShape);
822 std::shared_ptr<GeomAPI_Edge> anEdge2 = std::dynamic_pointer_cast<GeomAPI_Edge>(aSecondShape);
824 static const double TOL = 1.e-7;
825 if (anEdge1->isLine() && anEdge2->isLine()) {
826 // Check that lines not collinear
827 std::shared_ptr<GeomAPI_Dir> aDir1 = anEdge1->line()->direction();
828 std::shared_ptr<GeomAPI_Dir> aDir2 = anEdge2->line()->direction();
829 double aCross = aDir1->cross(aDir2)->squareModulus();
830 if (aCross < TOL * TOL)
832 } else if (anEdge1->isArc() && anEdge2->isArc()) {
833 // check the circles are not tangent
834 std::shared_ptr<GeomAPI_Circ> aCirc1 = anEdge1->circle();
835 std::shared_ptr<GeomAPI_Circ> aCirc2 = anEdge2->circle();
836 double aDistCC = aCirc1->center()->distance(aCirc2->center());
837 double aRadSum = aCirc1->radius() + aCirc2->radius();
838 double aRadDiff = fabs(aCirc1->radius() - aCirc2->radius());
839 if (fabs(aDistCC - aRadSum) < TOL || fabs(aDistCC - aRadDiff) < TOL)
842 // check whether line and arc are tangent
843 std::shared_ptr<GeomAPI_Circ> aCirc;
844 std::shared_ptr<GeomAPI_Lin> aLine;
845 if (anEdge1->isLine()) {
846 aLine = anEdge1->line();
847 aCirc = anEdge2->circle();
849 aCirc = anEdge1->circle();
850 aLine = anEdge2->line();
853 double aDistCL = aLine->distance(aCirc->center());
854 if (fabs(aDistCL - aCirc->radius()) < TOL)
861 bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttribute,
862 const std::list<std::string>& theArguments,
863 Events_InfoMessage& theError) const
865 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
866 theError = "The attribute with the %1 type is not processed";
867 theError.arg(theAttribute->attributeType());
871 // there is a check whether the feature contains a point and a linear edge or two point values
872 std::string aParamA = theArguments.front();
874 FeaturePtr anAttributeFeature =
875 std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
876 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
877 AttributeRefAttrPtr anOtherAttr = anAttributeFeature->data()->refattr(aParamA);
879 AttributeRefAttrPtr aRefAttrs[2] = {aRefAttr, anOtherAttr};
882 for (int i = 0; i < 2; ++i) {
883 if (!aRefAttrs[i]->isObject())
886 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrs[i]->object());
888 if (aNbPoints + aNbLines != 0)
893 if (aFeature->getKind() == SketchPlugin_Point::ID())
895 else if (aFeature->getKind() == SketchPlugin_Line::ID() ||
896 aFeature->getKind() == SketchPlugin_Arc::ID() ||
897 aFeature->getKind() == SketchPlugin_EllipticArc::ID())
902 if (aNbPoints != 1 || aNbLines != 1) {
903 theError = "Middle point constraint allows points and lines only";
909 bool SketchPlugin_ArcTangentPointValidator::isValid(const AttributePtr& theAttribute,
910 const std::list<std::string>& /*theArguments*/,
911 Events_InfoMessage& theError) const
913 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
914 theError = "The attribute with the %1 type is not processed";
915 theError.arg(theAttribute->attributeType());
918 FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
919 AttributeStringPtr anArcTypeAttr = anOwner->string(SketchPlugin_MacroArc::ARC_TYPE());
920 if (anArcTypeAttr && anArcTypeAttr->value() != SketchPlugin_MacroArc::ARC_TYPE_BY_TANGENT_EDGE())
921 return true; // not applicable for non-tangent arcs
923 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
924 AttributePtr anAttr = aRefAttr->attr();
926 theError = "The attribute %1 should be a point";
927 theError.arg(theAttribute->id());
931 FeaturePtr anAttrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
932 const std::string& aFeatureType = anAttrFeature->getKind();
933 if (aFeatureType == SketchPlugin_Arc::ID()) {
934 // selected point should not be a center of arc
935 const std::string& aPntId = anAttr->id();
936 if (aPntId != SketchPlugin_Arc::START_ID() && aPntId != SketchPlugin_Arc::END_ID()) {
937 theError = "The attribute %1 is not supported";
938 theError.arg(aPntId);
942 else if (aFeatureType == SketchPlugin_Line::ID()) {
943 // selected point should be bound point of line
944 const std::string& aPntId = anAttr->id();
945 if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) {
946 theError = "The attribute %1 is not supported";
947 theError.arg(aPntId);
952 theError = "Unable to build tangent arc on %1";
953 theError.arg(anAttrFeature->getKind());
960 bool SketchPlugin_ArcTransversalPointValidator::isValid(
961 const AttributePtr& theAttribute,
962 const std::list<std::string>& /*theArguments*/,
963 Events_InfoMessage& theError) const
965 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
966 theError = "The attribute with the %1 type is not processed";
967 theError.arg(theAttribute->attributeType());
970 FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
971 AttributeStringPtr anArcTypeAttr = anOwner->string(SketchPlugin_MacroArc::ARC_TYPE());
973 anArcTypeAttr->value() != SketchPlugin_MacroArc::ARC_TYPE_BY_TRANSVERSAL_LINE())
974 return true; // not applicable for non-transversal arcs
976 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
977 AttributePtr anAttr = aRefAttr->attr();
979 theError = "The attribute %1 should be a point";
980 theError.arg(theAttribute->id());
984 FeaturePtr anAttrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
985 const std::string& aFeatureType = anAttrFeature->getKind();
986 if (aFeatureType == SketchPlugin_Line::ID()) {
987 // selected point should be bound point of line
988 const std::string& aPntId = anAttr->id();
989 if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) {
990 theError = "The attribute %1 is not supported";
991 theError.arg(aPntId);
996 theError = "Unable to build perpendicular arc on %1";
997 theError.arg(anAttrFeature->getKind());
1004 bool SketchPlugin_IntersectionValidator::isValid(const AttributePtr& theAttribute,
1005 const std::list<std::string>& theArguments,
1006 Events_InfoMessage& theError) const
1008 if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
1009 theError = "The attribute with the %1 type is not processed";
1010 theError.arg(theAttribute->attributeType());
1013 AttributeSelectionPtr anExternalAttr =
1014 std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
1015 std::shared_ptr<GeomAPI_Edge> anEdge;
1016 if (anExternalAttr && anExternalAttr->value() && anExternalAttr->value()->isEdge()) {
1017 anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(anExternalAttr->value()));
1018 } else if(anExternalAttr->context() && anExternalAttr->context()->shape() &&
1019 anExternalAttr->context()->shape()->isEdge()) {
1020 anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(anExternalAttr->context()->shape()));
1024 theError = "The attribute %1 should be an edge";
1025 theError.arg(theAttribute->id());
1030 std::shared_ptr<SketchPlugin_Sketch> aSketch;
1031 std::set<AttributePtr> aRefs = anExternalAttr->owner()->data()->refsToMe();
1032 std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
1033 for (; anIt != aRefs.end(); ++anIt) {
1034 CompositeFeaturePtr aComp =
1035 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
1036 if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
1037 aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
1042 theError = "There is no sketch referring to the current feature";
1046 // check the edge is intersected with sketch plane
1047 std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
1049 std::list<GeomPointPtr> anIntersectionsPoints;
1050 anEdge->intersectWithPlane(aPlane, anIntersectionsPoints);
1051 if (anIntersectionsPoints.empty()) {
1052 theError = "The edge is not intersected with sketch plane";
1058 bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute,
1059 const std::list<std::string>& theArguments,
1060 Events_InfoMessage& theError) const
1062 bool aValid = false;
1064 if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
1065 theError = "The attribute with the %1 type is not processed";
1066 theError.arg(theAttribute->attributeType());
1069 AttributeReferencePtr aFeatureAttr =
1070 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
1071 std::shared_ptr<SketchPlugin_Feature> aSplitFeature =
1072 std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
1074 ObjectPtr anAttrObject = aFeatureAttr->value();
1075 if (!anAttrObject) {
1076 AttributePtr aPreviewAttr = aSplitFeature->attribute(SketchPlugin_Trim::PREVIEW_OBJECT());
1077 aFeatureAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(aPreviewAttr);
1078 anAttrObject = aFeatureAttr->value();
1081 FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttrObject);
1085 // B-splines are not supported by the Split yet
1086 if (anAttrFeature->getKind() == SketchPlugin_BSpline::ID() ||
1087 anAttrFeature->getKind() == SketchPlugin_BSplinePeriodic::ID()) {
1088 theError = "Not supported";
1092 std::set<ResultPtr> anEdgeShapes;
1093 ModelGeomAlgo_Shape::shapesOfType(anAttrFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
1094 if (anEdgeShapes.empty() || anEdgeShapes.size() > 1 /*there case has not existed yet*/)
1097 // coincidences to the feature
1098 std::set<std::shared_ptr<GeomDataAPI_Point2D> > aRefAttributes;
1099 ModelGeomAlgo_Point2D::getPointsOfReference(anAttrFeature,
1100 SketchPlugin_ConstraintCoincidence::ID(),
1101 aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
1103 GeomShapePtr anAttrShape = (*anEdgeShapes.begin())->shape();
1104 std::shared_ptr<SketchPlugin_Feature> aSFeature =
1105 std::dynamic_pointer_cast<SketchPlugin_Feature>(anAttrFeature);
1106 if (!aSFeature || aSFeature->isCopy())
1108 SketchPlugin_Sketch* aSketch = aSFeature->sketch();
1110 std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
1111 std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
1112 aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
1113 std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
1114 aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
1115 std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
1116 aData->attribute(SketchPlugin_Sketch::NORM_ID()));
1117 std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
1119 typedef std::map<std::shared_ptr<GeomAPI_Pnt>,
1120 std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
1121 std::list<std::shared_ptr<ModelAPI_Object> > > > PointToRefsMap;
1122 PointToRefsMap aPointsInfo;
1124 ModelGeomAlgo_Point2D::getPointsInsideShape(anAttrShape, aRefAttributes, aC->pnt(),
1125 aX->dir(), aDirY, aPointsInfo);
1126 int aCoincidentToFeature = (int)aPointsInfo.size();
1127 if (anAttrFeature->getKind() == SketchPlugin_Circle::ID() ||
1128 anAttrFeature->getKind() == SketchPlugin_Ellipse::ID())
1129 aValid = aCoincidentToFeature >= 2;
1131 aValid = aCoincidentToFeature >= 1;
1136 bool SketchPlugin_TrimValidator::isValid(const AttributePtr& theAttribute,
1137 const std::list<std::string>& theArguments,
1138 Events_InfoMessage& theError) const
1140 bool aValid = false;
1142 if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
1143 theError = "The attribute with the %1 type is not processed";
1144 theError.arg(theAttribute->attributeType());
1147 AttributeReferencePtr aBaseObjectAttr =
1148 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
1150 std::shared_ptr<SketchPlugin_Feature> aTrimFeature =
1151 std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
1153 ObjectPtr aBaseObject = aBaseObjectAttr->value();
1155 AttributePtr aPreviewAttr = aTrimFeature->attribute(SketchPlugin_Trim::PREVIEW_OBJECT());
1156 aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(aPreviewAttr);
1157 aBaseObject = aBaseObjectAttr->value();
1160 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject);
1164 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1165 std::dynamic_pointer_cast<SketchPlugin_Feature>(aBaseFeature);
1166 if (!aSketchFeature.get() || aSketchFeature->isCopy())
1169 // B-splines are not supported by the Trim yet
1170 if (aBaseFeature->getKind() == SketchPlugin_BSpline::ID() ||
1171 aBaseFeature->getKind() == SketchPlugin_BSplinePeriodic::ID()) {
1172 theError = "Not supported";
1177 AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1178 aTrimFeature->data()->attribute(SketchPlugin_Trim::PREVIEW_POINT()));
1180 SketchPlugin_Sketch* aSketch = aTrimFeature->sketch();
1182 std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPoint->pnt();
1183 std::shared_ptr<GeomAPI_Pnt> anAttributePnt = aSketch->to3D(anAttributePnt2d->x(),
1184 anAttributePnt2d->y());
1186 std::map<ObjectPtr, std::set<GeomShapePtr> > aCashedShapes;
1187 std::map<ObjectPtr, std::map<std::shared_ptr<GeomAPI_Pnt>,
1188 std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
1189 std::list<std::shared_ptr<ModelAPI_Object> > > > > anObjectToPoints;
1190 SketchPlugin_SegmentationTools::fillObjectShapes(
1191 aTrimFeature.get(), aBaseObject, aCashedShapes, anObjectToPoints);
1192 const std::set<GeomShapePtr>& aShapes = aCashedShapes[aBaseObject];
1194 return aShapes.size() > 1;
1197 bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
1198 const std::list<std::string>& theArguments,
1199 Events_InfoMessage& theError) const
1201 if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
1202 theError = "The attribute with the %1 type is not processed";
1203 theError.arg(theAttribute->attributeType());
1207 AttributeSelectionPtr aFeatureAttr =
1208 std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
1209 std::shared_ptr<GeomAPI_Vertex> aVertex;
1210 std::shared_ptr<GeomAPI_Edge> anEdge;
1211 std::shared_ptr<SketchPlugin_Feature> aSketchFeature;
1212 if (aFeatureAttr.get()) {
1213 GeomShapePtr aVal = aFeatureAttr->value();
1214 ResultPtr aRes = aFeatureAttr->context();
1215 if (aVal && aVal->isVertex())
1216 aVertex = std::shared_ptr<GeomAPI_Vertex>(new GeomAPI_Vertex(aVal));
1217 else if (aVal && aVal->isEdge()) {
1218 anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aVal));
1219 } else if(aRes && aRes->shape()) {
1220 if (aRes->shape()->isVertex())
1221 aVertex = std::shared_ptr<GeomAPI_Vertex>(new GeomAPI_Vertex(aRes->shape()));
1222 else if (aRes->shape()->isEdge())
1223 anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aRes->shape()));
1226 // try to convert result to sketch feature
1229 std::dynamic_pointer_cast<SketchPlugin_Feature>(ModelAPI_Feature::feature(aRes));
1232 if (!aVertex && !anEdge) {
1233 theError = "The attribute %1 should be an edge or vertex";
1234 theError.arg(theAttribute->id());
1239 std::shared_ptr<SketchPlugin_Sketch> aSketch;
1240 std::set<AttributePtr> aRefs = theAttribute->owner()->data()->refsToMe();
1241 std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
1242 for (; anIt != aRefs.end(); ++anIt) {
1243 CompositeFeaturePtr aComp =
1244 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
1245 if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
1246 aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
1251 theError = "There is no sketch referring to the current feature";
1254 if (aSketchFeature && aSketch.get() == aSketchFeature->sketch()) {
1255 theError = "Unable to project feature from the same sketch";
1259 std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
1260 std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
1261 std::shared_ptr<GeomAPI_Pnt> anOrigin = aPlane->location();
1265 aValid = true; // vertex is always could be projected
1266 else if (anEdge->isLine()) {
1267 std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
1268 std::shared_ptr<GeomAPI_Dir> aLineDir = aLine->direction();
1269 double aDot = fabs(aNormal->dot(aLineDir));
1270 aValid = fabs(aDot - 1.0) >= tolerance * tolerance;
1272 theError = "Error: Line is orthogonal to the sketch plane.";
1274 else if (anEdge->isCircle() || anEdge->isArc()) {
1275 std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
1276 std::shared_ptr<GeomAPI_Dir> aCircNormal = aCircle->normal();
1277 double aDot = fabs(aNormal->dot(aCircNormal));
1278 aValid = aDot >= tolerance * tolerance;
1280 theError.arg(anEdge->isCircle() ? "Error: Circle is orthogonal to the sketch plane."
1281 : "Error: Arc is orthogonal to the sketch plane.");
1283 else if (anEdge->isEllipse()) {
1284 std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
1285 std::shared_ptr<GeomAPI_Dir> anEllipseNormal = anEllipse->normal();
1286 double aDot = fabs(aNormal->dot(anEllipseNormal));
1287 aValid = aDot >= tolerance * tolerance;
1289 theError.arg(anEdge->isClosed() ? "Error: Ellipse is orthogonal to the sketch plane."
1290 : "Error: Elliptic Arc is orthogonal to the sketch plane.");
1292 else if (anEdge->isBSpline()) {
1293 // check B-spline is periodic and planar
1294 std::shared_ptr<GeomAPI_Curve> aCurve(new GeomAPI_Curve(anEdge));
1295 std::shared_ptr<GeomAPI_BSpline> aBSpline(new GeomAPI_BSpline(aCurve));
1296 if (aBSpline->isPeriodic()) {
1297 GeomPlanePtr aBSplinePlane = GeomAlgoAPI_ShapeTools::findPlane(ListOfShape(1, anEdge));
1298 if (aBSplinePlane) {
1299 std::shared_ptr<GeomAPI_Dir> aBSplineNormal = aBSplinePlane->direction();
1300 double aDot = fabs(aNormal->dot(aBSplineNormal));
1301 aValid = aDot > tolerance * tolerance;
1303 // B-spline's plane is orthogonal to the sketch plane,
1304 // thus, need to check whether B-spline is planar.
1305 std::list<GeomPointPtr> aPoles = aBSpline->poles();
1306 for (std::list<GeomPointPtr>::iterator it = aPoles.begin();
1307 it != aPoles.end() && !aValid; ++it) {
1308 if (aBSplinePlane->distance(*it) > tolerance)
1309 aValid = true; // non-planar B-spline curve
1312 theError = "Error: Periodic B-spline is orthogonal to the sketch plane.";
1322 static std::set<FeaturePtr> common(const std::set<FeaturePtr>& theSet1,
1323 const std::set<FeaturePtr>& theSet2)
1325 std::set<FeaturePtr> aCommon;
1326 if (theSet1.empty() || theSet2.empty())
1329 std::set<FeaturePtr>::const_iterator anIt2 = theSet2.begin();
1330 for (; anIt2 != theSet2.end(); ++anIt2)
1331 if (theSet1.find(*anIt2) != theSet1.end())
1332 aCommon.insert(*anIt2);
1336 bool SketchPlugin_DifferentReferenceValidator::isValid(
1337 const AttributePtr& theAttribute,
1338 const std::list<std::string>& theArguments,
1339 Events_InfoMessage& theError) const
1341 FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1343 int aNbFeaturesReferred = 0;
1344 int aNbAttributesReferred = 0;
1345 std::set<FeaturePtr> aCommonReferredFeatures;
1347 // find all features referred by attributes listed in theArguments
1348 std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1349 for (; anArgIt != theArguments.end(); ++anArgIt) {
1350 AttributeRefAttrPtr aRefAttr = anOwner->refattr(*anArgIt);
1354 std::set<FeaturePtr> aCoincidentFeatures;
1355 if (aRefAttr->isObject()) {
1356 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1358 aCoincidentFeatures.insert(aFeature);
1359 aNbFeaturesReferred += 1;
1362 AttributePoint2DPtr aPoint =
1363 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1365 aCoincidentFeatures = SketchPlugin_Tools::findFeaturesCoincidentToPoint(aPoint);
1366 aNbAttributesReferred += 1;
1370 if (aCommonReferredFeatures.empty())
1371 aCommonReferredFeatures = aCoincidentFeatures;
1373 aCommonReferredFeatures = common(aCommonReferredFeatures, aCoincidentFeatures);
1375 if (aCommonReferredFeatures.empty())
1379 bool isOk = aNbFeaturesReferred < 1;
1380 if (aNbFeaturesReferred == 1) {
1381 if (aCommonReferredFeatures.size() == 1) {
1382 FeaturePtr aFeature = *aCommonReferredFeatures.begin();
1383 isOk = aNbAttributesReferred <= 1 ||
1384 aFeature->getKind() == SketchPlugin_Circle::ID() ||
1385 aFeature->getKind() == SketchPlugin_Arc::ID();
1391 theError = "Attributes are referred to the same feature";
1395 bool SketchPlugin_DifferentPointReferenceValidator::isValid(
1396 const AttributePtr& theAttribute,
1397 const std::list<std::string>& theArguments,
1398 Events_InfoMessage& theError) const
1400 FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1401 std::set<AttributePoint2DPtr> aReferredCoincidentPoints;
1403 // find all points referred by attributes listed in theArguments
1404 bool hasRefsToPoints = false;
1405 std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1406 for (; anArgIt != theArguments.end(); ++anArgIt) {
1407 AttributeRefAttrPtr aRefAttr = anOwner->refattr(*anArgIt);
1411 if (!aRefAttr->isObject()) {
1412 AttributePoint2DPtr aPoint =
1413 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1414 if (aReferredCoincidentPoints.empty())
1415 aReferredCoincidentPoints = SketchPlugin_Tools::findPointsCoincidentToPoint(aPoint);
1416 else if (aReferredCoincidentPoints.find(aPoint) == aReferredCoincidentPoints.end())
1417 return true; // non-coincident point has been found
1419 hasRefsToPoints = true;
1423 if (hasRefsToPoints)
1424 theError = "Attributes are referred to the same point";
1425 return !hasRefsToPoints;
1428 bool SketchPlugin_CirclePassedPointValidator::isValid(
1429 const AttributePtr& theAttribute,
1430 const std::list<std::string>&,
1431 Events_InfoMessage& theError) const
1433 static const std::string aErrorMessage(
1434 "Passed point refers to the same feature as a center point");
1436 FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1438 AttributeRefAttrPtr aCenterRef =
1439 anOwner->refattr(SketchPlugin_MacroCircle::CENTER_POINT_REF_ID());
1440 AttributeRefAttrPtr aPassedRef =
1441 anOwner->refattr(SketchPlugin_MacroCircle::PASSED_POINT_REF_ID());
1443 if (!aPassedRef->isObject())
1446 FeaturePtr aPassedFeature = ModelAPI_Feature::feature(aPassedRef->object());
1447 if (!aPassedFeature)
1450 if (aCenterRef->isObject()) {
1451 if (aCenterRef->object() == aPassedRef->object()) {
1452 theError = aErrorMessage;
1456 AttributePoint2DPtr aCenterPoint =
1457 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCenterRef->attr());
1459 std::set<FeaturePtr> aCoincidentFeatures =
1460 SketchPlugin_Tools::findFeaturesCoincidentToPoint(aCenterPoint);
1461 // check one of coincident features is a feature referred by passed point
1462 std::set<FeaturePtr>::const_iterator anIt = aCoincidentFeatures.begin();
1463 for(; anIt != aCoincidentFeatures.end(); ++anIt)
1464 if (*anIt == aPassedFeature) {
1465 theError = aErrorMessage;
1473 bool SketchPlugin_ThirdPointValidator::isValid(
1474 const AttributePtr& theAttribute,
1475 const std::list<std::string>& theArguments,
1476 Events_InfoMessage& theError) const
1478 FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1479 return arePointsNotOnLine(anOwner, theError) &&
1480 arePointsNotSeparated(anOwner, theArguments, theError);
1483 static std::shared_ptr<GeomAPI_Pnt2d> toPoint(const FeaturePtr& theMacroCircle,
1484 const std::string& thePointAttrName,
1485 const std::string& theRefPointAttrName)
1487 AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1488 theMacroCircle->attribute(thePointAttrName));
1489 AttributeRefAttrPtr aRefAttr = theMacroCircle->refattr(theRefPointAttrName);
1491 std::shared_ptr<GeomAPI_Pnt2d> aPoint = aPointAttr->pnt();
1493 if (aRefAttr->isObject()) {
1494 // project a point onto selected feature
1495 std::shared_ptr<SketchPlugin_Feature> aFeature =
1496 std::dynamic_pointer_cast<SketchPlugin_Feature>(
1497 ModelAPI_Feature::feature(aRefAttr->object()));
1499 SketchPlugin_Sketch* aSketch = aFeature->sketch();
1500 std::shared_ptr<GeomAPI_Edge> anEdge =
1501 std::dynamic_pointer_cast<GeomAPI_Edge>(aFeature->lastResult()->shape());
1503 std::shared_ptr<GeomAPI_Pnt> aPoint3D = aSketch->to3D(aPoint->x(), aPoint->y());
1504 if (anEdge->isLine())
1505 aPoint3D = anEdge->line()->project(aPoint3D);
1506 else if (anEdge->isCircle())
1507 aPoint3D = anEdge->circle()->project(aPoint3D);
1509 aPoint = aSketch->to2D(aPoint3D);
1513 AttributePoint2DPtr anOtherPoint =
1514 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1516 aPoint = anOtherPoint->pnt(); // the reference point is much more precise, use it
1523 static void threePointsOfFeature(const FeaturePtr& theMacroFeature,
1524 std::shared_ptr<GeomAPI_Pnt2d> thePoints[3])
1526 if (theMacroFeature->getKind() == SketchPlugin_MacroCircle::ID()) {
1527 thePoints[0] = toPoint(theMacroFeature,
1528 SketchPlugin_MacroCircle::FIRST_POINT_ID(),
1529 SketchPlugin_MacroCircle::FIRST_POINT_REF_ID());
1530 thePoints[1] = toPoint(theMacroFeature,
1531 SketchPlugin_MacroCircle::SECOND_POINT_ID(),
1532 SketchPlugin_MacroCircle::SECOND_POINT_REF_ID());
1533 thePoints[2] = toPoint(theMacroFeature,
1534 SketchPlugin_MacroCircle::THIRD_POINT_ID(),
1535 SketchPlugin_MacroCircle::THIRD_POINT_REF_ID());
1536 } else if (theMacroFeature->getKind() == SketchPlugin_MacroArc::ID()) {
1537 thePoints[0] = toPoint(theMacroFeature,
1538 SketchPlugin_MacroArc::START_POINT_2_ID(),
1539 SketchPlugin_MacroArc::START_POINT_REF_ID());
1540 thePoints[1] = toPoint(theMacroFeature,
1541 SketchPlugin_MacroArc::END_POINT_2_ID(),
1542 SketchPlugin_MacroArc::END_POINT_REF_ID());
1543 thePoints[2] = toPoint(theMacroFeature,
1544 SketchPlugin_MacroArc::PASSED_POINT_ID(),
1545 SketchPlugin_MacroArc::PASSED_POINT_REF_ID());
1549 static bool isPointsOnLine(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint1,
1550 const std::shared_ptr<GeomAPI_Pnt2d>& thePoint2,
1551 const std::shared_ptr<GeomAPI_Pnt2d>& thePoint3)
1553 static const double aTolerance = 1.e-7;
1554 if (thePoint1->distance(thePoint2) < aTolerance ||
1555 thePoint1->distance(thePoint3) < aTolerance)
1558 std::shared_ptr<GeomAPI_Dir2d> aDirP1P2(new GeomAPI_Dir2d(thePoint2->x() - thePoint1->x(),
1559 thePoint2->y() - thePoint1->y()));
1560 std::shared_ptr<GeomAPI_Dir2d> aDirP1P3(new GeomAPI_Dir2d(thePoint3->x() - thePoint1->x(),
1561 thePoint3->y() - thePoint1->y()));
1562 return fabs(aDirP1P2->cross(aDirP1P3)) < aTolerance;
1565 static bool isOnSameSide(const std::shared_ptr<GeomAPI_Lin>& theLine,
1566 const std::shared_ptr<GeomAPI_Pnt>& thePoint1,
1567 const std::shared_ptr<GeomAPI_Pnt>& thePoint2)
1569 static const double aTolerance = 1.e-7;
1570 std::shared_ptr<GeomAPI_Dir> aLineDir = theLine->direction();
1571 std::shared_ptr<GeomAPI_XYZ> aLineLoc = theLine->location()->xyz();
1573 std::shared_ptr<GeomAPI_XYZ> aVec1 = thePoint1->xyz()->decreased(aLineLoc);
1574 // the first point is on the line
1575 if (aVec1->squareModulus() < aTolerance * aTolerance)
1577 std::shared_ptr<GeomAPI_Dir> aDirP1L(new GeomAPI_Dir(aVec1));
1578 std::shared_ptr<GeomAPI_XYZ> aVec2 = thePoint2->xyz()->decreased(aLineLoc);
1579 // the second point is on the line
1580 if (aVec2->squareModulus() < aTolerance * aTolerance)
1582 std::shared_ptr<GeomAPI_Dir> aDirP2L(new GeomAPI_Dir(aVec2));
1584 return aLineDir->cross(aDirP1L)->dot(aLineDir->cross(aDirP2L)) > -aTolerance;
1587 static bool isOnSameSide(const std::shared_ptr<GeomAPI_Circ>& theCircle,
1588 const std::shared_ptr<GeomAPI_Pnt>& thePoint1,
1589 const std::shared_ptr<GeomAPI_Pnt>& thePoint2)
1591 static const double aTolerance = 1.e-7;
1592 std::shared_ptr<GeomAPI_Pnt> aCenter = theCircle->center();
1593 double aDistP1C = thePoint1->distance(aCenter);
1594 double aDistP2C = thePoint2->distance(aCenter);
1595 return (aDistP1C - theCircle->radius()) * (aDistP2C - theCircle->radius()) > -aTolerance;
1598 bool SketchPlugin_ThirdPointValidator::arePointsNotOnLine(
1599 const FeaturePtr& theMacroFeature,
1600 Events_InfoMessage& theError) const
1602 static const std::string aErrorPointsOnLine(
1603 "Selected points are on the same line");
1605 std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
1606 threePointsOfFeature(theMacroFeature, aPoints);
1608 if (isPointsOnLine(aPoints[0], aPoints[1], aPoints[2])) {
1609 theError = aErrorPointsOnLine;
1615 bool SketchPlugin_ThirdPointValidator::arePointsNotSeparated(
1616 const FeaturePtr& theMacroFeature,
1617 const std::list<std::string>& theArguments,
1618 Events_InfoMessage& theError) const
1620 static const std::string aErrorPointsApart(
1621 "Selected entity is lying between first two points");
1623 AttributeRefAttrPtr aThirdPointRef = theMacroFeature->refattr(theArguments.front());
1624 FeaturePtr aRefByThird;
1625 if (aThirdPointRef->isObject())
1626 aRefByThird = ModelAPI_Feature::feature(aThirdPointRef->object());
1630 std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
1631 threePointsOfFeature(theMacroFeature, aPoints);
1633 std::shared_ptr<GeomAPI_Edge> aThirdShape =
1634 std::dynamic_pointer_cast<GeomAPI_Edge>(aRefByThird->lastResult()->shape());
1638 SketchPlugin_Sketch* aSketch =
1639 std::dynamic_pointer_cast<SketchPlugin_Feature>(theMacroFeature)->sketch();
1640 std::shared_ptr<GeomAPI_Pnt> aFirstPnt3D = aSketch->to3D(aPoints[0]->x(), aPoints[0]->y());
1641 std::shared_ptr<GeomAPI_Pnt> aSecondPnt3D = aSketch->to3D(aPoints[1]->x(), aPoints[1]->y());
1644 if (aThirdShape->isLine())
1645 isOk = isOnSameSide(aThirdShape->line(), aFirstPnt3D, aSecondPnt3D);
1646 else if (aThirdShape->isCircle() || aThirdShape->isArc())
1647 isOk = isOnSameSide(aThirdShape->circle(), aFirstPnt3D, aSecondPnt3D);
1650 theError = aErrorPointsApart;
1654 bool SketchPlugin_ArcEndPointValidator::isValid(
1655 const AttributePtr& theAttribute,
1656 const std::list<std::string>& theArguments,
1657 Events_InfoMessage& theError) const
1659 FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
1660 AttributeRefAttrPtr anEndPointRef = aFeature->refattr(theArguments.front());
1662 if(!anEndPointRef.get()) {
1666 ObjectPtr anObject = anEndPointRef->object();
1667 AttributePtr anAttr = anEndPointRef->attr();
1668 if(!anObject.get() && !anAttr.get()) {
1672 if(anEndPointRef->attr().get()) {
1676 ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1678 GeomShapePtr aShape = aResult->shape();
1679 if(aShape.get() && aShape->isVertex()) {
1684 aFeature = ModelAPI_Feature::feature(anObject);
1685 if(aFeature.get()) {
1686 if(aFeature->getKind() == SketchPlugin_Point::ID()) {
1694 static GeomShapePtr toInfiniteEdge(const GeomShapePtr theShape)
1696 if(!theShape.get()) {
1700 if(!theShape->isEdge()) {
1704 std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(theShape));
1710 if(anEdge->isLine()) {
1711 std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
1712 GeomShapePtr aShape = GeomAlgoAPI_EdgeBuilder::line(aLine);
1716 if(anEdge->isCircle() || anEdge->isArc()) {
1717 std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
1718 GeomShapePtr aShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCircle);
1725 bool SketchPlugin_ArcEndPointIntersectionValidator::isValid(
1726 const AttributePtr& theAttribute,
1727 const std::list<std::string>& theArguments,
1728 Events_InfoMessage& theError) const
1730 std::shared_ptr<SketchPlugin_MacroArc> anArcFeature =
1731 std::dynamic_pointer_cast<SketchPlugin_MacroArc>(theAttribute->owner());
1732 AttributeRefAttrPtr anEndPointRef = anArcFeature->refattr(theArguments.front());
1734 if(!anEndPointRef.get()) {
1738 GeomShapePtr anArcShape = toInfiniteEdge(anArcFeature->getArcShape(false));
1740 if(!anArcShape.get() || anArcShape->isNull()) {
1744 ObjectPtr anObject = anEndPointRef->object();
1745 AttributePtr anAttr = anEndPointRef->attr();
1746 if(!anObject.get() && !anAttr.get()) {
1750 ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1752 GeomShapePtr aShape = aResult->shape();
1753 if (!aShape->isEdge())
1755 aShape = toInfiniteEdge(aShape);
1756 if(aShape.get() && !aShape->isNull()) {
1757 if(anArcShape->isIntersect(aShape)) {
1763 FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(anObject);
1764 if(aSelectedFeature.get()) {
1765 std::list<ResultPtr> aResults = aSelectedFeature->results();
1766 for(std::list<ResultPtr>::const_iterator anIt = aResults.cbegin();
1767 anIt != aResults.cend();
1770 GeomShapePtr aShape = (*anIt)->shape();
1771 if (!aShape->isEdge())
1773 aShape = toInfiniteEdge(aShape);
1774 if(aShape.get() && !aShape->isNull()) {
1775 if(anArcShape->isIntersect(aShape)) {
1785 bool SketchPlugin_HasNoConstraint::isValid(const AttributePtr& theAttribute,
1786 const std::list<std::string>& theArguments,
1787 Events_InfoMessage& theError) const
1789 std::set<std::string> aFeatureKinds;
1790 for (std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1791 anArgIt != theArguments.end(); anArgIt++) {
1792 aFeatureKinds.insert(*anArgIt);
1795 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
1796 theError = "The attribute with the %1 type is not processed";
1797 theError.arg(theAttribute->attributeType());
1801 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
1803 bool isObject = aRefAttr->isObject();
1805 theError = "It uses an empty object";
1808 ObjectPtr anObject = aRefAttr->object();
1809 FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
1810 if (!aFeature.get()) {
1811 theError = "The feature of the checked attribute is empty";
1815 FeaturePtr aCurrentFeature = ModelAPI_Feature::feature(aRefAttr->owner());
1817 std::set<AttributePtr> aRefsList = anObject->data()->refsToMe();
1818 std::set<AttributePtr>::const_iterator anIt = aRefsList.begin();
1819 for (; anIt != aRefsList.end(); anIt++) {
1820 FeaturePtr aRefFeature = ModelAPI_Feature::feature((*anIt)->owner());
1821 if (aRefFeature.get() && aCurrentFeature != aRefFeature &&
1822 aFeatureKinds.find(aRefFeature->getKind()) != aFeatureKinds.end())
1823 return false; // constraint is found, that means that the check is not valid
1828 bool SketchPlugin_ReplicationReferenceValidator::isValid(
1829 const AttributePtr& theAttribute,
1830 const std::list<std::string>& theArguments,
1831 Events_InfoMessage& theError) const
1833 AttributeRefAttrPtr aRefAttr =
1834 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
1837 theError = "Incorrect attribute";
1842 if (aRefAttr->isObject())
1843 anOwner = aRefAttr->object();
1846 AttributePtr anAttr = aRefAttr->attr();
1847 anOwner = anAttr->owner();
1849 FeaturePtr anAttrOwnerFeature = ModelAPI_Feature::feature(anOwner);
1850 if (!anAttrOwnerFeature)
1852 AttributeBooleanPtr aCopyAttr = anAttrOwnerFeature->boolean(SketchPlugin_SketchEntity::COPY_ID());
1853 if (!aCopyAttr || !aCopyAttr->value())
1854 return true; // feature is not a copy, thus valid
1856 FeaturePtr aMultiFeature = ModelAPI_Feature::feature(theAttribute->owner());
1857 // Collect original entities
1858 std::set<FeaturePtr> anOriginalFeatures;
1859 if (theArguments.size() > 1) {
1860 AttributeRefListPtr anOrigList = aMultiFeature->reflist(theArguments.back());
1861 for (int i = 0; i < anOrigList->size(); ++i)
1863 FeaturePtr aFeature = ModelAPI_Feature::feature(anOrigList->object(i));
1864 if (aFeature == anAttrOwnerFeature)
1869 // check the copy feature is already referred by the "Multi" feature
1870 AttributeRefListPtr aRefList = aMultiFeature->reflist(theArguments.front());
1871 for (int i = 0; i < aRefList->size(); ++i)
1873 FeaturePtr aRefOwner = ModelAPI_Feature::feature(aRefList->object(i));
1874 if (aRefOwner == anAttrOwnerFeature)
1876 theError = "Attribute refers to the object generated by this feature";
1884 bool SketchPlugin_SketchFeatureValidator::isValid(const AttributePtr& theAttribute,
1885 const std::list<std::string>& theArguments,
1886 Events_InfoMessage& theError) const
1888 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId() &&
1889 theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
1890 theError = "The attribute with the %1 type is not processed";
1891 theError.arg(theAttribute->attributeType());
1895 // check the attribute refers to a sketch feature
1896 bool isSketchFeature = false;
1897 AttributeRefAttrPtr aRefAttr =
1898 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
1900 isSketchFeature = aRefAttr->isObject();
1901 if (isSketchFeature) {
1902 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1903 isSketchFeature = aFeature.get() != NULL;
1904 if (isSketchFeature) {
1905 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1906 std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
1907 isSketchFeature = aSketchFeature.get() != NULL;
1912 AttributeReferencePtr aReference =
1913 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
1915 FeaturePtr aFeature = ModelAPI_Feature::feature(aReference->value());
1916 isSketchFeature = aFeature.get() && aFeature->getKind() == SketchPlugin_Sketch::ID();
1920 if (!isSketchFeature)
1921 theError = "The object selected is not a sketch feature";
1922 return isSketchFeature;
1925 bool SketchPlugin_MultiRotationAngleValidator::isValid(const AttributePtr& theAttribute,
1926 const std::list<std::string>& theArguments,
1927 Events_InfoMessage& theError) const
1929 if (theAttribute->attributeType() != ModelAPI_AttributeDouble::typeId()) {
1930 theError = "The attribute with the %1 type is not processed";
1931 theError.arg(theAttribute->attributeType());
1935 AttributeDoublePtr anAngleAttr =
1936 std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
1938 FeaturePtr aMultiRotation = ModelAPI_Feature::feature(theAttribute->owner());
1939 AttributeStringPtr anAngleType =
1940 aMultiRotation->string(SketchPlugin_MultiRotation::ANGLE_TYPE());
1941 AttributeIntegerPtr aNbCopies =
1942 aMultiRotation->integer(SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID());
1944 if (anAngleType->value() != "FullAngle")
1946 double aFullAngleValue = anAngleAttr->value() * (aNbCopies->value() - 1);
1947 if (aFullAngleValue < -1.e-7 || aFullAngleValue > 359.9999999)
1949 theError = "Rotation single angle should produce full angle less than 360 degree";
1955 double aFullAngleValue = anAngleAttr->value();
1956 if (aFullAngleValue < -1.e-7 || aFullAngleValue > 360.0000001)
1958 theError = "Rotation full angle should be in range [0, 360]";
1966 bool SketchPlugin_BSplineValidator::isValid(const AttributePtr& theAttribute,
1967 const std::list<std::string>& theArguments,
1968 Events_InfoMessage& theError) const
1970 AttributePoint2DArrayPtr aPolesArray =
1971 std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
1975 if (aPolesArray->size() < 2) {
1976 theError = "Number of B-spline poles should be 2 or more";
1983 bool SketchPlugin_CurveFittingValidator::isValid(const FeaturePtr& theFeature,
1984 const std::list<std::string>& theArguments,
1985 Events_InfoMessage& theError) const
1987 AttributeRefAttrListPtr aRefAttrList =
1988 theFeature->refattrlist(SketchPlugin_CurveFitting::POINTS_ID());
1989 AttributeBooleanPtr aPeriodicAttr =
1990 theFeature->boolean(SketchPlugin_CurveFitting::PERIODIC_ID());
1992 // check number of selected entities
1993 int aMinNbPoints = aPeriodicAttr->value() ? 3 : 2;
1994 if (aRefAttrList->size() < aMinNbPoints) {
1995 theError = "Not enough points selected. Need at least %1 points.";
1996 theError.arg(aMinNbPoints);