1 // File: Model_AttributeSelection.h
3 // Author: Mikhail PONIKAROV
5 #include "Model_AttributeSelection.h"
6 #include "Model_Application.h"
7 #include "Model_Events.h"
8 #include "Model_Data.h"
9 #include <ModelAPI_Feature.h>
10 #include <ModelAPI_ResultBody.h>
11 #include <ModelAPI_ResultConstruction.h>
12 #include <ModelAPI_CompositeFeature.h>
13 #include <GeomAPI_Shape.h>
14 #include <GeomAPI_Wire.h>
15 #include <GeomAlgoAPI_SketchBuilder.h>
17 #include <TNaming_Selector.hxx>
18 #include <TNaming_NamedShape.hxx>
19 #include <TNaming_Tool.hxx>
20 #include <TNaming_Builder.hxx>
21 #include <TopoDS_Shape.hxx>
22 #include <TDataStd_IntPackedMap.hxx>
23 #include <TopTools_MapOfShape.hxx>
24 #include <TopExp_Explorer.hxx>
25 #include <TDF_LabelMap.hxx>
26 #include <BRep_Tool.hxx>
27 #include <TopoDS_Edge.hxx>
29 #include <TColStd_MapOfTransient.hxx>
33 void Model_AttributeSelection::setValue(const ResultPtr& theContext,
34 const boost::shared_ptr<GeomAPI_Shape>& theSubShape)
36 const boost::shared_ptr<GeomAPI_Shape>& anOldShape = value();
38 (theSubShape == anOldShape || (theSubShape && anOldShape && theSubShape->isEqual(anOldShape)));
39 if (isOldShape) return; // shape is the same, so context is also unchanged
40 // update the referenced object if needed
41 bool isOldContext = theContext == myRef.value();
43 myRef.setValue(theContext);
45 if (theContext->groupName() == ModelAPI_ResultBody::group())
46 selectBody(theContext, theSubShape);
47 else if (theContext->groupName() == ModelAPI_ResultConstruction::group())
48 selectConstruction(theContext, theSubShape);
50 myIsInitialized = true;
51 owner()->data()->sendAttributeUpdated(this);
54 boost::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::value()
56 boost::shared_ptr<GeomAPI_Shape> aResult;
57 if (myIsInitialized) {
58 Handle(TNaming_NamedShape) aSelection;
59 if (myRef.myRef->Label().FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
60 TopoDS_Shape aSelShape = aSelection->Get();
61 aResult = boost::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape);
62 aResult->setImpl(new TopoDS_Shape(aSelShape));
68 Model_AttributeSelection::Model_AttributeSelection(TDF_Label& theLabel)
71 myIsInitialized = myRef.isInitialized();
74 ResultPtr Model_AttributeSelection::context() {
75 return boost::dynamic_pointer_cast<ModelAPI_Result>(myRef.value());
79 void Model_AttributeSelection::setObject(const boost::shared_ptr<ModelAPI_Object>& theObject)
81 ModelAPI_AttributeSelection::setObject(theObject);
82 myRef.setObject(theObject);
85 bool Model_AttributeSelection::update()
87 ResultPtr aContext = context();
88 if (aContext->groupName() == ModelAPI_ResultBody::group()) {
89 // body: just a named shape, use selection mechanism from OCCT
90 TNaming_Selector aSelector(myRef.myRef->Label());
91 TDF_LabelMap aScope; // empty means the whole document
92 return aSelector.Solve(aScope) == Standard_True;
94 } else if (aContext->groupName() == ModelAPI_ResultConstruction::group()) {
95 // construction: identification by the results indexes, recompute faces and
96 // take the face that more close by the indexes
97 boost::shared_ptr<GeomAPI_Wire> aWirePtr = boost::dynamic_pointer_cast<GeomAPI_Wire>(
98 boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext)->shape());
99 if (aWirePtr && aWirePtr->hasPlane()) {
100 // If this is a wire with plane defined thin it is a sketch-like object
101 std::list<boost::shared_ptr<GeomAPI_Shape> > aFaces;
102 GeomAlgoAPI_SketchBuilder::createFaces(aWirePtr->origin(), aWirePtr->dirX(),
103 aWirePtr->dirY(), aWirePtr->norm(), aWirePtr, aFaces);
104 if (aFaces.empty()) // no faces, update can not work correctly
106 // if there is no edges indexes, any face can be used: take the first
107 boost::shared_ptr<Model_Data> aData =
108 boost::dynamic_pointer_cast<Model_Data>(owner()->data());
109 TDF_Label aLab = aData->label();
110 Handle(TDataStd_IntPackedMap) aSubIds;
111 boost::shared_ptr<GeomAPI_Shape> aNewSelected;
112 if (!aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), aSubIds) || aSubIds->Extent() == 0) {
113 aNewSelected = *(aFaces.begin());
114 } else { // searching for most looks-like initial face by the indexes
115 // prepare edges of the current resut for the fast searching
116 TColStd_MapOfTransient allCurves;
117 FeaturePtr aContextFeature = owner()->document()->feature(aContext);
118 CompositeFeaturePtr aComposite =
119 boost::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
120 if (!aComposite) // must be composite at least for the current implementation
122 const int aSubNum = aComposite->numberOfSubs();
123 for(int a = 0; a < aSubNum; a++) {
124 if (aSubIds->Contains(aComposite->subFeatureId(a))) {
125 FeaturePtr aSub = aComposite->subFeature(a);
126 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
127 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
128 for(; aRes != aResults.cend(); aRes++) {
129 ResultConstructionPtr aConstr =
130 boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
131 if (aConstr->shape()) {
132 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
133 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
134 if (!anEdge.IsNull()) {
135 Standard_Real aFirst, aLast;
136 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
137 allCurves.Add(aCurve);
143 // iterate new result faces and searching for these edges
144 std::list<boost::shared_ptr<GeomAPI_Shape> >::iterator aFacesIter = aFaces.begin();
145 double aBestFound = 0; // best percentage of found edges
146 for(; aFacesIter != aFaces.end(); aFacesIter++) {
147 int aFound = 0, aNotFound = 0;
148 TopExp_Explorer anEdgesExp((*aFacesIter)->impl<TopoDS_Shape>(), TopAbs_EDGE);
149 for(; anEdgesExp.More(); anEdgesExp.Next()) {
150 TopoDS_Edge anEdge = TopoDS::Edge(anEdgesExp.Current());
151 if (!anEdge.IsNull()) {
152 Standard_Real aFirst, aLast;
153 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
154 if (allCurves.Contains(aCurve)) {
161 if (aFound + aNotFound != 0) {
162 double aPercentage = double(aFound) / double(aFound + aNotFound);
163 if (aPercentage > aBestFound) {
164 aBestFound = aPercentage;
165 aNewSelected = *aFacesIter;
169 if (aNewSelected) { // store this new selection
170 selectConstruction(aContext, aNewSelected);
176 return false; // unknown case
180 void Model_AttributeSelection::selectBody(
181 const ResultPtr& theContext, const boost::shared_ptr<GeomAPI_Shape>& theSubShape)
183 // perform the selection
184 TNaming_Selector aSel(myRef.myRef->Label());
185 TopoDS_Shape aNewShape = theSubShape ? theSubShape->impl<TopoDS_Shape>() : TopoDS_Shape();
186 TopoDS_Shape aContext;
188 ResultBodyPtr aBody = boost::dynamic_pointer_cast<ModelAPI_ResultBody>(myRef.value());
190 aContext = aBody->shape()->impl<TopoDS_Shape>();
192 ResultConstructionPtr aConstr = boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(myRef.value());
194 aContext = aConstr->shape()->impl<TopoDS_Shape>();
196 throw std::invalid_argument("a result with shape is expected");
198 Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aNewShape, myRef.myRef->Label());
199 TDF_Label aLab = aNS->Label();
201 aSel.Select(aNewShape, aContext);
204 void Model_AttributeSelection::selectConstruction(
205 const ResultPtr& theContext, const boost::shared_ptr<GeomAPI_Shape>& theSubShape)
207 FeaturePtr aContextFeature = owner()->document()->feature(theContext);
208 CompositeFeaturePtr aComposite =
209 boost::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
210 if (!aComposite || aComposite->numberOfSubs() == 0) {
211 return; // saving of context is enough: result construction contains exactly the needed shape
213 boost::shared_ptr<Model_Data> aData = boost::dynamic_pointer_cast<Model_Data>(owner()->data());
214 TDF_Label aLab = aData->label();
215 // identify the reuslts of sub-object of the composite by edges
216 const TopoDS_Shape& aSubShape = theSubShape->impl<TopoDS_Shape>();
217 TColStd_MapOfTransient allCurves;
218 for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) {
219 TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
220 Standard_Real aFirst, aLast;
221 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
222 allCurves.Add(aCurve);
224 // iterate and store the result ids of sub-elements
225 Handle(TDataStd_IntPackedMap) aRefs = TDataStd_IntPackedMap::Set(aLab);
226 const int aSubNum = aComposite->numberOfSubs();
227 for(int a = 0; a < aSubNum; a++) {
228 FeaturePtr aSub = aComposite->subFeature(a);
229 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
230 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
231 // there may be many shapes (circle and center): register if at least one is in selection
232 for(; aRes != aResults.cend(); aRes++) {
233 ResultConstructionPtr aConstr =
234 boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
235 if (aConstr->shape()) {
236 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
237 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
238 if (!anEdge.IsNull()) {
239 Standard_Real aFirst, aLast;
240 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
241 if (allCurves.Contains(aCurve)) {
242 boost::shared_ptr<Model_Data> aSubData = boost::dynamic_pointer_cast<Model_Data>(aSub->data());
243 TDF_Label aSubLab = aSubData->label();
244 aRefs->Add(aComposite->subFeatureId(a));
250 // store the selected as primitive
251 TNaming_Builder aBuilder(myRef.myRef->Label());
252 aBuilder.Generated(aSubShape);