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>
16 #include <Events_Error.h>
18 #include <TNaming_Selector.hxx>
19 #include <TNaming_NamedShape.hxx>
20 #include <TNaming_Tool.hxx>
21 #include <TNaming_Builder.hxx>
22 #include <TopoDS_Shape.hxx>
23 #include <TDataStd_IntPackedMap.hxx>
24 #include <TopTools_MapOfShape.hxx>
25 #include <TopExp_Explorer.hxx>
26 #include <TDF_LabelMap.hxx>
27 #include <BRep_Tool.hxx>
28 #include <TopoDS_Edge.hxx>
30 #include <TColStd_MapOfTransient.hxx>
34 void Model_AttributeSelection::setValue(const ResultPtr& theContext,
35 const boost::shared_ptr<GeomAPI_Shape>& theSubShape)
37 const boost::shared_ptr<GeomAPI_Shape>& anOldShape = value();
39 (theSubShape == anOldShape || (theSubShape && anOldShape && theSubShape->isEqual(anOldShape)));
40 if (isOldShape) return; // shape is the same, so context is also unchanged
41 // update the referenced object if needed
42 bool isOldContext = theContext == myRef.value();
44 myRef.setValue(theContext);
46 if (theContext->groupName() == ModelAPI_ResultBody::group())
47 selectBody(theContext, theSubShape);
48 else if (theContext->groupName() == ModelAPI_ResultConstruction::group())
49 selectConstruction(theContext, theSubShape);
51 myIsInitialized = true;
52 owner()->data()->sendAttributeUpdated(this);
55 boost::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::value()
57 boost::shared_ptr<GeomAPI_Shape> aResult;
58 if (myIsInitialized) {
59 Handle(TNaming_NamedShape) aSelection;
60 if (selectionLabel().FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
61 TopoDS_Shape aSelShape = aSelection->Get();
62 aResult = boost::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape);
63 aResult->setImpl(new TopoDS_Shape(aSelShape));
69 Model_AttributeSelection::Model_AttributeSelection(TDF_Label& theLabel)
72 myIsInitialized = myRef.isInitialized();
75 ResultPtr Model_AttributeSelection::context() {
76 return boost::dynamic_pointer_cast<ModelAPI_Result>(myRef.value());
80 void Model_AttributeSelection::setObject(const boost::shared_ptr<ModelAPI_Object>& theObject)
82 ModelAPI_AttributeSelection::setObject(theObject);
83 myRef.setObject(theObject);
86 bool Model_AttributeSelection::update()
88 ResultPtr aContext = context();
89 if (!aContext) return false;
90 if (aContext->groupName() == ModelAPI_ResultBody::group()) {
91 // body: just a named shape, use selection mechanism from OCCT
92 TNaming_Selector aSelector(selectionLabel());
93 TDF_LabelMap aScope; // empty means the whole document
94 return aSelector.Solve(aScope) == Standard_True;
96 } else if (aContext->groupName() == ModelAPI_ResultConstruction::group()) {
97 // construction: identification by the results indexes, recompute faces and
98 // take the face that more close by the indexes
99 boost::shared_ptr<GeomAPI_Wire> aWirePtr = boost::dynamic_pointer_cast<GeomAPI_Wire>(
100 boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext)->shape());
101 if (aWirePtr && aWirePtr->hasPlane()) {
102 // If this is a wire with plane defined thin it is a sketch-like object
103 std::list<boost::shared_ptr<GeomAPI_Shape> > aFaces;
104 GeomAlgoAPI_SketchBuilder::createFaces(aWirePtr->origin(), aWirePtr->dirX(),
105 aWirePtr->dirY(), aWirePtr->norm(), aWirePtr, aFaces);
106 if (aFaces.empty()) // no faces, update can not work correctly
108 // if there is no edges indexes, any face can be used: take the first
109 boost::shared_ptr<Model_Data> aData =
110 boost::dynamic_pointer_cast<Model_Data>(owner()->data());
111 TDF_Label aLab = aData->label();
112 Handle(TDataStd_IntPackedMap) aSubIds;
113 boost::shared_ptr<GeomAPI_Shape> aNewSelected;
114 if (!aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), aSubIds) || aSubIds->Extent() == 0) {
115 aNewSelected = *(aFaces.begin());
116 } else { // searching for most looks-like initial face by the indexes
117 // prepare edges of the current resut for the fast searching
118 TColStd_MapOfTransient allCurves;
119 FeaturePtr aContextFeature = owner()->document()->feature(aContext);
120 CompositeFeaturePtr aComposite =
121 boost::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
122 if (!aComposite) // must be composite at least for the current implementation
124 const int aSubNum = aComposite->numberOfSubs();
125 for(int a = 0; a < aSubNum; a++) {
126 if (aSubIds->Contains(aComposite->subFeatureId(a))) {
127 FeaturePtr aSub = aComposite->subFeature(a);
128 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
129 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
130 for(; aRes != aResults.cend(); aRes++) {
131 ResultConstructionPtr aConstr =
132 boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
133 if (aConstr->shape() && aConstr->shape()->isEdge()) {
134 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
135 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
136 if (!anEdge.IsNull()) {
137 Standard_Real aFirst, aLast;
138 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
139 allCurves.Add(aCurve);
145 // iterate new result faces and searching for these edges
146 std::list<boost::shared_ptr<GeomAPI_Shape> >::iterator aFacesIter = aFaces.begin();
147 double aBestFound = 0; // best percentage of found edges
148 for(; aFacesIter != aFaces.end(); aFacesIter++) {
149 int aFound = 0, aNotFound = 0;
150 TopExp_Explorer anEdgesExp((*aFacesIter)->impl<TopoDS_Shape>(), TopAbs_EDGE);
151 for(; anEdgesExp.More(); anEdgesExp.Next()) {
152 TopoDS_Edge anEdge = TopoDS::Edge(anEdgesExp.Current());
153 if (!anEdge.IsNull()) {
154 Standard_Real aFirst, aLast;
155 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
156 if (allCurves.Contains(aCurve)) {
163 if (aFound + aNotFound != 0) {
164 double aPercentage = double(aFound) / double(aFound + aNotFound);
165 if (aPercentage > aBestFound) {
166 aBestFound = aPercentage;
167 aNewSelected = *aFacesIter;
171 if (aNewSelected) { // store this new selection
172 selectConstruction(aContext, aNewSelected);
178 return false; // unknown case
182 void Model_AttributeSelection::selectBody(
183 const ResultPtr& theContext, const boost::shared_ptr<GeomAPI_Shape>& theSubShape)
185 // perform the selection
186 TNaming_Selector aSel(selectionLabel());
187 TopoDS_Shape aNewShape = theSubShape ? theSubShape->impl<TopoDS_Shape>() : TopoDS_Shape();
188 TopoDS_Shape aContext;
190 ResultBodyPtr aBody = boost::dynamic_pointer_cast<ModelAPI_ResultBody>(myRef.value());
192 aContext = aBody->shape()->impl<TopoDS_Shape>();
194 ResultConstructionPtr aConstr = boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(myRef.value());
196 aContext = aConstr->shape()->impl<TopoDS_Shape>();
198 Events_Error::send("A result with shape is expected");
202 aSel.Select(aNewShape, aContext);
205 void Model_AttributeSelection::selectConstruction(
206 const ResultPtr& theContext, const boost::shared_ptr<GeomAPI_Shape>& theSubShape)
208 FeaturePtr aContextFeature = owner()->document()->feature(theContext);
209 CompositeFeaturePtr aComposite =
210 boost::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
211 if (!aComposite || aComposite->numberOfSubs() == 0) {
212 return; // saving of context is enough: result construction contains exactly the needed shape
214 boost::shared_ptr<Model_Data> aData = boost::dynamic_pointer_cast<Model_Data>(owner()->data());
215 TDF_Label aLab = aData->label();
216 // identify the reuslts of sub-object of the composite by edges
217 const TopoDS_Shape& aSubShape = theSubShape->impl<TopoDS_Shape>();
218 TColStd_MapOfTransient allCurves;
219 for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) {
220 TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
221 Standard_Real aFirst, aLast;
222 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
223 allCurves.Add(aCurve);
225 // iterate and store the result ids of sub-elements
226 Handle(TDataStd_IntPackedMap) aRefs = TDataStd_IntPackedMap::Set(aLab);
227 const int aSubNum = aComposite->numberOfSubs();
228 for(int a = 0; a < aSubNum; a++) {
229 FeaturePtr aSub = aComposite->subFeature(a);
230 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
231 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
232 // there may be many shapes (circle and center): register if at least one is in selection
233 for(; aRes != aResults.cend(); aRes++) {
234 ResultConstructionPtr aConstr =
235 boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
236 if (aConstr->shape() && aConstr->shape()->isEdge()) {
237 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
238 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
239 if (!anEdge.IsNull()) {
240 Standard_Real aFirst, aLast;
241 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
242 if (allCurves.Contains(aCurve)) {
243 boost::shared_ptr<Model_Data> aSubData = boost::dynamic_pointer_cast<Model_Data>(aSub->data());
244 TDF_Label aSubLab = aSubData->label();
245 aRefs->Add(aComposite->subFeatureId(a));
251 // store the selected as primitive
252 TNaming_Builder aBuilder(selectionLabel());
253 aBuilder.Generated(aSubShape);
256 TDF_Label Model_AttributeSelection::selectionLabel()
258 return myRef.myRef->Label().FindChild(1);