Salome HOME
70bce07523825dd57182bdf3a688a2e528908a57
[modules/geom.git] / src / GEOMGUI / GEOMGUI_DimensionProperty.cxx
1 // Copyright (C) 2007-2023  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // File   : GEOMGUI_DimensionProperty.cxx
24 // Author : Anton POLETAEV, Open CASCADE S.A.S.
25 //
26
27 #include "GEOMGUI_DimensionProperty.h"
28
29 #include <Basics_OCCTVersion.hxx>
30
31 // OCCT includes
32 #include <Standard_ProgramError.hxx>
33 #include <gp_Trsf.hxx>
34
35 #include <SalomeApp_Application.h>
36
37 // Static patterns for casting value-to-string & value-from-string. The patterns are:
38 //  ITEM: { name[string] : visibility : type : values[composite] };
39 //  PLANE: a[float] : b[float] : c[float] : d[float]
40 //  PROPS: flyout[float] : text h pos[int] : text v pos[int] : arrow pos[int]
41 //  XYZ: x [float] : y[float] : z[float]
42 //  FLOAT: value [float]
43 namespace
44 {
45   static const QString PATTERN_ITEM_GROUP = "\\{ (Name=(?::{2,}|.)*:(?!:)Visible=.*:Type=.*:.*) \\}";
46   static const QString PATTERN_ITEM  = "Name=((?::{2,}|.)*):(?!:)Visible=(\\d{1}):Type=(\\d{1}):(.*)";
47   static const QString PATTERN_PLANE = "Plane=\\{(.*):(.*):(.*):(.*)\\}";
48   static const QString PATTERN_PROPS = "Flyout=(.*):TextH=(.*):TextV=(.*):Arrow=(.*)";
49   static const QString PATTERN_XYZ   = "%1=\\{(.*):(.*):(.*)\\}";
50   static const QString PATTERN_FLOAT = "%1=(.*)";
51
52   static const QString PATTERN_LENGTH =
53     PATTERN_PLANE + ":" +
54     PATTERN_PROPS + ":" +
55     PATTERN_XYZ.arg( "Point1" ) + ":" +
56     PATTERN_XYZ.arg( "Point2" );
57
58   static const QString PATTERN_DIAMETER =
59     PATTERN_PLANE + ":" +
60     PATTERN_PROPS + ":" +
61     PATTERN_XYZ.arg( "Position" ) + ":" +
62     PATTERN_XYZ.arg( "NDir" ) + ":" +
63     PATTERN_XYZ.arg( "XDir" ) + ":" +
64     PATTERN_FLOAT.arg( "Radius" );
65
66   static const QString PATTERN_ANGLE =
67     PATTERN_PROPS + ":" +
68     PATTERN_XYZ.arg( "Point1" ) + ":" +
69     PATTERN_XYZ.arg( "Point2" ) + ":" +
70     PATTERN_XYZ.arg( "Point3" );
71 }
72
73 //=================================================================================
74 // function : Length::Init
75 // purpose  : 
76 //=================================================================================
77 #if OCC_VERSION_LARGE >= 0x070400ff
78 void GEOMGUI_DimensionProperty::Length::Init( const Handle(PrsDim_LengthDimension)& theIO, const gp_Ax3& theLCS )
79 #else
80 void GEOMGUI_DimensionProperty::Length::Init( const Handle(AIS_LengthDimension)& theIO, const gp_Ax3& theLCS )
81 #endif
82 {
83   gp_Trsf aFromLCS;
84   aFromLCS.SetTransformation( gp_Ax3(), theLCS );
85
86   FirstPoint  = theIO->FirstPoint().Transformed( aFromLCS );
87   SecondPoint = theIO->SecondPoint().Transformed( aFromLCS );
88   Plane       = theIO->GetPlane().Transformed( aFromLCS );
89   Flyout      = theIO->GetFlyout();
90   TextHPos    = theIO->DimensionAspect()->TextHorizontalPosition();
91   TextVPos    = theIO->DimensionAspect()->TextVerticalPosition();
92   ArrowPos    = theIO->DimensionAspect()->ArrowOrientation();
93 }
94
95 //=================================================================================
96 // function : Length::Update
97 // purpose  : 
98 //=================================================================================
99 #if OCC_VERSION_LARGE >= 0x070400ff
100 void GEOMGUI_DimensionProperty::Length::Update( Handle(PrsDim_LengthDimension)& theIO, const gp_Ax3& theLCS )
101 #else
102 void GEOMGUI_DimensionProperty::Length::Update( Handle(AIS_LengthDimension)& theIO, const gp_Ax3& theLCS )
103 #endif
104 {
105   gp_Trsf aToLCS;
106   aToLCS.SetTransformation( theLCS, gp_Ax3() );
107
108   gp_Pnt aPoint1 = FirstPoint.Transformed( aToLCS );
109   gp_Pnt aPoint2 = SecondPoint.Transformed( aToLCS );
110   gp_Pln aPlane  = Plane.Transformed( aToLCS );
111
112   theIO->SetMeasuredGeometry( aPoint1, aPoint2, aPlane );
113   theIO->SetFlyout( Flyout );
114
115   Handle(Prs3d_DimensionAspect) aStyle = new Prs3d_DimensionAspect();
116   aStyle->SetTextHorizontalPosition( TextHPos );
117   aStyle->SetTextVerticalPosition( TextVPos );
118   aStyle->SetArrowOrientation( ArrowPos );
119   theIO->SetDimensionAspect( aStyle );
120 }
121
122 //=================================================================================
123 // function : Length::ToValues
124 // purpose  : 
125 //=================================================================================
126 void GEOMGUI_DimensionProperty::Length::ToValues(std::vector<double>& theValues) const
127 {
128   // custom plane [2,3,4,5]
129   Standard_Real A, B, C, D;
130   Plane.Coefficients( A, B, C, D );
131   theValues.push_back( (double) A );
132   theValues.push_back( (double) B );
133   theValues.push_back( (double) C );
134   theValues.push_back( (double) D );
135
136   // flyout size [6]
137   theValues.push_back( (double) Flyout );
138
139   // text flags [7,8]
140   theValues.push_back( (double) TextHPos );
141   theValues.push_back( (double) TextVPos );
142
143   // arrow flags [9]
144   theValues.push_back( (double) ArrowPos );
145
146   // point 1 [10,11,12]
147   theValues.push_back( (double) FirstPoint.X() );
148   theValues.push_back( (double) FirstPoint.Y() );
149   theValues.push_back( (double) FirstPoint.Z() );
150
151   // point 2 [13,14,15]
152   theValues.push_back( (double) SecondPoint.X() );
153   theValues.push_back( (double) SecondPoint.Y() );
154   theValues.push_back( (double) SecondPoint.Z() );
155 }
156
157 //=================================================================================
158 // function : Length::FromValues
159 // purpose  : 
160 //=================================================================================
161 void GEOMGUI_DimensionProperty::Length::FromValues(int& theIt, const std::vector<double>& theValues)
162 {
163   // custom plane [2,3,4,5]
164   Standard_Real A = (Standard_Real) theValues[theIt++];
165   Standard_Real B = (Standard_Real) theValues[theIt++];
166   Standard_Real C = (Standard_Real) theValues[theIt++];
167   Standard_Real D = (Standard_Real) theValues[theIt++];
168   Plane = gp_Pln( A, B, C, D );
169
170   // flyout size [6]
171   Flyout = (Standard_Real) theValues[theIt++];
172
173   // text flags [7,8]
174   TextHPos = (Prs3d_DimensionTextHorizontalPosition)(int)theValues[theIt++];
175   TextVPos = (Prs3d_DimensionTextVerticalPosition)  (int)theValues[theIt++];
176
177   // arrow flags [9]
178   ArrowPos = (Prs3d_DimensionArrowOrientation) (int)theValues[theIt++];
179
180   // point 1 [10,11,12]
181   Standard_Real aFirstX = theValues[theIt++];
182   Standard_Real aFirstY = theValues[theIt++];
183   Standard_Real aFirstZ = theValues[theIt++];
184   FirstPoint = gp_Pnt( aFirstX, aFirstY, aFirstZ );
185
186   // point 2 [13,14,15]
187   Standard_Real aSecondX = theValues[theIt++];
188   Standard_Real aSecondY = theValues[theIt++];
189   Standard_Real aSecondZ = theValues[theIt++];
190   SecondPoint = gp_Pnt( aSecondX, aSecondY, aSecondZ );
191 }
192
193 //=================================================================================
194 // function : Length::operator == 
195 // purpose  : 
196 //=================================================================================
197 bool GEOMGUI_DimensionProperty::Length::operator == (const Length& theOther) const
198 {
199   if ( FirstPoint.X()  != theOther.FirstPoint.X()
200     || FirstPoint.Y()  != theOther.FirstPoint.Y()
201     || FirstPoint.Z()  != theOther.FirstPoint.Z()
202     || SecondPoint.X() != theOther.SecondPoint.X()
203     || SecondPoint.Y() != theOther.SecondPoint.Y()
204     || SecondPoint.Z() != theOther.SecondPoint.Z() )
205   {
206     return false;
207   }
208
209   if ( Plane.Location().X() != theOther.Plane.Location().X()
210     || Plane.Location().Y() != theOther.Plane.Location().Y()
211     || Plane.Location().Z() != theOther.Plane.Location().Z()
212     || Plane.Axis().Direction().X() != theOther.Plane.Axis().Direction().X()
213     || Plane.Axis().Direction().Y() != theOther.Plane.Axis().Direction().Y()
214     || Plane.Axis().Direction().Z() != theOther.Plane.Axis().Direction().Z() )
215   {
216     return false;
217   }
218
219   if ( Flyout   != theOther.Flyout 
220     || TextHPos != theOther.TextHPos 
221     || TextVPos != theOther.TextVPos
222     || ArrowPos != theOther.ArrowPos )
223   {
224     return false;
225   }
226
227   return true;
228 }
229
230 //=================================================================================
231 // function : Diameter::Init
232 // purpose  : 
233 //=================================================================================
234 void GEOMGUI_DimensionProperty::Diameter::Init( const Handle(AIS_DiameterDimension)& theIO, const gp_Ax3& theLCS )
235 {
236   gp_Trsf aFromLCS;
237   aFromLCS.SetTransformation( gp_Ax3(), theLCS );
238
239   Circle   = theIO->Circle().Transformed( aFromLCS );
240   Plane    = theIO->GetPlane().Transformed( aFromLCS );
241   Flyout   = theIO->GetFlyout();
242   TextHPos = theIO->DimensionAspect()->TextHorizontalPosition();
243   TextVPos = theIO->DimensionAspect()->TextVerticalPosition();
244   ArrowPos = theIO->DimensionAspect()->ArrowOrientation();
245 }
246
247 //=================================================================================
248 // function : Diameter::Update
249 // purpose  : 
250 //=================================================================================
251 void GEOMGUI_DimensionProperty::Diameter::Update( Handle(AIS_DiameterDimension)& theIO, const gp_Ax3& theLCS )
252 {
253   gp_Trsf aToLCS;
254   aToLCS.SetTransformation( theLCS, gp_Ax3() );
255
256   gp_Circ aCircle = Circle.Transformed( aToLCS );
257   gp_Pln  aPlane  = Plane.Transformed( aToLCS );
258
259   Standard_Boolean isParallel = 
260     aCircle.Axis().Direction().IsParallel( aPlane.Axis().Direction(), Precision::Angular() );
261
262   if ( isParallel )
263   {
264     theIO->UnsetCustomPlane();
265     theIO->SetMeasuredGeometry( aCircle );
266   }
267   else
268   {
269     theIO->SetCustomPlane( aPlane );
270     theIO->SetMeasuredGeometry( aCircle );
271   }
272
273   theIO->SetFlyout( Flyout );
274
275   Handle(Prs3d_DimensionAspect) aStyle = new Prs3d_DimensionAspect();
276   aStyle->SetTextHorizontalPosition( TextHPos );
277   aStyle->SetTextVerticalPosition( TextVPos );
278   aStyle->SetArrowOrientation( ArrowPos );
279   theIO->SetDimensionAspect( aStyle );
280 }
281
282 //=================================================================================
283 // function : Diameter::ToValues
284 // purpose  : 
285 //=================================================================================
286 void GEOMGUI_DimensionProperty::Diameter::ToValues(std::vector<double>& theValues) const
287 {
288   // custom plane [2,3,4,5]
289   Standard_Real A, B, C, D;
290   Plane.Coefficients( A, B, C, D );
291   theValues.push_back( (double) A );
292   theValues.push_back( (double) B );
293   theValues.push_back( (double) C );
294   theValues.push_back( (double) D );
295
296   // flyout size [6]
297   theValues.push_back( (double) Flyout );
298
299   // text flags [7,8]
300   theValues.push_back( (double) TextHPos );
301   theValues.push_back( (double) TextVPos );
302
303   // arrow flags [9]
304   theValues.push_back( (double) ArrowPos );
305
306   // circle location [10,11,12]
307   theValues.push_back( (double) Circle.Location().X() );
308   theValues.push_back( (double) Circle.Location().Y() );
309   theValues.push_back( (double) Circle.Location().Z() );
310
311   // circle normal [13,14,15]
312   theValues.push_back( (double) Circle.Axis().Direction().X() );
313   theValues.push_back( (double) Circle.Axis().Direction().Y() );
314   theValues.push_back( (double) Circle.Axis().Direction().Z() );
315
316   // x-direction [16,17,18]
317   theValues.push_back( (double) Circle.XAxis().Direction().X() );
318   theValues.push_back( (double) Circle.XAxis().Direction().Y() );
319   theValues.push_back( (double) Circle.XAxis().Direction().Z() );
320
321   // radius [19]
322   theValues.push_back( (double) Circle.Radius() );
323 }
324
325 //=================================================================================
326 // function : Diameter::FromValues
327 // purpose  : 
328 //=================================================================================
329 void GEOMGUI_DimensionProperty::Diameter::FromValues(int& theIt, const std::vector<double>& theValues)
330 {
331   // custom plane [2,3,4,5]
332   Standard_Real A = (Standard_Real) theValues[theIt++];
333   Standard_Real B = (Standard_Real) theValues[theIt++];
334   Standard_Real C = (Standard_Real) theValues[theIt++];
335   Standard_Real D = (Standard_Real) theValues[theIt++];
336   Plane = gp_Pln( A, B, C, D );
337
338   // flyout size [6]
339   Flyout = (Standard_Real) theValues[theIt++];
340
341   // text flags [7,8]
342   TextHPos = (Prs3d_DimensionTextHorizontalPosition)(int)theValues[theIt++];
343   TextVPos = (Prs3d_DimensionTextVerticalPosition)  (int)theValues[theIt++];
344
345   // arrow flags [9]
346   ArrowPos = (Prs3d_DimensionArrowOrientation) (int)theValues[theIt++];
347
348   // circle location [10,11,12]
349   Standard_Real aLocX = (Standard_Real) theValues[theIt++];
350   Standard_Real aLocY = (Standard_Real) theValues[theIt++];
351   Standard_Real aLocZ = (Standard_Real) theValues[theIt++];
352
353   // circle normal [13,14,15]
354   Standard_Real aNormX = (Standard_Real) theValues[theIt++];
355   Standard_Real aNormY = (Standard_Real) theValues[theIt++];
356   Standard_Real aNormZ = (Standard_Real) theValues[theIt++];
357
358   // x-direction [16,17,18]
359   Standard_Real aXDirX = (Standard_Real) theValues[theIt++];
360   Standard_Real aXDirY = (Standard_Real) theValues[theIt++];
361   Standard_Real aXDirZ = (Standard_Real) theValues[theIt++];
362
363   // radius [19]
364   Standard_Real aRadius = (Standard_Real) theValues[theIt++];
365
366   gp_Ax2 anAx( gp_Pnt( aLocX, aLocY, aLocZ ),
367                gp_Dir( aNormX, aNormY, aNormZ ),
368                gp_Dir( aXDirX, aXDirY, aXDirZ ) );
369
370   Circle = gp_Circ( anAx, aRadius );
371 }
372
373 //=================================================================================
374 // function : Diameter::operator == 
375 // purpose  : 
376 //=================================================================================
377 bool GEOMGUI_DimensionProperty::Diameter::operator == (const Diameter& theOther) const
378 {
379   if ( Circle.Location().X()  != theOther.Circle.Location().X()
380     || Circle.Location().Y()  != theOther.Circle.Location().Y()
381     || Circle.Location().Z()  != theOther.Circle.Location().Z()
382     || Circle.Axis().Direction().X() != theOther.Circle.Axis().Direction().X()
383     || Circle.Axis().Direction().Y() != theOther.Circle.Axis().Direction().Y()
384     || Circle.Axis().Direction().Z() != theOther.Circle.Axis().Direction().Z()
385     || Circle.XAxis().Direction().X() != theOther.Circle.XAxis().Direction().X()
386     || Circle.XAxis().Direction().Y() != theOther.Circle.XAxis().Direction().Y()
387     || Circle.XAxis().Direction().Z() != theOther.Circle.XAxis().Direction().Z() 
388     || Circle.Radius() != theOther.Circle.Radius() )
389   {
390     return false;
391   }
392
393   if ( Plane.Location().X() != theOther.Plane.Location().X()
394     || Plane.Location().Y() != theOther.Plane.Location().Y()
395     || Plane.Location().Z() != theOther.Plane.Location().Z()
396     || Plane.Axis().Direction().X() != theOther.Plane.Axis().Direction().X()
397     || Plane.Axis().Direction().Y() != theOther.Plane.Axis().Direction().Y()
398     || Plane.Axis().Direction().Z() != theOther.Plane.Axis().Direction().Z() )
399   {
400     return false;
401   }
402
403   if ( Flyout   != theOther.Flyout 
404     || TextHPos != theOther.TextHPos 
405     || TextVPos != theOther.TextVPos 
406     || ArrowPos != theOther.ArrowPos )
407   {
408     return false;
409   }
410
411   return true;
412 }
413
414 //=================================================================================
415 // function : Angle::Init
416 // purpose  : 
417 //=================================================================================
418 void GEOMGUI_DimensionProperty::Angle::Init( const Handle(AIS_AngleDimension)& theIO, const gp_Ax3& theLCS )
419 {
420   gp_Trsf aFromLCS;
421   aFromLCS.SetTransformation( gp_Ax3(), theLCS );
422
423   FirstPoint  = theIO->FirstPoint().Transformed( aFromLCS );
424   SecondPoint = theIO->SecondPoint().Transformed( aFromLCS );
425   CenterPoint = theIO->CenterPoint().Transformed( aFromLCS );
426   Flyout      = theIO->GetFlyout();
427   TextHPos    = theIO->DimensionAspect()->TextHorizontalPosition();
428   TextVPos    = theIO->DimensionAspect()->TextVerticalPosition();
429   ArrowPos    = theIO->DimensionAspect()->ArrowOrientation();
430 }
431
432 //=================================================================================
433 // function : Angle::Update
434 // purpose  : 
435 //=================================================================================
436 void GEOMGUI_DimensionProperty::Angle::Update( Handle(AIS_AngleDimension)& theIO, const gp_Ax3& theLCS )
437 {
438   gp_Trsf aToLCS;
439   aToLCS.SetTransformation( theLCS, gp_Ax3() );
440
441   gp_Pnt aPoint1 = FirstPoint.Transformed( aToLCS );
442   gp_Pnt aPoint2 = CenterPoint.Transformed( aToLCS );
443   gp_Pnt aPoint3 = SecondPoint.Transformed( aToLCS );
444
445   theIO->SetMeasuredGeometry( aPoint1, aPoint2, aPoint3 );
446   theIO->SetFlyout( Flyout );
447
448   Handle(Prs3d_DimensionAspect) aStyle = new Prs3d_DimensionAspect();
449   aStyle->SetTextHorizontalPosition( TextHPos );
450   aStyle->SetTextVerticalPosition( TextVPos );
451   aStyle->SetArrowOrientation( ArrowPos );
452   theIO->SetDimensionAspect( aStyle );
453 }
454
455 //=================================================================================
456 // function : Angle::ToValues
457 // purpose  : 
458 //=================================================================================
459 void GEOMGUI_DimensionProperty::Angle::ToValues(std::vector<double>& theValues) const
460 {
461   // flyout [2]
462   theValues.push_back( (double) Flyout );
463
464   // text flags [3,4]
465   theValues.push_back( (double) TextHPos );
466   theValues.push_back( (double) TextVPos );
467
468   // arrow flags [5]
469   theValues.push_back( (double) ArrowPos );
470
471   // point 1 [6,7,8]
472   theValues.push_back( (double) FirstPoint.X() );
473   theValues.push_back( (double) FirstPoint.Y() );
474   theValues.push_back( (double) FirstPoint.Z() );
475
476   // point 2 [9,10,11]
477   theValues.push_back( (double) SecondPoint.X() );
478   theValues.push_back( (double) SecondPoint.Y() );
479   theValues.push_back( (double) SecondPoint.Z() );
480
481   // center [12,13,14]
482   theValues.push_back( (double) CenterPoint.X() );
483   theValues.push_back( (double) CenterPoint.Y() );
484   theValues.push_back( (double) CenterPoint.Z() );
485 }
486
487 //=================================================================================
488 // function : Angle::FromValues
489 // purpose  : 
490 //=================================================================================
491 void GEOMGUI_DimensionProperty::Angle::FromValues(int& theIt, const std::vector<double>& theValues)
492 {
493   // flyout [2]
494   Flyout = (Standard_Real) theValues[theIt++];
495
496   // text flags [3,4]
497   TextHPos = (Prs3d_DimensionTextHorizontalPosition)(int)theValues[theIt++];
498   TextVPos = (Prs3d_DimensionTextVerticalPosition)  (int)theValues[theIt++];
499
500   // arrow flags [5]
501   ArrowPos = (Prs3d_DimensionArrowOrientation) (int)theValues[theIt++];
502
503   // point 1 [6,7,8]
504   Standard_Real aFirstX = (Standard_Real) theValues[theIt++];
505   Standard_Real aFirstY = (Standard_Real) theValues[theIt++];
506   Standard_Real aFirstZ = (Standard_Real) theValues[theIt++];
507
508   // point 2 [9,10,11]
509   Standard_Real aSecondX = (Standard_Real) theValues[theIt++];
510   Standard_Real aSecondY = (Standard_Real) theValues[theIt++];
511   Standard_Real aSecondZ = (Standard_Real) theValues[theIt++];
512
513   // center [12,13,14]
514   Standard_Real aCenterX = (Standard_Real) theValues[theIt++];
515   Standard_Real aCenterY = (Standard_Real) theValues[theIt++];
516   Standard_Real aCenterZ = (Standard_Real) theValues[theIt++];
517
518   FirstPoint  = gp_Pnt( aFirstX, aFirstY, aFirstZ );
519   SecondPoint = gp_Pnt( aSecondX, aSecondY, aSecondZ );
520   CenterPoint = gp_Pnt( aCenterX, aCenterY, aCenterZ );
521 }
522
523 //=================================================================================
524 // function : Angle::operator == 
525 // purpose  : 
526 //=================================================================================
527 bool GEOMGUI_DimensionProperty::Angle::operator == (const Angle& theOther) const
528 {
529   if ( FirstPoint.X()  != theOther.FirstPoint.X()
530     || FirstPoint.Y()  != theOther.FirstPoint.Y()
531     || FirstPoint.Z()  != theOther.FirstPoint.Z()
532     || SecondPoint.X() != theOther.SecondPoint.X()
533     || SecondPoint.Y() != theOther.SecondPoint.Y()
534     || SecondPoint.Z() != theOther.SecondPoint.Z()
535     || CenterPoint.X() != theOther.CenterPoint.X()
536     || CenterPoint.Y() != theOther.CenterPoint.Y()
537     || CenterPoint.Z() != theOther.CenterPoint.Z() )
538   {
539     return false;
540   }
541
542   if ( Flyout   != theOther.Flyout 
543     || TextHPos != theOther.TextHPos 
544     || TextVPos != theOther.TextVPos 
545     || ArrowPos != theOther.ArrowPos )
546   {
547     return false;
548   }
549
550   return true;
551 }
552
553 //=================================================================================
554 // function : Constructor
555 // purpose  : 
556 //=================================================================================
557 GEOMGUI_DimensionProperty::GEOMGUI_DimensionProperty()
558 {
559 }
560
561 //=================================================================================
562 // function : Copy constructor
563 // purpose  : 
564 //=================================================================================
565 GEOMGUI_DimensionProperty::GEOMGUI_DimensionProperty( const GEOMGUI_DimensionProperty& theOther )
566 {
567   const VectorOfVisibility& aOtherVis   = theOther.myVisibility;
568   const VectorOfNames& aOtherNames      = theOther.myNames;
569   const VectorOfRecords& aOtherRecords  = theOther.myRecords;
570
571   VectorOfVisibility::const_iterator aVisIt = aOtherVis.constBegin();
572   VectorOfNames::const_iterator   aNamesIt  = aOtherNames.constBegin();
573   VectorOfRecords::const_iterator aRecordIt = aOtherRecords.constBegin();
574   for ( ; aRecordIt != aOtherRecords.constEnd(); ++aVisIt, ++aNamesIt, ++aRecordIt )
575   {
576     RecordPtr aNewRecord;
577     const RecordPtr& aRecord = *aRecordIt;
578     switch( aRecord->Type() )
579     {
580       case DimensionType_Length :
581         aNewRecord = RecordPtr( new Length( *aRecord->AsLength() ) );
582         break;
583
584       case DimensionType_Diameter :
585         aNewRecord = RecordPtr( new Diameter( *aRecord->AsDiameter() ) );
586         break;
587
588       case DimensionType_Angle :
589         aNewRecord = RecordPtr( new Angle( *aRecord->AsAngle() ) );
590         break;
591     }
592
593     myVisibility.append( *aVisIt );
594     myNames.append( *aNamesIt );
595     myRecords.append( aNewRecord );
596   }
597 }
598
599 //=================================================================================
600 // function : Init constructor
601 // purpose  : 
602 //=================================================================================
603 GEOMGUI_DimensionProperty::GEOMGUI_DimensionProperty( const std::string& theEntry )
604 {
605   LoadFromAttribute( theEntry );
606 }
607
608 //=================================================================================
609 // function : Init constructor
610 // purpose  : 
611 //=================================================================================
612 GEOMGUI_DimensionProperty::GEOMGUI_DimensionProperty( const QString& theProperty )
613 {
614   QRegExp aRegExpItemGroups( PATTERN_ITEM_GROUP );
615   QRegExp aRegExpItem( "^" + PATTERN_ITEM + "$" );
616   aRegExpItemGroups.setMinimal( true );
617   aRegExpItem.setMinimal( true );
618
619   int aPos = 0;
620   while ( ( aPos = aRegExpItemGroups.indexIn( theProperty, aPos ) ) != -1 )
621   {
622     aPos += aRegExpItemGroups.matchedLength();
623
624     QString aStrItem = aRegExpItemGroups.cap(1);
625
626     if ( aRegExpItem.indexIn( aStrItem ) < 0 )
627     {
628       continue;
629     }
630
631     // extract name
632     QString aStrName    = aRegExpItem.cap( 1 );
633     QString aStrVisible = aRegExpItem.cap( 2 );
634     QString aStrType    = aRegExpItem.cap( 3 );
635     QString aStrValues  = aRegExpItem.cap( 4 );
636
637     // extract values
638     aStrName.replace( "::", ":" );
639     bool isVisible = aStrVisible.toInt() != 0;
640     int aType = aStrType.toInt();
641     
642     RecordPtr aRecord;
643     switch ( aType )
644     {
645       case DimensionType_Length   : aRecord = RecordPtr( new Length ); break;
646       case DimensionType_Diameter : aRecord = RecordPtr( new Diameter ); break;
647       case DimensionType_Angle    : aRecord = RecordPtr( new Angle ); break;
648       default:
649         continue;
650     }
651     
652     QRegExp aRegExpValues;
653     switch ( aType )
654     {
655       case DimensionType_Length   : aRegExpValues = QRegExp( "^" + PATTERN_LENGTH + "$" ); break;
656       case DimensionType_Diameter : aRegExpValues = QRegExp( "^" + PATTERN_DIAMETER + "$" ); break;
657       case DimensionType_Angle    : aRegExpValues = QRegExp( "^" + PATTERN_ANGLE + "$" ); break;
658     }
659
660     aRegExpValues.setMinimal(true);
661
662     if ( aRegExpValues.indexIn( aStrValues ) < 0 )
663     {
664       continue;
665     }
666
667     std::vector<double> aValues;
668
669     QStringList aStrListOfValues = aRegExpValues.capturedTexts();
670     QStringList::Iterator aStrListOfValuesIt = aStrListOfValues.begin();
671     ++aStrListOfValuesIt; // skip first capture
672     for ( ; aStrListOfValuesIt != aStrListOfValues.end(); ++aStrListOfValuesIt )
673     {
674       aValues.push_back( (*aStrListOfValuesIt).toDouble() );
675     }
676
677     int aValueIt = 0;
678
679     aRecord->FromValues( aValueIt, aValues );
680
681     myVisibility.append( isVisible );
682     myNames.append( aStrName );
683     myRecords.append( aRecord );
684   }
685 }
686
687 //=================================================================================
688 // function : Destructor
689 // purpose  : 
690 //=================================================================================
691 GEOMGUI_DimensionProperty::~GEOMGUI_DimensionProperty()
692 {
693 }
694
695 //=================================================================================
696 // function : operator QVariant()
697 // purpose  : 
698 //=================================================================================
699 GEOMGUI_DimensionProperty::operator QVariant() const
700 {
701   QVariant aQVariant;
702   aQVariant.setValue( *this );
703   return aQVariant;
704 }
705
706 //=================================================================================
707 // function : operator QString()
708 // purpose  : 
709 //=================================================================================
710 GEOMGUI_DimensionProperty::operator QString() const
711 {
712   QStringList anItems;
713
714   VectorOfVisibility::ConstIterator aVisibilityIt = myVisibility.constBegin();
715   VectorOfRecords::ConstIterator aRecordIt        = myRecords.constBegin();
716   VectorOfNames::ConstIterator aNameIt            = myNames.constBegin();
717   for ( ; aRecordIt != myRecords.constEnd(); ++aRecordIt, ++aNameIt, ++aVisibilityIt )
718   {
719     QString aName            = *aNameIt;
720     const bool& isVisible    = *aVisibilityIt;
721     const RecordPtr& aRecord = *aRecordIt;
722
723     // pack values
724     std::vector<double> aPacked;
725     aRecord->ToValues( aPacked );
726
727     // put values into pattern
728     QString aStringValues;
729     switch ( aRecord->Type() )
730     {
731       case DimensionType_Length   : aStringValues = PATTERN_LENGTH; break;
732       case DimensionType_Diameter : aStringValues = PATTERN_DIAMETER; break;
733       case DimensionType_Angle    : aStringValues = PATTERN_ANGLE; break;
734       default:
735         continue;
736     }
737
738     aStringValues.remove("\\");
739
740     size_t it = 0;
741     for ( ; it < aPacked.size(); ++it )
742     {
743       int aNextPos = aStringValues.indexOf("(.*)");
744       if ( aNextPos < 0 )
745       {
746         break; // invalid pattern
747       }
748
749       aStringValues.replace( aNextPos, 4, QString::number( aPacked.at(it) ) );
750     }
751
752     if ( it < aPacked.size() )
753     {
754       continue; // invalid pattern
755     }
756
757     // replace all ':' to '::' for pattern matching
758     aName.replace(":", "::");
759
760     anItems.append( 
761       QString("{ Name=") + aName +
762       QString(":") + QString("Visible=") + QString::number( isVisible ? 1 : 0 ) +
763       QString(":") + QString("Type=") + QString::number( (int) aRecord->Type() ) +
764       QString(":") + aStringValues + QString(" }") );
765   }
766
767   return anItems.join( ":" );
768 }
769
770 //=================================================================================
771 // function : operator ==
772 // purpose  : 
773 //=================================================================================
774 bool GEOMGUI_DimensionProperty::operator == (const GEOMGUI_DimensionProperty& theOther) const
775 {
776   if ( myVisibility.size() != theOther.myVisibility.size()
777     || myNames.size() != theOther.myNames.size()
778     || myRecords.size() != theOther.myRecords.size() )
779   {
780     return false;
781   }
782
783   for ( int it = 0; it < myRecords.size(); ++it )
784   {
785     if ( myVisibility[it] != theOther.myVisibility[it] )
786     {
787       return false;
788     }
789
790     if ( myNames[it] != theOther.myNames[it] )
791     {
792       return false;
793     }
794
795     const RecordPtr& aRecord = myRecords[it];
796     const RecordPtr& aOtherRecord = theOther.myRecords[it];
797     if ( aRecord->Type() != aOtherRecord->Type() )
798     {
799       return false;
800     }
801
802     switch ( aRecord->Type() )
803     {
804       case DimensionType_Length:
805         if ( (*aRecord->AsLength()) != (*aOtherRecord->AsLength()) )
806         {
807           return false;
808         }
809         break;
810
811       case DimensionType_Diameter:
812         if ( (*aRecord->AsDiameter()) != (*aOtherRecord->AsDiameter()) )
813         {
814           return false;
815         }
816         break;
817
818       case DimensionType_Angle:
819         if ( (*aRecord->AsAngle()) != (*aOtherRecord->AsAngle()) )
820         {
821           return false;
822         }
823         break;
824     }
825   }
826
827   return true;
828 }
829
830 //=================================================================================
831 // function : GetNumber
832 // purpose  : 
833 //=================================================================================
834 int GEOMGUI_DimensionProperty::GetNumber() const
835 {
836   return myRecords.size();
837 }
838
839 //=================================================================================
840 // function : AddRecord
841 // purpose  : 
842 //=================================================================================
843 void GEOMGUI_DimensionProperty::AddRecord( const Handle(AIS_Dimension)& theIO, const gp_Ax3& theLCS )
844 {
845   RecordPtr aNewRecord;
846
847   int aType = TypeFromIO( theIO );
848
849   switch ( aType )
850   {
851     case DimensionType_Length :
852     {
853 #if OCC_VERSION_LARGE >= 0x070400ff
854       Handle(PrsDim_LengthDimension) aLength = 
855         Handle(PrsDim_LengthDimension)::DownCast( theIO );
856 #else
857       Handle(AIS_LengthDimension) aLength = 
858         Handle(AIS_LengthDimension)::DownCast( theIO );
859 #endif
860
861       aNewRecord = RecordPtr( new Length() );
862       aNewRecord->AsLength()->Init( aLength, theLCS );
863       break;
864     }
865
866     case DimensionType_Diameter :
867     {
868       Handle(AIS_DiameterDimension) aDiam =
869         Handle(AIS_DiameterDimension)::DownCast( theIO );
870
871       aNewRecord = RecordPtr( new Diameter() );
872       aNewRecord->AsDiameter()->Init( aDiam, theLCS );
873       break;
874     }
875
876     case DimensionType_Angle :
877     {
878       Handle(AIS_AngleDimension) anAngle =
879         Handle(AIS_AngleDimension)::DownCast( theIO );
880
881       aNewRecord = RecordPtr( new Angle() );
882       aNewRecord->AsAngle()->Init( anAngle, theLCS );
883     }
884   }
885
886   myVisibility.append( true );
887   myNames.append( QString() );
888   myRecords.append( aNewRecord );
889 }
890
891 //=================================================================================
892 // function : AddRecord
893 // purpose  : 
894 //=================================================================================
895 void GEOMGUI_DimensionProperty::AddRecord( const RecordPtr& theRecord )
896 {
897   myVisibility.append( true );
898   myNames.append( QString() );
899   myRecords.append( theRecord );
900 }
901
902 //=================================================================================
903 // function : RemoveRecord
904 // purpose  : 
905 //=================================================================================
906 void GEOMGUI_DimensionProperty::RemoveRecord( const int theIndex )
907 {
908   myNames.remove( theIndex );
909   myVisibility.remove( theIndex );
910   myRecords.remove( theIndex );
911 }
912
913 //=================================================================================
914 // function : Clear
915 // purpose  : 
916 //=================================================================================
917 void GEOMGUI_DimensionProperty::Clear()
918 {
919   myNames.clear();
920   myVisibility.clear();
921   myRecords.clear();
922 }
923
924 //=================================================================================
925 // function : SetRecord
926 // purpose  : 
927 //=================================================================================
928 void GEOMGUI_DimensionProperty::SetRecord( const int theIndex,
929                                            const Handle(AIS_Dimension)& theIO,
930                                            const gp_Ax3& theLCS )
931 {
932   int aType = TypeFromIO( theIO );
933
934   RecordPtr& aChangeRecord = myRecords[theIndex];
935
936   switch ( aType )
937   {
938     case DimensionType_Length :
939     {
940 #if OCC_VERSION_LARGE >= 0x070400ff
941       Handle(PrsDim_LengthDimension) aLength = 
942         Handle(PrsDim_LengthDimension)::DownCast( theIO );
943 #else
944       Handle(AIS_LengthDimension) aLength = 
945         Handle(AIS_LengthDimension)::DownCast( theIO );
946 #endif
947
948       aChangeRecord = RecordPtr( new Length() );
949       aChangeRecord->AsLength()->Init( aLength, theLCS );
950       break;
951     }
952
953     case DimensionType_Diameter :
954     {
955       Handle(AIS_DiameterDimension) aDiam =
956         Handle(AIS_DiameterDimension)::DownCast( theIO );
957
958       aChangeRecord = RecordPtr( new Diameter() );
959       aChangeRecord->AsDiameter()->Init( aDiam, theLCS );
960       break;
961     }
962
963     case DimensionType_Angle :
964     {
965       Handle(AIS_AngleDimension) anAngle =
966         Handle(AIS_AngleDimension)::DownCast( theIO );
967
968       aChangeRecord = RecordPtr( new Angle() );
969       aChangeRecord->AsAngle()->Init( anAngle, theLCS );
970     }
971   }
972 }
973
974 //=================================================================================
975 // function : SetRecord
976 // purpose  : 
977 //=================================================================================
978 void GEOMGUI_DimensionProperty::SetRecord( const int theIndex, const RecordPtr& theRecord )
979 {
980   myRecords[theIndex] = theRecord;
981 }
982
983 //=================================================================================
984 // function : GetRecord
985 // purpose  : 
986 //=================================================================================
987 const GEOMGUI_DimensionProperty::RecordPtr& GEOMGUI_DimensionProperty::GetRecord( const int theIndex ) const
988 {
989   return myRecords[theIndex];
990 }
991
992 //=================================================================================
993 // function : IsVisible
994 // purpose  : 
995 //=================================================================================
996 bool GEOMGUI_DimensionProperty::IsVisible( const int theIndex ) const
997 {
998   return myVisibility[theIndex];
999 }
1000
1001 //=================================================================================
1002 // function : SetVisible
1003 // purpose  : 
1004 //=================================================================================
1005 void GEOMGUI_DimensionProperty::SetVisible( const int theIndex, const bool theIsVisible )
1006 {
1007   myVisibility[theIndex] = theIsVisible;
1008 }
1009
1010 //=================================================================================
1011 // function : GetName
1012 // purpose  : 
1013 //=================================================================================
1014 QString GEOMGUI_DimensionProperty::GetName( const int theIndex ) const
1015 {
1016   return myNames[theIndex];
1017 }
1018
1019 //=================================================================================
1020 // function : SetName
1021 // purpose  : 
1022 //=================================================================================
1023 void GEOMGUI_DimensionProperty::SetName( const int theIndex, const QString &theName )
1024 {
1025   myNames[theIndex] = theName;
1026 }
1027
1028 //=================================================================================
1029 // function : GetType
1030 // purpose  : 
1031 //=================================================================================
1032 int GEOMGUI_DimensionProperty::GetType( const int theIndex ) const
1033 {
1034   return myRecords[theIndex]->Type();
1035 }
1036
1037 //=================================================================================
1038 // function : LoadFromAttribute
1039 // purpose  : 
1040 //=================================================================================
1041 void GEOMGUI_DimensionProperty::LoadFromAttribute( const std::string& theEntry )
1042 {
1043   Clear();
1044
1045   _PTR(SObject) aSObj = SalomeApp_Application::getStudy()->FindObjectID( theEntry );
1046   if ( !aSObj )
1047   {
1048     return;
1049   }
1050
1051   _PTR(StudyBuilder) aBuilder = SalomeApp_Application::getStudy()->NewBuilder();
1052
1053   _PTR(GenericAttribute) aSeekAtt;
1054   _PTR(AttributeTableOfReal) aRecordsAtt;
1055
1056   if ( !aSObj->FindAttribute( aSeekAtt, "AttributeTableOfReal" ) )
1057   {
1058     return;
1059   }
1060
1061   aRecordsAtt = aSeekAtt;
1062
1063   for ( int aRecordIt = 1; aRecordIt <= aRecordsAtt->GetNbColumns(); ++aRecordIt )
1064   {
1065     std::vector<double> aPacked = aRecordsAtt->GetColumn( aRecordIt );
1066
1067     RecordPtr aRecord;
1068
1069     QString aName( aRecordsAtt->GetColumnTitle( aRecordIt ).c_str() );
1070
1071     // unpack records
1072     int it = 0;
1073
1074     // visibility [0]
1075     bool isVisible = (bool) aPacked[it++];
1076
1077     // type [1]
1078     int aType = (int) aPacked[it++];
1079
1080     switch (aType)
1081     {
1082       case DimensionType_Length   : aRecord = RecordPtr( new Length ); break;
1083       case DimensionType_Diameter : aRecord = RecordPtr( new Diameter ); break;
1084       case DimensionType_Angle    : aRecord = RecordPtr( new Angle ); break;
1085     }
1086     aRecord->FromValues(it, aPacked);
1087
1088     myVisibility.append( isVisible );
1089     myNames.append( aName );
1090     myRecords.append( aRecord );
1091   }
1092 }
1093
1094 //=================================================================================
1095 // function : SaveToAttribute
1096 // purpose  : 
1097 //=================================================================================
1098 void GEOMGUI_DimensionProperty::SaveToAttribute( const std::string &theEntry )
1099 {
1100   _PTR(SObject) aSObj = SalomeApp_Application::getStudy()->FindObjectID( theEntry );
1101   if ( !aSObj )
1102   {
1103     return;
1104   }
1105
1106   _PTR(StudyBuilder) aBuilder = SalomeApp_Application::getStudy()->NewBuilder();
1107
1108   _PTR(AttributeTableOfReal) aRecordsAtt;
1109
1110   aRecordsAtt = aBuilder->FindOrCreateAttribute( aSObj, "AttributeTableOfReal" );
1111   aRecordsAtt->SetNbColumns( 0 );
1112
1113   for ( int it = 0; it < myRecords.size(); ++it )
1114   {
1115     bool aVisibility   = myVisibility[it];
1116     QString& aName     = myNames[it];
1117     RecordPtr& aRecord = myRecords[it];
1118
1119     std::vector<double> aPacked;
1120
1121     // visibility [0]
1122     aPacked.push_back( (double) aVisibility );
1123
1124     // type [1]
1125     aPacked.push_back( (double) aRecord->Type() );
1126
1127     // values
1128     aRecord->ToValues( aPacked );
1129
1130     aRecordsAtt->AddColumn( aPacked );
1131     aRecordsAtt->SetColumnTitle( it + 1, aName.toStdString() );
1132   }
1133 }
1134
1135 //=================================================================================
1136 // function : TypeFromIO
1137 // purpose  : 
1138 //=================================================================================
1139 int GEOMGUI_DimensionProperty::TypeFromIO( const Handle(AIS_Dimension)& theIO ) const
1140 {
1141 #if OCC_VERSION_LARGE >= 0x070400ff
1142   if ( theIO->IsKind( STANDARD_TYPE( PrsDim_LengthDimension ) ) )
1143 #else
1144   if ( theIO->IsKind( STANDARD_TYPE( AIS_LengthDimension ) ) )
1145 #endif
1146   {
1147     return DimensionType_Length;
1148   }
1149
1150   if ( theIO->IsKind( STANDARD_TYPE( AIS_DiameterDimension ) ) )
1151   {
1152     return DimensionType_Diameter;
1153   }
1154
1155   if ( theIO->IsKind( STANDARD_TYPE( AIS_AngleDimension ) ) )
1156   {
1157     return DimensionType_Angle;
1158   }
1159
1160   Standard_ProgramError::Raise( "unsupported dimension type" );
1161
1162   return 0;
1163 }