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 (selectionLabel().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) return false;
89 if (aContext->groupName() == ModelAPI_ResultBody::group()) {
90 // body: just a named shape, use selection mechanism from OCCT
91 TNaming_Selector aSelector(selectionLabel());
92 TDF_LabelMap aScope; // empty means the whole document
93 return aSelector.Solve(aScope) == Standard_True;
95 } else if (aContext->groupName() == ModelAPI_ResultConstruction::group()) {
96 // construction: identification by the results indexes, recompute faces and
97 // take the face that more close by the indexes
98 boost::shared_ptr<GeomAPI_Wire> aWirePtr = boost::dynamic_pointer_cast<GeomAPI_Wire>(
99 boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext)->shape());
100 if (aWirePtr && aWirePtr->hasPlane()) {
101 // If this is a wire with plane defined thin it is a sketch-like object
102 std::list<boost::shared_ptr<GeomAPI_Shape> > aFaces;
103 GeomAlgoAPI_SketchBuilder::createFaces(aWirePtr->origin(), aWirePtr->dirX(),
104 aWirePtr->dirY(), aWirePtr->norm(), aWirePtr, aFaces);
105 if (aFaces.empty()) // no faces, update can not work correctly
107 // if there is no edges indexes, any face can be used: take the first
108 boost::shared_ptr<Model_Data> aData =
109 boost::dynamic_pointer_cast<Model_Data>(owner()->data());
110 TDF_Label aLab = aData->label();
111 Handle(TDataStd_IntPackedMap) aSubIds;
112 boost::shared_ptr<GeomAPI_Shape> aNewSelected;
113 if (!aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), aSubIds) || aSubIds->Extent() == 0) {
114 aNewSelected = *(aFaces.begin());
115 } else { // searching for most looks-like initial face by the indexes
116 // prepare edges of the current resut for the fast searching
117 TColStd_MapOfTransient allCurves;
118 FeaturePtr aContextFeature = owner()->document()->feature(aContext);
119 CompositeFeaturePtr aComposite =
120 boost::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
121 if (!aComposite) // must be composite at least for the current implementation
123 const int aSubNum = aComposite->numberOfSubs();
124 for(int a = 0; a < aSubNum; a++) {
125 if (aSubIds->Contains(aComposite->subFeatureId(a))) {
126 FeaturePtr aSub = aComposite->subFeature(a);
127 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
128 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
129 for(; aRes != aResults.cend(); aRes++) {
130 ResultConstructionPtr aConstr =
131 boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
132 if (aConstr->shape()) {
133 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
134 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
135 if (!anEdge.IsNull()) {
136 Standard_Real aFirst, aLast;
137 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
138 allCurves.Add(aCurve);
144 // iterate new result faces and searching for these edges
145 std::list<boost::shared_ptr<GeomAPI_Shape> >::iterator aFacesIter = aFaces.begin();
146 double aBestFound = 0; // best percentage of found edges
147 for(; aFacesIter != aFaces.end(); aFacesIter++) {
148 int aFound = 0, aNotFound = 0;
149 TopExp_Explorer anEdgesExp((*aFacesIter)->impl<TopoDS_Shape>(), TopAbs_EDGE);
150 for(; anEdgesExp.More(); anEdgesExp.Next()) {
151 TopoDS_Edge anEdge = TopoDS::Edge(anEdgesExp.Current());
152 if (!anEdge.IsNull()) {
153 Standard_Real aFirst, aLast;
154 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
155 if (allCurves.Contains(aCurve)) {
162 if (aFound + aNotFound != 0) {
163 double aPercentage = double(aFound) / double(aFound + aNotFound);
164 if (aPercentage > aBestFound) {
165 aBestFound = aPercentage;
166 aNewSelected = *aFacesIter;
170 if (aNewSelected) { // store this new selection
171 selectConstruction(aContext, aNewSelected);
177 return false; // unknown case
181 void Model_AttributeSelection::selectBody(
182 const ResultPtr& theContext, const boost::shared_ptr<GeomAPI_Shape>& theSubShape)
184 // perform the selection
185 TNaming_Selector aSel(selectionLabel());
186 TopoDS_Shape aNewShape = theSubShape ? theSubShape->impl<TopoDS_Shape>() : TopoDS_Shape();
187 TopoDS_Shape aContext;
189 ResultBodyPtr aBody = boost::dynamic_pointer_cast<ModelAPI_ResultBody>(myRef.value());
191 aContext = aBody->shape()->impl<TopoDS_Shape>();
193 ResultConstructionPtr aConstr = boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(myRef.value());
195 aContext = aConstr->shape()->impl<TopoDS_Shape>();
197 throw std::invalid_argument("a result with shape is expected");
199 aSel.Select(aNewShape, aContext);
202 void Model_AttributeSelection::selectConstruction(
203 const ResultPtr& theContext, const boost::shared_ptr<GeomAPI_Shape>& theSubShape)
205 FeaturePtr aContextFeature = owner()->document()->feature(theContext);
206 CompositeFeaturePtr aComposite =
207 boost::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
208 if (!aComposite || aComposite->numberOfSubs() == 0) {
209 return; // saving of context is enough: result construction contains exactly the needed shape
211 boost::shared_ptr<Model_Data> aData = boost::dynamic_pointer_cast<Model_Data>(owner()->data());
212 TDF_Label aLab = aData->label();
213 // identify the reuslts of sub-object of the composite by edges
214 const TopoDS_Shape& aSubShape = theSubShape->impl<TopoDS_Shape>();
215 TColStd_MapOfTransient allCurves;
216 for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) {
217 TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
218 Standard_Real aFirst, aLast;
219 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
220 allCurves.Add(aCurve);
222 // iterate and store the result ids of sub-elements
223 Handle(TDataStd_IntPackedMap) aRefs = TDataStd_IntPackedMap::Set(aLab);
224 const int aSubNum = aComposite->numberOfSubs();
225 for(int a = 0; a < aSubNum; a++) {
226 FeaturePtr aSub = aComposite->subFeature(a);
227 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
228 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
229 // there may be many shapes (circle and center): register if at least one is in selection
230 for(; aRes != aResults.cend(); aRes++) {
231 ResultConstructionPtr aConstr =
232 boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
233 if (aConstr->shape()) {
234 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
235 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
236 if (!anEdge.IsNull()) {
237 Standard_Real aFirst, aLast;
238 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
239 if (allCurves.Contains(aCurve)) {
240 boost::shared_ptr<Model_Data> aSubData = boost::dynamic_pointer_cast<Model_Data>(aSub->data());
241 TDF_Label aSubLab = aSubData->label();
242 aRefs->Add(aComposite->subFeatureId(a));
248 // store the selected as primitive
249 TNaming_Builder aBuilder(selectionLabel());
250 aBuilder.Generated(aSubShape);
253 TDF_Label Model_AttributeSelection::selectionLabel()
255 return myRef.myRef->Label().FindChild(1);