db5bd5b0e25613da07f4861c2bf5a8a89cd3baf2
[occt.git] / src / TopLoc / TopLoc_Location.cxx
1 // Created on: 1991-01-21
2 // Created by: Christophe MARION
3 // Copyright (c) 1991-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #define No_Standard_NoSuchObject
18
19 #include <TopLoc_Location.ixx>
20 #include <Standard_NoSuchObject.hxx>
21 #include <TopLoc_Datum3D.hxx>
22 #include <TopLoc_SListOfItemLocation.hxx>
23 #include <TopLoc_ItemLocation.hxx>
24 #include <gp_Trsf.hxx>
25 #include <TopLoc_TrsfPtr.hxx>
26
27 static const gp_Trsf TheIdentity;
28
29
30 static Standard_Boolean IsInternalIdentity(const TopLoc_Location& loc)
31 {
32   if (loc.IsIdentity()) {
33     return Standard_True;
34   }
35 //  if (loc.FirstDatum()->Transformation().Form() == gp_Identity) {
36 //    return Standard_True;
37 //  }
38   return Standard_False;
39 }
40
41 //=======================================================================
42 //function : TopLoc_Location
43 //purpose  : constructor Identity
44 //=======================================================================
45
46 TopLoc_Location::TopLoc_Location () 
47 {
48 }
49 //=======================================================================
50 //function : TopLoc_Location
51 //purpose  : constructor Datum
52 //=======================================================================
53
54 TopLoc_Location::TopLoc_Location (const Handle(TopLoc_Datum3D)& D)
55 {
56   myItems.Construct(TopLoc_ItemLocation(D,1));
57 }
58
59 //=======================================================================
60 //function : TopLoc_Location
61 //purpose  : 
62 //=======================================================================
63
64 TopLoc_Location::TopLoc_Location(const gp_Trsf& T)
65 {
66   Handle(TopLoc_Datum3D) D = new TopLoc_Datum3D(T);
67   myItems.Construct(TopLoc_ItemLocation(D,1));
68 }
69
70 //=======================================================================
71 //function : Transformation
72 //purpose  : 
73 //=======================================================================
74
75 const gp_Trsf& TopLoc_Location::Transformation() const
76 {
77   if (IsInternalIdentity(*this))
78     return TheIdentity;
79   else {
80     if (myItems.Value().myTrsf == NULL) {
81       TopLoc_ItemLocation *I = (TopLoc_ItemLocation*) (void*) &this->myItems.Value();
82       // CLE
83       if (I->myTrsf == NULL) I->myTrsf = new gp_Trsf;
84       *(I->myTrsf) = I->myDatum->Transformation();
85       I->myTrsf->Power(I->myPower);
86       I->myTrsf->PreMultiply(NextLocation().Transformation());
87     }
88     return *(myItems.Value().myTrsf);
89   }
90 }
91
92 TopLoc_Location::operator gp_Trsf() const
93 {
94   return Transformation();
95 }
96
97 //=======================================================================
98 //function : Inverted
99 //purpose  : return the inverse
100 //=======================================================================
101
102 TopLoc_Location TopLoc_Location::Inverted () const
103 {
104   //
105   // the inverse of a Location is a chain in revert order
106   // with opposite powers and same Local
107   //
108   TopLoc_Location result;
109   TopLoc_SListOfItemLocation items = myItems;
110   while (items.More()) {
111     result.myItems.Construct(TopLoc_ItemLocation(items.Value().myDatum,
112                                                  -items.Value().myPower));
113     items.Next();
114   }
115   return result;
116 }
117
118 //=======================================================================
119 //function : Multiplied
120 //purpose  : operator *
121 //=======================================================================
122
123 TopLoc_Location TopLoc_Location::Multiplied(const TopLoc_Location& Other) const
124 {
125   // prepend the chain Other in front of this
126   // cancelling null exponents
127   
128   if (IsIdentity()) return Other;
129   if (Other.IsIdentity()) return *this;
130   
131   // prepend the queue of Other
132   TopLoc_Location result = Multiplied(Other.NextLocation());
133   // does the head of Other cancel the head of result
134
135   Standard_Integer p = Other.FirstPower();
136   if (!result.IsIdentity()) {
137     if (Other.FirstDatum() == result.FirstDatum()) {
138       p += result.FirstPower();
139       result.myItems.ToTail();
140     }
141   }
142   if (p != 0)
143     result.myItems.Construct(TopLoc_ItemLocation(Other.FirstDatum(),p));
144   return result;
145 }
146
147 //=======================================================================
148 //function : Divided
149 //purpose  : operator /   this*Other.Inverted()
150 //=======================================================================
151
152 TopLoc_Location TopLoc_Location::Divided (const TopLoc_Location& Other) const
153 {
154   return Multiplied(Other.Inverted());
155 }
156
157 //=======================================================================
158 //function : Predivided
159 //purpose  : return Other.Inverted() * this
160 //=======================================================================
161
162 TopLoc_Location TopLoc_Location::Predivided (const TopLoc_Location& Other) 
163      const
164 {
165   return Other.Inverted().Multiplied(*this);
166 }
167
168 //=======================================================================
169 //function : Powered
170 //purpose  : power elevation
171 //=======================================================================
172
173 TopLoc_Location TopLoc_Location::Powered (const Standard_Integer pwr) const
174 {
175   if (IsInternalIdentity(*this)) return *this;
176   if (pwr == 1) return *this;
177   if (pwr == 0) return TopLoc_Location();
178   
179   // optimisation when just one element
180   if (myItems.Tail().IsEmpty()) {
181     TopLoc_Location result;
182     result.myItems.Construct(TopLoc_ItemLocation(FirstDatum(),
183                                                  FirstPower() * pwr));
184     return result;
185   }
186
187   if (pwr > 0) return Multiplied(Powered(pwr - 1));
188   else         return Inverted().Powered(-pwr);
189 }
190
191 //=======================================================================
192 //function : HashCode
193 //purpose  : 
194 //=======================================================================
195
196 Standard_Integer TopLoc_Location::HashCode(const Standard_Integer upper) const
197 {
198   // the HashCode computed for a Location is the bitwise exclusive or
199   // of values computed for each element of the list
200   // to compute this value, the depth of the element is computed 
201   // the depth is the position of the element in the list
202   // this depth is multiplied by 3
203   // each element is an elementary Datum raised to a Power
204   // the Power is bitwise left shifted by depth
205   // this is added to the HashCode of the Datum
206   // this value is biwise rotated by depth
207   // the use of depth avoids getting the same result for two permutated lists.
208
209   Standard_Integer depth = 0;
210   unsigned int h = 0;
211   TopLoc_SListOfItemLocation items = myItems;
212   while (items.More()) {
213     depth += 3;
214     unsigned int i = ::HashCode (items.Value().myDatum, upper);
215     unsigned int j = ( (i + items.Value().myPower) <<depth);
216     j = j>>(32-depth) | j<<depth;
217     h ^= j;
218     items.Next();
219   }
220   return h % upper;
221 }
222
223 //=======================================================================
224 //function : IsEqual
225 //purpose  : operator ==
226 //=======================================================================
227
228 // two locations are Equal if the Items have the same LocalValues and Powers
229 // this is a recursive function to test it
230
231 Standard_Boolean TopLoc_Location::IsEqual (const TopLoc_Location& Other) const
232 {
233   const void** p = (const void**) &myItems;
234   const void** q = (const void**) &Other.myItems;
235   if (*p            == *q                  ) {return Standard_True ; }
236   if (IsIdentity()  || Other.IsIdentity()  ) {return Standard_False; }
237   if (FirstDatum()  != Other.FirstDatum()  ) {return Standard_False; }
238   if (FirstPower()  != Other.FirstPower()  ) {return Standard_False; }
239   else { return NextLocation() == Other.NextLocation();}
240 }
241
242 //=======================================================================
243 //function : IsDifferent
244 //purpose  : 
245 //=======================================================================
246
247 Standard_Boolean TopLoc_Location::IsDifferent
248   (const TopLoc_Location& Other) const
249 {
250   return !IsEqual(Other);
251 }
252
253 //=======================================================================
254 //function : ShallowDump
255 //purpose  : 
256 //=======================================================================
257
258 void TopLoc_Location::ShallowDump(Standard_OStream& S) const
259 {
260   S << "TopLoc_Location : ";
261   TopLoc_SListOfItemLocation items  = myItems;
262   if (items.IsEmpty()) S << "Identity"<<endl;
263   while (items.More()) {
264     S<<"\n";
265     S << "       Exponent : " << items.Value().myPower <<endl;
266     items.Value().myDatum->ShallowDump(S);
267     items.Next();
268   }
269   S << "\n";
270 }
271
272