Salome HOME
refs #570: Land Cover: the partition algorithm (further implementation)
[modules/hydro.git] / src / HYDROData / HYDROData_PriorityQueue.cxx
1 // Copyright (C) 2014-2015  EDF-R&D
2 // This library is free software; you can redistribute it and/or
3 // modify it under the terms of the GNU Lesser General Public
4 // License as published by the Free Software Foundation; either
5 // version 2.1 of the License, or (at your option) any later version.
6 //
7 // This library is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10 // Lesser General Public License for more details.
11 //
12 // You should have received a copy of the GNU Lesser General Public
13 // License along with this library; if not, write to the Free Software
14 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
15 //
16 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
17 //
18
19 #include <HYDROData_PriorityQueue.h>
20 #include <HYDROData_CalculationCase.h>
21 #include <HYDROData_Iterator.h>
22 #include <HYDROData_LandCover.h>
23 #include <TDataStd_ReferenceList.hxx>
24 #include <TDataStd_Integer.hxx>
25 #include <TDF_ChildIterator.hxx>
26
27 HYDROData_PriorityQueue::HYDROData_PriorityQueue( HYDROData_CalculationCase* theCalcCase,
28                                                   Standard_Integer aTag )
29 {
30   myGeomObjects = theCalcCase->GetGeometryObjects();
31   for( int i=myGeomObjects.Lower(), n=myGeomObjects.Upper(); i<=n; i++ )
32   {
33     Handle(HYDROData_Entity) anObj = myGeomObjects.Value( i );
34     if( !anObj.IsNull() )
35     {
36       QString anObjName = anObj->GetName();
37       myNames[anObjName] = anObj;
38     }
39   }
40
41   myRules = GetRules( theCalcCase->Label().FindChild( aTag ) );
42 }
43
44 HYDROData_PriorityQueue::~HYDROData_PriorityQueue()
45 {
46 }
47
48 Handle(HYDROData_Entity) HYDROData_PriorityQueue::GetMostPriorityObject( const QStringList& theZoneObjects,
49                                                                          HYDROData_Zone::MergeType& theMergeType ) const
50 {
51   QStringList aSortedZoneObjects;
52   for( int i=myGeomObjects.Lower(), n=myGeomObjects.Upper(); i<=n; i++ )
53   {
54     QString aName = myGeomObjects.Value( i )->GetName();
55     if( theZoneObjects.contains( aName ) )
56       aSortedZoneObjects.append( aName );
57   }
58
59   Handle(HYDROData_Entity) aMostPriorityObj;
60   theMergeType = HYDROData_Zone::Merge_UNKNOWN;
61   QStringList::const_iterator anIt = aSortedZoneObjects.begin(), aLast = aSortedZoneObjects.end();
62   for( ; anIt!=aLast; anIt++ )
63   {
64     HYDROData_Zone::MergeType aLocalMerge = HYDROData_Zone::Merge_UNKNOWN;
65     Handle(HYDROData_Entity) anObj = myNames[*anIt];
66     if( !anObj.IsNull() )
67     {
68       if( aMostPriorityObj.IsNull() )
69       {
70         aMostPriorityObj = anObj;
71         continue;
72       }
73
74       bool isMorePriority = IsMorePriority( anObj, aMostPriorityObj, aLocalMerge );
75
76       if( isMorePriority )
77         aMostPriorityObj = anObj;
78
79       if( aLocalMerge != HYDROData_Zone::Merge_UNKNOWN && 
80           ( theMergeType==HYDROData_Zone::Merge_UNKNOWN || isMorePriority ) )
81         theMergeType = aLocalMerge;
82     }
83   }
84   return aMostPriorityObj;
85 }
86
87 bool HYDROData_PriorityQueue::IsMorePriority( const Handle(HYDROData_Entity)& theObj1,
88                                               const Handle(HYDROData_Entity)& theObj2,
89                                               HYDROData_Zone::MergeType& theMergeType ) const
90 {
91   // 1. First we check custom rules
92   HYDROData_ListOfRules::const_iterator anIt = myRules.begin(), aLast = myRules.end();
93   for( ; anIt!=aLast; anIt++ )
94   {
95     if( anIt->Object1->Label()==theObj1->Label() && anIt->Object2->Label()==theObj2->Label() )
96     {
97       theMergeType = anIt->MergeType;
98       return anIt->Priority==GREATER;
99     }
100     if( anIt->Object1->Label()==theObj2->Label() && anIt->Object2->Label()==theObj1->Label() )
101     {
102       theMergeType = anIt->MergeType;
103       return anIt->Priority==LESS;
104     }
105   }
106
107   // 2. If no custom rule found, the standard ordering list is applied
108   for( int i=myGeomObjects.Lower(), n=myGeomObjects.Upper(); i<=n; i++ )
109   {
110     if( myGeomObjects.Value( i )->Label() == theObj1->Label() )
111     {
112       theMergeType = HYDROData_Zone::Merge_Object;
113       return true;
114     }
115     if( myGeomObjects.Value( i )->Label() == theObj2->Label() )
116     {
117       theMergeType = HYDROData_Zone::Merge_Object;
118       return false;
119     }
120   }
121   return false;
122 }
123
124 void HYDROData_PriorityQueue::ClearRules( TDF_Label& theRulesLabel )
125 {
126   theRulesLabel.ForgetAllAttributes( true );
127 }
128
129 enum HYDROData_PriorityQueueTag
130 {
131   Object1_Tag,
132   Priority_Tag,
133   Object2_Tag,
134   Merge_Tag,
135 };
136
137 void HYDROData_PriorityQueue::AddRule( TDF_Label&                      theRulesLabel,
138                                        const Handle(HYDROData_Entity)& theObject1,
139                                        HYDROData_PriorityType          thePriority,
140                                        const Handle(HYDROData_Entity)& theObject2,
141                                        HYDROData_Zone::MergeType       theMergeType )
142 {
143   // Get the last rule index
144   Standard_Integer aRuleIndex = 0;
145   Handle(TDataStd_Integer) anIntVal;
146   if ( theRulesLabel.FindAttribute( TDataStd_Integer::GetID(), anIntVal ) ) {
147     aRuleIndex = anIntVal->Get();
148   }
149
150   TDF_Label aNewRuleLab = theRulesLabel.FindChild( aRuleIndex );
151
152   TDF_Label anObj1Lab = aNewRuleLab.FindChild( Object1_Tag );
153   Handle(TDataStd_ReferenceList) aRefs = TDataStd_ReferenceList::Set( anObj1Lab );
154   aRefs->Append( theObject1->Label() );
155   
156   TDF_Label aPriorityLab = aNewRuleLab.FindChild( Priority_Tag );
157   TDataStd_Integer::Set( aPriorityLab, thePriority );
158
159   TDF_Label anObj2Lab = aNewRuleLab.FindChild( Object2_Tag );
160   aRefs = TDataStd_ReferenceList::Set( anObj2Lab );
161   aRefs->Append( theObject2->Label() );
162
163   TDF_Label aMergeLab = aNewRuleLab.FindChild( Merge_Tag );
164   TDataStd_Integer::Set( aMergeLab, theMergeType );
165
166   // Increment the last rule index
167   TDataStd_Integer::Set( theRulesLabel, aRuleIndex + 1 );
168 }
169
170 HYDROData_ListOfRules HYDROData_PriorityQueue::GetRules( const TDF_Label& theRulesLabel )
171 {
172   HYDROData_ListOfRules aRules;
173
174   Handle(TDataStd_ReferenceList) aRefs1, aRefs2;
175   Handle(TDataStd_Integer) aPriorityAttr, aMergeAttr;
176
177   TDF_ChildIterator anIt( theRulesLabel );
178   for( ; anIt.More(); anIt.Next() )
179   {
180     TDF_Label aRuleLabel = anIt.Value();
181
182     bool isObj1OK = aRuleLabel.FindChild    ( Object1_Tag ). FindAttribute( TDataStd_ReferenceList::GetID(), aRefs1 );
183     bool isPriorityOK = aRuleLabel.FindChild( Priority_Tag ).FindAttribute( TDataStd_Integer::GetID(),       aPriorityAttr );
184     bool isObj2OK = aRuleLabel.FindChild    ( Object2_Tag ). FindAttribute( TDataStd_ReferenceList::GetID(), aRefs2 );
185     bool isMergeOK = aRuleLabel.FindChild   ( Merge_Tag ).   FindAttribute( TDataStd_Integer::GetID(),       aMergeAttr );
186
187     if( isObj1OK && isPriorityOK && isObj2OK && isMergeOK )
188     {
189       HYDROData_CustomRule aRule;
190       aRule.Object1 = HYDROData_Iterator::Object( aRefs1->First() );
191       aRule.Priority = ( HYDROData_PriorityType ) aPriorityAttr->Get();
192       aRule.Object2 = HYDROData_Iterator::Object( aRefs2->First() );
193       aRule.MergeType = ( HYDROData_Zone::MergeType ) aMergeAttr->Get();
194       aRules.append( aRule );
195     }
196   }
197
198   return aRules;
199 }
200
201 QString HYDROData_PriorityQueue::DumpRules( const TDF_Label& theRulesLab )
202 {
203   QString aDump = "Rules:\n";
204   HYDROData_ListOfRules aRules = GetRules( theRulesLab );
205   HYDROData_ListOfRules::const_iterator anIt = aRules.begin(), aLast = aRules.end();
206   for( ; anIt!=aLast; anIt++ )
207   {
208     QString aRule = anIt->Object1->GetName() + " ";
209     aRule += ( anIt->Priority == LESS ? "<" : ">" ) + QString( " " );
210     aRule += anIt->Object2->GetName() + " ";
211
212     switch( anIt->MergeType )
213     {
214     case HYDROData_Zone::Merge_UNKNOWN:
215       aRule += "unknown";
216       break;
217     case HYDROData_Zone::Merge_ZMIN:
218       aRule += "zmin";
219       break;
220     case HYDROData_Zone::Merge_ZMAX:
221       aRule += "zmax";
222       break;
223     case HYDROData_Zone::Merge_Object:
224       aRule += "object";
225       break;
226     }
227     aDump += aRule + "\n";
228   }
229   return aDump;
230 }
231
232 void HYDROData_PriorityQueue::DumpRulesToPython( const TDF_Label& theRulesLab,
233                                                  const QString& theCalcCaseName,
234                                                  QStringList& theScript )
235 {
236   HYDROData_ListOfRules aRules = GetRules( theRulesLab );
237   HYDROData_ListOfRules::const_iterator anIt = aRules.begin(), aLast = aRules.end();
238   for( ; anIt!=aLast; anIt++ )
239   {
240     QString anObj1 = anIt->Object1->GetObjPyName();
241     QString anObj2 = anIt->Object2->GetObjPyName();
242     QString aPriority = anIt->Priority == LESS ? "LESS" : "GREATER";
243     QString aMergeType;
244
245     HYDROData_CalculationCase::DataTag aDataTag = HYDROData_CalculationCase::DataTag_CustomRules;
246     Handle(HYDROData_LandCover) aLandCover1 = Handle(HYDROData_LandCover)::DownCast( anIt->Object1 );
247     Handle(HYDROData_LandCover) aLandCover2 = Handle(HYDROData_LandCover)::DownCast( anIt->Object2 );
248     if ( !aLandCover1.IsNull() && !aLandCover2.IsNull() )
249       aDataTag = HYDROData_CalculationCase::DataTag_CustomLandCoverRules;
250
251     switch( anIt->MergeType )
252     {
253     case HYDROData_Zone::Merge_UNKNOWN:
254       aMergeType = "HYDROData_Zone.Merge_UNKNOWN";
255       break;
256     case HYDROData_Zone::Merge_ZMIN:
257       aMergeType = "HYDROData_Zone.Merge_ZMIN";
258       break;
259     case HYDROData_Zone::Merge_ZMAX:
260       aMergeType = "HYDROData_Zone.Merge_ZMAX";
261       break;
262     case HYDROData_Zone::Merge_Object:
263       aMergeType = "HYDROData_Zone.Merge_Object";
264       break;
265     }
266
267     QString aRule = QString( "%0.AddRule( %1, %2, %3, %4, %5 )" ).
268       arg( theCalcCaseName ).arg( anObj1 ).arg( aPriority ).arg( anObj2 ).arg( aMergeType ).arg( aDataTag );
269
270     theScript << aRule;
271   }
272 }
273
274 bool HYDROData_PriorityQueue::GetRule( const TDF_Label& theRulesLab,
275                                        int theIndex, 
276                                        Handle(HYDROData_Entity)&  theObject1,
277                                        HYDROData_PriorityType&    thePriority,
278                                        Handle(HYDROData_Entity)&  theObject2,
279                                        HYDROData_Zone::MergeType& theMergeType )
280 {
281   TDF_Label aRuleLabel = theRulesLab.FindChild( theIndex );
282
283   Handle(TDataStd_ReferenceList) aRefs1, aRefs2;
284   Handle(TDataStd_Integer) aPriorityAttr, aMergeAttr;
285
286   bool isObj1OK = aRuleLabel.FindChild    ( Object1_Tag ). FindAttribute( TDataStd_ReferenceList::GetID(), aRefs1 );
287   bool isPriorityOK = aRuleLabel.FindChild( Priority_Tag ).FindAttribute( TDataStd_Integer::GetID(),       aPriorityAttr );
288   bool isObj2OK = aRuleLabel.FindChild    ( Object2_Tag ). FindAttribute( TDataStd_ReferenceList::GetID(), aRefs2 );
289   bool isMergeOK = aRuleLabel.FindChild   ( Merge_Tag ).   FindAttribute( TDataStd_Integer::GetID(),       aMergeAttr );
290
291   bool isOK = isObj1OK && isPriorityOK && isObj2OK && isMergeOK;
292   if( isOK )
293   {
294     theObject1   = HYDROData_Iterator::Object( aRefs1->First() );
295     thePriority  = ( HYDROData_PriorityType ) aPriorityAttr->Get();
296     theObject2   = HYDROData_Iterator::Object( aRefs2->First() );
297     theMergeType = ( HYDROData_Zone::MergeType ) aMergeAttr->Get();
298   }
299   return isOK;
300 }