- // By default, the start point of fillet arc is connected to FeatureA,
- // and the end point - to FeatureB. But when the angle between TangentDirA and
- // TangentDirB greater 180 degree, the sequaence of features need to be reversed.
- double cosBA = aTangentDir[0]->cross(aTangentDir[1]); // cos(B-A), where A and B - angles between corresponding tanget direction and the X axis
- bool isReversed = cosBA > 0.0;
-
- // Calculate fillet arc parameters
- std::shared_ptr<GeomAPI_XY> aCenter, aTangentPntA, aTangentPntB;
- calculateFilletCenter(aBaseEdgeA, aBaseEdgeB, aFilletRadius, isStart, aCenter, aTangentPntA, aTangentPntB);
- if(!aCenter.get() || !aTangentPntA.get() || !aTangentPntB.get()) {
- setError("Can not create fillet with the specified parameters.");
- return;
- }
- // update features
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aResultEdgeA->attribute(aFeatAttributes[isStart[0] ? 0 : 1]))->setValue(aTangentPntA->x(), aTangentPntA->y());
- aResultEdgeA->execute();
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aResultEdgeB->attribute(aFeatAttributes[2 + (isStart[1] ? 0 : 1)]))->setValue(aTangentPntB->x(), aTangentPntB->y());
- aResultEdgeB->execute();
- // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated"
- // by arc; moreover, it may cause cyclicity in hte mechanism of updater
- aResultArc->data()->blockSendAttributeUpdated(true);
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aResultArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(aCenter->x(), aCenter->y());
- if(isReversed) {
- std::shared_ptr<GeomAPI_XY> aTmp = aTangentPntA;
- aTangentPntA = aTangentPntB;
- aTangentPntB = aTmp;
- }
- std::shared_ptr<GeomDataAPI_Point2D> aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aResultArc->attribute(SketchPlugin_Arc::START_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aResultArc->attribute(SketchPlugin_Arc::END_ID()));
- if(aStartPoint->isInitialized() && aEndPoint->isInitialized() &&
- (aStartPoint->pnt()->xy()->distance(aTangentPntA) > tolerance ||
- aEndPoint->pnt()->xy()->distance(aTangentPntB) > tolerance)) {
- std::dynamic_pointer_cast<SketchPlugin_Arc>(aResultArc)->setReversed(false);
- }
- aStartPoint->setValue(aTangentPntA->x(), aTangentPntA->y());
- aEndPoint->setValue(aTangentPntB->x(), aTangentPntB->y());
- aResultArc->data()->blockSendAttributeUpdated(false);
- aResultArc->execute();
-
- if(anIsNeedNewObjects) {
- // Create list of additional constraints:
- // 1. Coincidence of boundary points of features (copied lines/arcs) and fillet arc
- // 1.1. coincidence
- FeaturePtr aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
- AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- aRefAttr->setAttr(aResultArc->attribute(SketchPlugin_Arc::START_ID()));
- aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
- int aFeatInd = isReversed ? 1 : 0;
- int anAttrInd = (isReversed ? 2 : 0) + (isStart[isReversed ? 1 : 0] ? 0 : 1);
- aRefAttr->setAttr(aResultFeatures[aFeatInd]->attribute(aFeatAttributes[anAttrInd]));
- recalculateAttributes(aResultArc, SketchPlugin_Arc::START_ID(), aResultFeatures[aFeatInd], aFeatAttributes[anAttrInd]);
- aConstraint->execute();
- aFilletFeatures.resultConstraints.push_back(aConstraint);
- ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
- // 1.2. coincidence
- aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
- aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- aRefAttr->setAttr(aResultArc->attribute(SketchPlugin_Arc::END_ID()));
- aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
- aFeatInd = isReversed ? 0 : 1;
- anAttrInd = (isReversed ? 0 : 2) + (isStart[isReversed ? 0 : 1] ? 0 : 1);
- aRefAttr->setAttr(aResultFeatures[aFeatInd]->attribute(aFeatAttributes[anAttrInd]));
- recalculateAttributes(aResultArc, SketchPlugin_Arc::END_ID(), aResultFeatures[aFeatInd], aFeatAttributes[anAttrInd]);
- aConstraint->execute();
- aFilletFeatures.resultConstraints.push_back(aConstraint);
- ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
- // 2. Fillet arc radius
- //aConstraint = sketch()->addFeature(SketchPlugin_ConstraintRadius::ID());
- //aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- // aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- //aRefAttr->setObject(aNewArc->lastResult());
- //std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
- // aConstraint->attribute(SketchPlugin_Constraint::VALUE()))->setValue(aFilletRadius);
- //std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- // aConstraint->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()))->setValue(
- // isStart[0] ? aStartEndPnt[0] : aStartEndPnt[1]);
- //aConstraint->execute();
- //myProducedFeatures.push_back(aConstraint);
- //ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
- // 3. Tangency of fillet arc and features
- for (int i = 0; i < aNbFeatures; i++) {
- aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
- aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- aRefAttr->setObject(aResultArc->lastResult());
- aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
- bool isArc = aResultFeatures[i]->getKind() == SketchPlugin_Arc::ID();
- aRefAttr->setObject(isArc ? aResultFeatures[i]->lastResult() : aResultFeatures[i]->firstResult());
- aConstraint->execute();
- aFilletFeatures.resultConstraints.push_back(aConstraint);
- ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
- }
- // 4. Coincidence of free boundaries of base and copied features
- for (int i = 0; i < aNbFeatures; i++) {
- anAttrInd = 2*i + (isStart[i] ? 1 : 0);
- aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
- aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- aRefAttr->setAttr(aBaseFeatures[i]->attribute(aFeatAttributes[anAttrInd]));
- aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
- aRefAttr->setAttr(aResultFeatures[i]->attribute(aFeatAttributes[anAttrInd]));
- aFilletFeatures.resultConstraints.push_back(aConstraint);
- }
- // 4.1. Additional tangency constraints when the fillet is based on arcs.
- // It is used to verify the created arc will be placed on a source.
- for (int i = 0; i < aNbFeatures; ++i) {
- if (aResultFeatures[i]->getKind() != SketchPlugin_Arc::ID())
- continue;
- aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
- aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- aRefAttr->setObject(aBaseFeatures[i]->lastResult());
- aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
- aRefAttr->setObject(aResultFeatures[i]->lastResult());
- aConstraint->execute();
- aFilletFeatures.resultConstraints.push_back(aConstraint);
- ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
- }
- // 5. Tangent points should be placed on the base features
- for (int i = 0; i < aNbFeatures; i++) {
- anAttrInd = 2*i + (isStart[i] ? 0 : 1);
- aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
- aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- aRefAttr->setAttr(aResultFeatures[i]->attribute(aFeatAttributes[anAttrInd]));
- aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
- aRefAttr->setObject(aBaseFeatures[i]->lastResult());
- aFilletFeatures.resultConstraints.push_back(aConstraint);
- }
- // make base features auxiliary
- aBaseEdgeA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true);
- aBaseEdgeB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true);
-
- // exchange the naming IDs of newly created and old line that become auxiliary
- sketch()->exchangeIDs(aBaseEdgeA, aResultEdgeA);
- sketch()->exchangeIDs(aBaseEdgeB, aResultEdgeB);
-
- // store point and features in the map.
- myPointFeaturesMap[aPointAttr] = aFilletFeatures;
- } else {
- // Update radius value
- int aNbSubs = sketch()->numberOfSubs();
- FeaturePtr aSubFeature;
- for (int aSub = 0; aSub < aNbSubs; aSub++) {
- aSubFeature = sketch()->subFeature(aSub);
- if (aSubFeature->getKind() != SketchPlugin_ConstraintRadius::ID())
- continue;
- AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aSubFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
- if (!aRefAttr || !aRefAttr->isObject())
- continue;
- FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
- if (aFeature == aResultArc) {
- AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
- aSubFeature->attribute(SketchPlugin_Constraint::VALUE()));
- aRadius->setValue(aFilletRadius);
- break;
- }
- }