Salome HOME
Update from BR_V5_DEV 13Feb2009
[modules/gui.git] / src / GLViewer / GLViewer_BaseObjects.cxx
1 //  Copyright (C) 2007-2008  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.
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 //  Author : OPEN CASCADE
23 //#include <GLViewerAfx.h>
24 //
25 #include "GLViewer_BaseObjects.h"
26 #include "GLViewer_BaseDrawers.h"
27 #include "GLViewer_AspectLine.h"
28 #include "GLViewer_CoordSystem.h"
29 #include "GLViewer_Text.h"
30 #include "GLViewer_Group.h"
31
32 #include "GLViewer_Drawer.h"
33
34 #include <QFile>
35
36 //#include <cmath>
37 //using namespace std;
38
39 /*!
40   Constructor
41 */
42 GLViewer_MarkerSet::GLViewer_MarkerSet( int number, float size, const QString& toolTip ) :
43   GLViewer_Object(),
44   myNumber( 0 ),
45   myXCoord( 0 ),
46   myYCoord( 0 )       
47 {
48     
49     myMarkerSize = size;
50     myHNumbers.clear();
51     myUHNumbers.clear();
52     mySelNumbers.clear();
53     myUSelNumbers.clear();
54     myCurSelNumbers.clear();
55     myPrevHNumbers.clear();    
56
57     myType = "GLViewer_MarkerSet";
58     myToolTipText = toolTip;
59     
60     setNumMarkers( number );    
61 }
62
63 /*!
64   Destructor
65 */
66 GLViewer_MarkerSet::~GLViewer_MarkerSet()
67 {
68     if ( myXCoord )
69         delete[] myXCoord;
70     if ( myYCoord )
71         delete[] myYCoord;
72 }
73
74 /*!
75   Adds coords to text buffer in HPGL format
76   \param buffer - text buffer
77   \param command - command to be added with coords
78   \param aViewerCS - viewer co-ordinates system
79   \param aPaperCS - paper co-ordinates system
80   \param x - x co-ordinate
81   \param y - y co-ordinate
82   \param NewLine - adds new line to buffer
83 */
84 void AddCoordsToHPGL( QString& buffer, QString command, GLViewer_CoordSystem* aViewerCS, 
85                       GLViewer_CoordSystem* aPaperCS, double x, double y, bool NewLine = true )
86 {
87     if( aViewerCS && aPaperCS )
88         aViewerCS->transform( *aPaperCS, x, y );
89
90     QString temp = command + "%1, %2;";
91     buffer += temp.arg( x ).arg( y );
92     if( NewLine )
93         buffer += ";\n";
94 }
95
96 /*!
97   Adds coords to text buffer in PostScript format
98   \param buffer - text buffer
99   \param command - command to be added with coords
100   \param aViewerCS - viewer co-ordinates system
101   \param aPaperCS - paper co-ordinates system
102   \param x - x co-ordinate
103   \param y - y co-ordinate
104   \param NewLine - adds new line to buffer
105 */
106 void AddCoordsToPS( QString& buffer, QString command, GLViewer_CoordSystem* aViewerCS, 
107                     GLViewer_CoordSystem* aPaperCS, double x, double y, bool NewLine = true )
108 {
109     if( aViewerCS && aPaperCS )
110         aViewerCS->transform( *aPaperCS, x, y );
111
112     QString temp = "%1 %2 "+command;    
113     buffer += temp.arg( x ).arg( y );
114     if( NewLine )
115         buffer += "\n";
116 }
117
118 /*!
119   Adds line aspect description to text buffer in PostScript format
120   \param buffer - text buffer
121   \param anAspect - line aspect
122   \param aViewerCS - viewer co-ordinates system
123   \param aPaperCS - paper co-ordinates system
124 */
125 void AddLineAspectToPS( QString& buffer, GLViewer_AspectLine* anAspect, 
126                         GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPaperCS )
127 {
128     if( anAspect )
129     {
130         QColor col1, col2, col3;
131         anAspect->getLineColors( col1, col2, col3 );
132
133         float aWidth = anAspect->getLineWidth();
134         int aLineType = anAspect->getLineType();
135
136         QString temp = "%1 %2 %3 setrgbcolor\n";
137         double rr = 1 - double( col1.red() ) / 255.0, //color inverting
138                gg = 1 - double( col1.green() ) / 255.0,
139                bb = 1 - double( col1.blue() ) / 255.0;
140
141         buffer += temp.arg( rr ).arg( gg ).arg( bb );
142
143         double x_stretch, y_stretch;
144         aViewerCS->getStretching( *aPaperCS, x_stretch, y_stretch );
145         buffer += temp.arg( x_stretch * aWidth )+" setlinewidth\n";
146
147         if( aLineType==0 ) //solid
148             buffer += "[] 0 setdash\n";
149         else if( aLineType==1 ) //strip
150             buffer += "[2] 0 setdash\n";
151     }
152 }
153
154 #ifdef WIN32
155 /*!
156   Adds line aspect description EMF image
157   \param hDC - descriptor of EMF
158   \param anAspect - line aspect
159   \param aViewerCS - viewer co-ordinates system
160   \param aPaperCS - paper co-ordinates system
161 */
162 HPEN AddLineAspectToEMF( HDC hDC, GLViewer_AspectLine* anAspect, 
163                          GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPaperCS )
164 {
165     if( anAspect )
166     {
167         QColor col1, col2, col3;
168         anAspect->getLineColors( col1, col2, col3 );
169
170         double x_stretch, y_stretch;
171         aViewerCS->getStretching( *aPaperCS, x_stretch, y_stretch );
172
173         double aWidth = anAspect->getLineWidth()*x_stretch;
174         int aLineType = anAspect->getLineType();
175
176         return CreatePen( PS_SOLID, aWidth, RGB( 255-col1.red(), 255-col1.green(), 255-col1.blue() ) );
177     }
178     else
179         return NULL;
180 }
181 #endif
182
183 /*!
184   Saves to file PostScript set of markers
185   \param hFile - file instance
186   \param aViewerCS - viewer co-ordinates system
187   \param aPSCS - paper co-ordinates system
188 */
189 bool GLViewer_MarkerSet::translateToPS( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS )
190 {   
191     int noPoints = 20;
192
193     QString aBuffer = "newpath\n";
194
195     AddLineAspectToPS( aBuffer, getAspectLine(), aViewerCS, aPSCS );
196
197     for( int i=0; i<myNumber; i++ )
198     {       
199         aBuffer += "\n";
200
201         double x_stretch, y_stretch;
202         aViewerCS->getStretching( *aPSCS, x_stretch, y_stretch );
203
204         double x0 = myXCoord[i],
205                y0 = myYCoord[i],
206                r  = myMarkerSize,
207                x, y;
208
209         for( int j=0; j<=noPoints; j++ )
210         {
211             x = x0 + r*cos( double(j)*2*PI/double(noPoints) );
212             y = y0 + r*sin( double(j)*2*PI/double(noPoints) );          
213             if( j==0 )
214                 AddCoordsToPS( aBuffer, "moveto", aViewerCS, aPSCS, x, y, true );               
215             else
216                 AddCoordsToPS( aBuffer, "lineto", aViewerCS, aPSCS, x, y, true );
217         }
218     }
219     aBuffer+="closepath\nstroke\n";
220
221     hFile.write( aBuffer.toAscii() );
222
223     return true;
224 }
225
226 /*!
227   Saves to file HPGL set of markers
228   \param hFile - file instance
229   \param aViewerCS - viewer co-ordinates system
230   \param aHPGLCS - paper co-ordinates system
231 */
232 bool GLViewer_MarkerSet::translateToHPGL( QFile& hFile, GLViewer_CoordSystem* aViewerCS,
233                                        GLViewer_CoordSystem* aHPGLCS )
234 {
235     int noPoints = 20;
236     QString aBuffer;
237     for( int i=0; i<myNumber; i++ )
238     {
239         aBuffer = "";
240
241         double x_stretch, y_stretch;
242         aViewerCS->getStretching( *aHPGLCS, x_stretch, y_stretch );
243
244         double x0 = myXCoord[i],
245                y0 = myYCoord[i],
246                r  = myMarkerSize,
247                x, y;
248
249         AddCoordsToHPGL( aBuffer, "PA", aViewerCS, aHPGLCS, x0+r, y0 );
250         aBuffer+="PD;\n";
251         for( int j=1; j<=noPoints; j++ )
252         {
253             x = x0 + r*cos( double(j)*2*PI/double(noPoints) );
254             y = y0 + r*sin( double(j)*2*PI/double(noPoints) );
255             AddCoordsToHPGL( aBuffer, "PD", aViewerCS, aHPGLCS, x, y );
256         }
257         aBuffer+="PU;\n";
258
259         hFile.write( aBuffer.toAscii() );
260     }
261
262     return true;
263 }
264
265 #ifdef WIN32
266 /*!
267   Saves to EMF image set of markers
268   \param dc - EMF image descriptor
269   \param aViewerCS - viewer co-ordinates system
270   \param aEMFCS - paper co-ordinates system
271 */
272 bool GLViewer_MarkerSet::translateToEMF( HDC dc, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aEMFCS )
273 {
274     int noPoints = 20;
275     if( !aViewerCS || !aEMFCS )
276         return false;
277     
278     HPEN pen = AddLineAspectToEMF( dc, getAspectLine(), aViewerCS, aEMFCS );
279     HGDIOBJ old = SelectObject( dc, pen );
280
281     for( int i=0; i<myNumber; i++ )
282     {
283         double x0 = myXCoord[i],
284                y0 = myYCoord[i],
285                r  = myMarkerSize,
286                x, y;
287
288         for( int j=0; j<=noPoints; j++ )
289         {
290             x = x0 + r*cos( double(j)*2*PI/double(noPoints) );
291             y = y0 + r*sin( double(j)*2*PI/double(noPoints) );
292             aViewerCS->transform( *aEMFCS, x, y );
293             if( j==0 )
294                 MoveToEx( dc, x, y, NULL );
295             else
296                 LineTo( dc, x, y );
297         }
298     }
299
300     SelectObject( dc, old );
301     if( pen )
302         DeleteObject( pen );
303     return true;
304 }
305 #endif
306
307 /*! 
308   Computes all necessary information about object for presentation in drawer
309 */
310 void GLViewer_MarkerSet::compute()
311 {
312 //  cout << "GLViewer_MarkerSet::compute" << endl;
313   GLfloat xa = myXCoord[0]; 
314   GLfloat xb = myXCoord[0]; 
315   GLfloat ya = myYCoord[0]; 
316   GLfloat yb = myYCoord[0]; 
317
318   for ( int i = 0; i < myNumber; i++ )  
319   {
320     xa = qMin( xa, myXCoord[i] );
321     xb = qMax( xb, myXCoord[i] );
322     ya = qMin( ya, myYCoord[i] );
323     yb = qMax( yb, myYCoord[i] );
324   }
325   
326   myXGap = ( xb - xa ) / 10;
327   myYGap = ( yb - ya ) / 10;
328
329   myRect->setLeft( xa - myXGap );
330   myRect->setTop( yb + myYGap ); 
331   myRect->setRight( xb + myXGap );
332   myRect->setBottom( ya - myYGap );
333 }
334
335 /*!
336   Creates corresponding drawer
337 */
338 GLViewer_Drawer* GLViewer_MarkerSet::createDrawer()
339 {
340 //  cout << "GLViewer_MarkerSet::createDrawer" << endl;
341   return myDrawer = new GLViewer_MarkerDrawer();
342 }
343
344 /*!
345   Computes highlight presentation
346   \param x        - x coord
347   \param y        - y coord
348   \param tol      - tolerance of detecting
349   \param isCircle - true if sensitive area of detection is round
350   \return true if highlight status is changed
351 */
352 GLboolean GLViewer_MarkerSet::highlight( GLfloat x, GLfloat y, GLfloat tol, GLboolean isCircle )
353 {
354     if( !myIsVisible )
355         return false;
356 //  cout << "GLViewer_MarkerSet::highlight " << x <<" " << y << " " << tol << endl;
357   int count = 0;
358   GLfloat xdist, ydist, radius;
359   QList<int>::Iterator it;
360   QList<int> curHNumbers;
361   bool isFound;
362   GLboolean update;
363   int cnt = 0;
364
365   radius = tol - myMarkerSize / 2.;
366   
367   myUHNumbers += myHNumbers;
368   myHNumbers.clear();
369
370   for ( int i = 0; i < myNumber; i++ ) 
371   {
372     xdist = ( myXCoord[i] - x ) * myXScale;
373     ydist = ( myYCoord[i] - y ) * myYScale;
374
375 //    if ( isCircle && ( xdist * xdist + ydist * ydist <= radius * radius ) ||
376     if ( isCircle && ( xdist * xdist + ydist * ydist <= myMarkerSize * myMarkerSize ) ||
377     !isCircle && ( fabs( xdist ) <= radius && fabs( ydist ) <= radius ) )
378     {
379       isFound = FALSE;
380       count++;
381       for ( it = myCurSelNumbers.begin(); it != myCurSelNumbers.end(); ++it )
382         if( i == *it )
383         {
384           isFound = TRUE;
385           curHNumbers.append( i );
386         }
387       
388       if( !isFound )
389           myHNumbers.append( i );
390       else
391         cnt++;
392     }
393   }
394   myCurSelNumbers = curHNumbers;
395
396   myIsHigh = ( GLboolean )count;
397   update = ( GLboolean )( myHNumbers != myPrevHNumbers );
398
399   myPrevHNumbers = myHNumbers;
400
401   //cout << "GLViewer_MarkerSet::highlight complete with " << (int)myIsHigh << endl;
402   return update;
403 }
404
405 /*!
406   Unhilights object
407 */
408 GLboolean GLViewer_MarkerSet::unhighlight()
409 {
410   if( !myHNumbers.isEmpty() )
411   {
412     myUHNumbers += myHNumbers;
413     myPrevHNumbers.clear();
414     myHNumbers.clear();
415     //??? myCurSelNumbers.clear();
416     return GL_TRUE;
417   }
418   
419   return GL_FALSE;
420 }
421
422 /*!
423   Selects marker set
424   /param x, y - co-ordinates of mouse
425   /param tol - tolerance
426   /param rect - rectangle (in case of rectangular selection)
427   /param isFull - if it is true, then object may selected only if it lays whole in selection zone
428   \param isCircle - true if sensitive area of detection is round
429   \param isShift  - true if selection exec with append option
430 */
431 GLboolean GLViewer_MarkerSet::select( GLfloat x, GLfloat y, GLfloat tol, GLViewer_Rect rect, GLboolean isFull,
432                                       GLboolean isCircle, GLboolean isShift )
433 {
434     if( !myIsVisible )
435         return false;
436 //  cout << "GLViewer_MarkerSet::select " << x << " " << y << endl;
437   int count = 0;
438   GLfloat xdist, ydist, radius;
439   QList<int>::Iterator it;
440   QList<int>::Iterator it1;
441   QList<int>::Iterator remIt;
442   QList<int>::Iterator curIt;
443
444   radius = tol - myMarkerSize / 2.;
445
446   if( radius < myMarkerSize / 2.)
447     radius = myMarkerSize / 2.;
448
449   count = isShift ? mySelNumbers.count() : 0;
450
451   myUSelNumbers = mySelNumbers;
452
453   if ( !isShift )
454   {
455     mySelNumbers.clear();
456     myCurSelNumbers.clear();
457   }
458
459   for ( int i = 0; i < myNumber; i++ ) 
460   {
461     xdist = ( myXCoord[i] - x ) * myXScale;
462     ydist = ( myYCoord[i] - y ) * myYScale;
463
464     //if ( isCircle && ( xdist * xdist + ydist * ydist <= radius * radius ) ||
465     if ( isCircle && ( xdist * xdist + ydist * ydist <= myMarkerSize * myMarkerSize ) ||
466           !isCircle && ( fabs( xdist ) <= radius && fabs( ydist ) <= radius ) )
467     {
468       count++;
469       if ( isShift )
470       {
471         bool isFound = FALSE;
472           for( it = mySelNumbers.begin(); it != mySelNumbers.end(); ++it )
473             if ( *it == i )
474             {
475               myUSelNumbers.append( *it );
476             remIt = it;
477               isFound = TRUE;
478               break;
479             }
480
481           if ( !isFound )
482         {
483           mySelNumbers.append( i );
484             myCurSelNumbers.append( i );
485             for ( it1 = myHNumbers.begin(); it1 != myHNumbers.end(); ++it1 )
486               if( i == *it1 )
487               {
488                 myHNumbers.erase( it1 );
489                 break;
490               }
491       for ( it1 = myUHNumbers.begin(); it1 != myUHNumbers.end(); ++it1 )
492         if( i == *it1 )
493         {
494           myUHNumbers.erase( it1 );
495           break;
496         }
497         }
498     else
499         {
500       mySelNumbers.erase( remIt );
501       for ( curIt = myCurSelNumbers.begin(); curIt != myCurSelNumbers.end(); ++curIt )
502         if( *curIt == *remIt)
503         {
504           myCurSelNumbers.erase( curIt );
505           break;
506         }
507       for ( it1 = myHNumbers.begin(); it1 != myHNumbers.end(); ++it1 )
508         if( i == *it1 )
509         {
510           myHNumbers.erase( it1 );
511           break;
512         }
513       for ( it1 = myUHNumbers.begin(); it1 != myUHNumbers.end(); ++it1 )
514         if( i == *it1 )
515         {
516           myUHNumbers.erase( it1 );
517           break;
518         }
519         }
520       }
521       else
522       {
523     mySelNumbers.append( i );
524     myCurSelNumbers.append( i );
525     for ( it1 = myHNumbers.begin(); it1 != myHNumbers.end(); ++it1 )
526       if( i == *it1 )
527       {
528         myHNumbers.erase( it1 );
529         break;
530       }
531     for ( it1 = myUHNumbers.begin(); it1 != myUHNumbers.end(); ++it1 )
532       if( i == *it1 )
533           {
534         myUHNumbers.erase( it1 );
535         break;
536       }        
537       }     
538     }
539   }
540
541   for( it = mySelNumbers.begin(); it != mySelNumbers.end(); ++it )
542     for( it1 = myUSelNumbers.begin(); it1 != myUSelNumbers.end(); ++it1 )
543       if( *it == *it1 )
544       {
545         it1 = myUSelNumbers.erase( it1 );
546         it1--;
547       }
548   
549   myIsSel = (GLboolean)count;
550
551 //  cout << "GLViewer_MarkerSet::select complete with " << (int)myIsSel << endl;
552   return myIsSel;
553 }
554
555 /*!
556   Unselects marker set
557 */
558 GLboolean GLViewer_MarkerSet::unselect()
559 {
560   if( !mySelNumbers.isEmpty() )
561   {
562     myUSelNumbers = mySelNumbers;
563     mySelNumbers.clear();
564     myCurSelNumbers.clear();
565     return GL_TRUE;
566   }
567
568   return GL_FALSE;
569 }
570
571 /*!
572   \return update object rectangle
573   Does not equal getRect() if object have a persistence to some viewer transformations
574 */
575 GLViewer_Rect* GLViewer_MarkerSet::getUpdateRect()
576 {
577   GLViewer_Rect* rect = new GLViewer_Rect();
578   
579   rect->setLeft( myRect->left() + myXGap - myMarkerSize / myXScale );
580   rect->setTop( myRect->top() + myYGap + myMarkerSize / myYScale ); 
581   rect->setRight( myRect->right() - myXGap + myMarkerSize / myXScale );
582   rect->setBottom( myRect->bottom() - myYGap - myMarkerSize / myYScale );
583   //cout << " Additional tolerance " << myMarkerSize / myYScale << endl;
584   //rect->setLeft( myRect->left() - myMarkerSize / myXScale );
585   //rect->setTop( myRect->top() - myMarkerSize / myYScale ); 
586   //rect->setRight( myRect->right() + myMarkerSize / myXScale );
587   //rect->setBottom( myRect->bottom() + myMarkerSize / myYScale );
588   
589   return rect;
590 }
591
592 /*!
593   Sets array of x coords of points
594   \param xCoord - array of co-ordinates
595   \param size - array size
596 */
597 void GLViewer_MarkerSet::setXCoord( GLfloat* xCoord, int size )
598 {
599   myXCoord = new GLfloat[ size ];
600   for( int i = 0; i < size; i++ )
601      myXCoord[i] = xCoord[i];
602 }
603
604 /*!
605   Sets array of y coords of points
606   \param yCoord - array of co-ordinates
607   \param size - array size
608 */
609 void GLViewer_MarkerSet::setYCoord( GLfloat* yCoord, int size )
610 {
611   myYCoord = new GLfloat[ size ];
612   for( int i = 0; i < size; i++ )
613      myYCoord[i] = yCoord[i];
614 }
615
616 /*!
617   Sets number of markers
618   \param number - new number of markers
619 */
620 void GLViewer_MarkerSet::setNumMarkers( GLint number )
621 {
622   if ( myNumber == number )
623     return;
624     
625   if ( myXCoord && myYCoord )
626   {
627     delete[] myXCoord;
628     delete[] myYCoord;
629   }
630
631   myNumber = number;
632   myXCoord = new GLfloat[ myNumber ];
633   myYCoord = new GLfloat[ myNumber ];
634 }
635
636
637 /*!
638   Export numbers of highlighted/selected lines
639 */
640 void GLViewer_MarkerSet::exportNumbers( QList<int>& highlight,
641                      QList<int>& unhighlight,
642                      QList<int>& select,
643                      QList<int>& unselect )
644 {
645     highlight = myHNumbers;
646     unhighlight = myUHNumbers;
647     select = mySelNumbers;
648     unselect = myUSelNumbers;
649
650     myUHNumbers = myHNumbers;
651 }
652
653 /*!
654   Adds or remove selected number
655   \param index - selected index
656 */
657 bool GLViewer_MarkerSet::addOrRemoveSelected( int index )
658 {
659   if( index < 0 || index > myNumber )
660     return FALSE;
661
662   int n = mySelNumbers.indexOf( index );
663   if( n == -1 )
664     mySelNumbers.append( index );
665   else
666   {
667     mySelNumbers.removeAt(n);
668     myUSelNumbers.append( index );
669   }
670   return TRUE;
671 }
672
673 /*!
674   Adds some selected numbers
675   \param seq - sequence of indices
676 */
677 void GLViewer_MarkerSet::addSelected( const TColStd_SequenceOfInteger& seq )
678 {
679   for ( int i = 1; i <= seq.Length(); i++ )
680     if( mySelNumbers.indexOf( seq.Value( i ) ) == -1 )
681       mySelNumbers.append( seq.Value( i ) - 1 );
682 }
683
684 /*!
685   Sets some numbers as selected
686   \param seq - sequence of indices
687 */
688 void GLViewer_MarkerSet::setSelected( const TColStd_SequenceOfInteger& seq )
689 {
690 //   for( QList<int>::Iterator it = mySelNumbers.begin(); it != mySelNumbers.end(); ++it )
691 //     if( myUSelNumbers.findIndex( *it ) == -1 )
692 //       myUSelNumbers.append( *it );
693
694   myUSelNumbers = mySelNumbers;
695   mySelNumbers.clear();
696     
697   for ( int i = 1; i <= seq.Length(); i++ )
698     mySelNumbers.append( seq.Value( i ) - 1 );
699 }
700
701 /*! Moves object by recomputing
702   \param dx        - moving along X coord
703   \param dy        - moving along Y coord
704   \param fromGroup - is true if this method called from group
705 */
706 void GLViewer_MarkerSet::moveObject( float theX, float theY, bool fromGroup )
707 {
708     if( !fromGroup && myGroup)
709     {
710       myGroup->dragingObjects( theX, theY );
711       return;
712     }
713     for( int i = 0; i < myNumber;  i++ )
714     {
715         myXCoord[i] = myXCoord[i] + theX;
716         myYCoord[i] = myYCoord[i] + theY;
717     }
718     compute();    
719 }
720
721 /*!
722   Codes marker set as byte copy
723   \return byte array
724 */
725 QByteArray GLViewer_MarkerSet::getByteCopy()
726 {
727     int i = 0;
728     int anISize = sizeof( GLint );
729     int aFSize = sizeof( GLfloat );
730     
731     QByteArray aObject = GLViewer_Object::getByteCopy();
732
733     QByteArray aResult;
734     aResult.resize( anISize + 2*aFSize*myNumber + aFSize + aObject.size());
735
736     char* aPointer = (char*)&myNumber;
737     for( i = 0; i < anISize; i++, aPointer++ )
738         aResult[i] = *aPointer;
739
740     aPointer = (char*)myXCoord;
741     for( ; i < anISize + aFSize*myNumber; i++, aPointer++ )
742         aResult[i] = *aPointer;
743     aPointer = (char*)myYCoord;
744     for( ; i < anISize + 2*aFSize*myNumber; i++, aPointer++ )
745         aResult[i] = *aPointer;
746     
747     aPointer = (char*)&myMarkerSize;
748     for( ; i < anISize + 2*aFSize*myNumber + aFSize; i++, aPointer++ )
749         aResult[i] = *aPointer;
750         
751     
752     for ( ; i < (int)aResult.size(); i++ )
753         aResult[i] = aObject[i - anISize - 2*aFSize*myNumber - aFSize];
754
755     return aResult;
756 }
757
758 /*!
759   Initialize marker set by byte array
760   \param theArray - byte array
761 */
762 bool GLViewer_MarkerSet::initializeFromByteCopy( QByteArray theArray )
763 {
764     int i = 0;
765     int anISize = sizeof( GLint );
766     int aFSize = sizeof( GLfloat );
767
768     char* aPointer = (char*)&myNumber;
769     for( i = 0; i < anISize; i++, aPointer++ )
770         *aPointer = theArray[i];
771
772     int aSize = theArray.size();
773     if( aSize < anISize + 2*aFSize*myNumber + aFSize)
774         return false;
775
776     myXCoord = new GLfloat[myNumber];
777     myYCoord = new GLfloat[myNumber];
778     aPointer = (char*)myXCoord;
779     for( ; i < anISize + aFSize*myNumber; i++, aPointer++ )
780         *aPointer = theArray[i];
781     aPointer = (char*)myYCoord;
782     for( ; i < anISize + 2*aFSize*myNumber; i++, aPointer++ )
783         *aPointer = theArray[i];
784
785     aPointer = (char*)&myMarkerSize;
786     for( ; i < anISize + 2*aFSize*myNumber + aFSize; i++, aPointer++ )
787          *aPointer = theArray[i];
788          
789     int aCurIndex = anISize + 2*aFSize*myNumber + aFSize;
790     QByteArray aObject;
791     aObject.resize( aSize - aCurIndex );
792     for( ; i < aSize; i++ )
793         aObject[i - aCurIndex] = theArray[i];
794         
795
796     if( !GLViewer_Object::initializeFromByteCopy( aObject ) || myType != "GLViewer_MarkerSet" )
797         return false;
798
799     myHNumbers.clear();
800     myUHNumbers.clear();
801     mySelNumbers.clear();
802     myUSelNumbers.clear();
803     myCurSelNumbers.clear();
804     myPrevHNumbers.clear();
805
806     return true;        
807 }
808
809 /*!
810   \class GLViewer_Polyline
811   OpenGL Polyline
812 */
813
814 #define SECTIONS 100
815 #define DISTANTION 5
816
817 /*!
818   Constructor
819   \param number - number of segments
820   \param size - size of polyline
821   \param toolTip - tool tip of polyline
822 */
823 GLViewer_Polyline::GLViewer_Polyline( int number, float size, const QString& toolTip ):
824   GLViewer_Object(),
825   myNumber( 0 ),
826   myXCoord( 0 ),
827   myYCoord( 0 )       
828 {
829   myHighFlag = GL_TRUE;
830
831   myHNumbers.clear();
832   myUHNumbers.clear();
833   mySelNumbers.clear();
834   myUSelNumbers.clear();
835   myCurSelNumbers.clear();
836   myPrevHNumbers.clear();
837
838   setNumber( number );
839
840   myType = "GLViewer_Polyline";
841   myToolTipText = toolTip;
842 }
843
844 /*!
845   Destructor, destroys internal arrays of co-ordinates
846 */
847 GLViewer_Polyline::~GLViewer_Polyline()
848 {
849   if ( myXCoord )
850     delete[] myXCoord;
851   if ( myYCoord )
852     delete[] myYCoord;
853 }
854
855 /*!
856   Saves polyline to file PostScript
857   \param hFile - file instance
858   \param aViewerCS - viewer co-ordinates system
859   \param aPSCS - paper co-ordinates system
860 */
861 bool GLViewer_Polyline::translateToPS( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS )
862 {
863     QString aBuffer = "newpath\n";
864
865     AddLineAspectToPS( aBuffer, getAspectLine(), aViewerCS, aPSCS );
866
867     for( int i=0; i<myNumber; i++ )
868         if( i==0 )
869             AddCoordsToPS( aBuffer, "moveto", aViewerCS, aPSCS, myXCoord[i], myYCoord[i] );
870         else
871             AddCoordsToPS( aBuffer, "lineto", aViewerCS, aPSCS, myXCoord[i], myYCoord[i] );
872
873     if( myIsClosed )
874         AddCoordsToPS( aBuffer, "lineto", aViewerCS, aPSCS, myXCoord[0], myYCoord[0] );
875
876     aBuffer+="closepath\nstroke\n";
877     
878     hFile.write( aBuffer.toAscii() );
879
880     return true;
881 }
882
883 /*!
884   Saves polyline to file HPGL
885   \param hFile - file instance
886   \param aViewerCS - viewer co-ordinates system
887   \param aHPGLCS - paper co-ordinates system
888 */
889 bool GLViewer_Polyline::translateToHPGL( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aHPGLCS )
890 {
891     QString aBuffer = "";
892     for( int i=0; i<myNumber; i++ )
893     {
894         AddCoordsToHPGL( aBuffer, "PA", aViewerCS, aHPGLCS, myXCoord[i], myYCoord[i] );
895         if( i==0 )
896             aBuffer+="PD;\n";
897     }
898
899     if( myIsClosed )
900         AddCoordsToHPGL( aBuffer, "PA", aViewerCS, aHPGLCS, myXCoord[0], myYCoord[0] );
901
902     aBuffer+="PU;\n";
903     
904     hFile.write( aBuffer.toAscii() );
905
906     return true;
907 }
908
909 #ifdef WIN32
910 /*!
911   Saves polyline to EMF image
912   \param dc - EMF image descriptor
913   \param aViewerCS - viewer co-ordinates system
914   \param aEMFCS - paper co-ordinates system
915 */
916 bool GLViewer_Polyline::translateToEMF( HDC dc, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aEMFCS )
917 {
918     if( !aViewerCS || !aEMFCS )
919         return false;
920     
921     HPEN pen = AddLineAspectToEMF( dc, getAspectLine(), aViewerCS, aEMFCS );
922     HGDIOBJ old = SelectObject( dc, pen );
923
924     double x, y;
925     for( int i=0; i<myNumber; i++ )
926     {
927         x = myXCoord[i];
928         y = myYCoord[i];
929         aViewerCS->transform( *aEMFCS, x, y );
930         if( i==0 )
931             MoveToEx( dc, x, y, NULL );
932         else
933             LineTo( dc, x, y );
934     }
935
936     if( myIsClosed )
937     {
938         x = myXCoord[0];
939         y = myYCoord[0];
940         aViewerCS->transform( *aEMFCS, x, y );
941         LineTo( dc, x, y );
942     }
943
944     SelectObject( dc, old );
945     if( pen )
946         DeleteObject( pen );
947
948     return true;
949 }
950 #endif
951
952 /*! 
953   Computes all necessary information about object for presentation in drawer
954 */
955 void GLViewer_Polyline::compute()
956 {
957 //  cout << "GLViewer_MarkerSet::compute" << endl;
958   GLfloat xa = myXCoord[0]; 
959   GLfloat xb = myXCoord[0]; 
960   GLfloat ya = myYCoord[0]; 
961   GLfloat yb = myYCoord[0]; 
962
963   for ( int i = 0; i < myNumber; i++ )  
964   {
965     xa = qMin( xa, myXCoord[i] );
966     xb = qMax( xb, myXCoord[i] );
967     ya = qMin( ya, myYCoord[i] );
968     yb = qMax( yb, myYCoord[i] );
969   }
970
971   GLfloat xGap = ( xb - xa ) / 10;
972   GLfloat yGap = ( yb - ya ) / 10;
973
974   myRect->setLeft( xa - xGap );
975   myRect->setTop( yb + yGap ); 
976   myRect->setRight( xb + xGap );
977   myRect->setBottom( ya - yGap );
978 }
979
980 /*!
981   \return update object rectangle
982   Does not equal getRect() if object have a persistence to some viewer transformations
983 */
984 GLViewer_Rect* GLViewer_Polyline::getUpdateRect()
985 {
986     GLViewer_Rect* rect = new GLViewer_Rect();
987
988     rect->setLeft( myRect->left() - myXGap );
989     rect->setTop( myRect->top() + myYGap ); 
990     rect->setRight( myRect->right() + myXGap );
991     rect->setBottom( myRect->bottom() - myYGap );
992
993     return rect;
994 }
995
996 /*!
997   Creates corresponding drawer
998 */
999 GLViewer_Drawer* GLViewer_Polyline::createDrawer()
1000 {
1001 //  cout << "GLViewer_MarkerSet::createDrawer" << endl;
1002     return myDrawer = new GLViewer_PolylineDrawer();
1003 }
1004
1005 /*!
1006   Computes highlight presentation
1007   \param x        - x coord
1008   \param y        - y coord
1009   \param tol      - tolerance of detecting
1010   \param isCircle - true if sensitive area of detection is round
1011   \return true if highlight status is changed
1012 */
1013 GLboolean GLViewer_Polyline::highlight( GLfloat x, GLfloat y, GLfloat tol, GLboolean isCircle )
1014 {
1015     if( !myIsVisible )
1016         return false;
1017     GLfloat xa, xb, ya, yb, l;
1018     GLfloat rsin, rcos, r, ra, rb;
1019     GLboolean update;
1020     GLboolean highlighted = myIsHigh;
1021
1022     myIsHigh = GL_FALSE;
1023
1024     int c = 0;
1025     if( myIsClosed )
1026         c = 1;
1027
1028     for( int i = 0; i < myNumber-1+c; i++ ) 
1029     {
1030         xa = myXCoord[i];
1031         ya = myYCoord[i];
1032         if( i != myNumber-1 )
1033         {
1034               xb = myXCoord[i+1];
1035               yb = myYCoord[i+1];
1036         }
1037         else
1038         {    
1039               xb = myXCoord[0];      
1040               yb = myYCoord[0];
1041         }
1042
1043         l = sqrt( (xb-xa)*(xb-xa) + (yb-ya)*(yb-ya) );
1044         rsin = (yb-ya) / l;
1045         rcos = (xb-xa) / l;
1046         r = ( (x-xa)*(y-yb) - (x-xb)*(y-ya) ) / ( rsin*(ya-yb) + rcos*(xa-xb) );
1047         ra = sqrt( (x-xa)*(x-xa) + (y-ya)*(y-ya) );
1048         rb = sqrt( (x-xb)*(x-xb) + (y-yb)*(y-yb) );
1049         if( fabs( r ) * myXScale <= DISTANTION && ra <= l + DISTANTION && rb <= l + DISTANTION )
1050         {
1051             myIsHigh = GL_TRUE;
1052             break;
1053         }
1054     }
1055
1056     if( !myHighFlag && myIsHigh )
1057         myIsHigh = GL_FALSE;
1058     else
1059         myHighFlag = GL_TRUE;
1060
1061     update = ( GLboolean )( myIsHigh != highlighted );
1062
1063 //  cout << "GLViewer_Polyline::highlight complete with " << (int)myIsHigh << endl;
1064     return update;
1065 }
1066
1067 /*!
1068   Unhilights object
1069 */
1070 GLboolean GLViewer_Polyline::unhighlight()
1071 {
1072 //   if( !myHNumbers.isEmpty() )
1073 //   {
1074 //     myUHNumbers = myHNumbers;
1075 //     myHNumbers.clear();
1076 //     return GL_TRUE;
1077 //   }
1078
1079   if( myIsHigh )
1080   {
1081     myIsHigh = GL_FALSE;
1082     return GL_TRUE;
1083   }
1084
1085   return GL_FALSE;
1086 }
1087
1088 /*!
1089   Selects polyline
1090   /param x, y - co-ordinates of mouse
1091   /param tol - tolerance
1092   /param rect - rectangle (in case of rectangular selection)
1093   /param isFull - if it is true, then object may selected only if it lays whole in selection zone
1094   \param isCircle - true if sensitive area of detection is round
1095   \param isShift  - true if selection exec with append option
1096 */
1097 GLboolean GLViewer_Polyline::select( GLfloat x, GLfloat y, GLfloat tol, GLViewer_Rect rect, GLboolean isFull,
1098                                      GLboolean isCircle, GLboolean isShift )
1099 {
1100     if( !myIsVisible )
1101         return false;
1102     GLfloat xa, xb, ya, yb, l;
1103     GLfloat rsin, rcos, r, ra, rb;
1104     GLboolean update;
1105     GLboolean selected = myIsSel;
1106
1107     myIsSel = GL_FALSE;
1108
1109     int c = 0;
1110     if( myIsClosed )
1111         c = 1;
1112
1113     for( int i = 0; i < myNumber-1+c; i++ ) 
1114     {
1115         xa = myXCoord[i];
1116         ya = myYCoord[i];
1117         if( i != myNumber-1 )
1118         {
1119             xb = myXCoord[i+1];
1120             yb = myYCoord[i+1];
1121         }
1122         else
1123         {
1124             xb = myXCoord[0];
1125             yb = myYCoord[0];
1126         }
1127
1128         l = sqrt( (xb-xa)*(xb-xa) + (yb-ya)*(yb-ya) );
1129         rsin = (yb-ya) / l;
1130         rcos = (xb-xa) / l;
1131         r = ( (x-xa)*(y-yb) - (x-xb)*(y-ya) ) / ( rsin*(ya-yb) + rcos*(xa-xb) );
1132         ra = sqrt( (x-xa)*(x-xa) + (y-ya)*(y-ya) );
1133         rb = sqrt( (x-xb)*(x-xb) + (y-yb)*(y-yb) );
1134         if( fabs( r ) * myXScale <= DISTANTION && ra <= l + DISTANTION && rb <= l + DISTANTION )
1135         {
1136             myIsSel = GL_TRUE;
1137             break;
1138         }
1139     }
1140
1141     if ( myIsSel )
1142     {
1143         myHighFlag = GL_FALSE;
1144         myIsHigh = GL_FALSE;
1145     }
1146     else
1147         myHighFlag = GL_TRUE;
1148
1149     update = ( GLboolean )( myIsSel != selected );
1150
1151     //  cout << "GLViewer_Polyline::select complete with " << (int)myIsSel << endl;
1152
1153     //  return update;  !!!!!!!!!!!!!!!!!!!!!!!!!!! no here
1154     return myIsSel;
1155 }
1156
1157 /*!
1158   Unselects polyline
1159 */
1160 GLboolean GLViewer_Polyline::unselect()
1161 {
1162 //   if( !mySelNumbers.isEmpty() )
1163 //   {
1164 //     myUSelNumbers = mySelNumbers;
1165 //     mySelNumbers.clear();
1166 //     myCurSelNumbers.clear();
1167 //     return GL_TRUE;
1168 //   }
1169
1170   if( myIsSel )
1171   {
1172     myIsSel = GL_FALSE;
1173     return GL_TRUE;
1174   }
1175
1176   return GL_FALSE;
1177 }
1178
1179 /*!
1180   Sets array of abscisses for points of polyline
1181   \param xCoord - array of of abscisses
1182   \param size - size of array
1183 */
1184 void GLViewer_Polyline::setXCoord( GLfloat* xCoord, int size )
1185 {
1186   myXCoord = new GLfloat[ size ];
1187   for( int i = 0; i < size; i++ )
1188      myXCoord[i] = xCoord[i];
1189 }
1190
1191 /*!
1192   Sets array of ordinates for points of polyline
1193   \param xCoord - array of of ordinates
1194   \param size - size of array
1195 */
1196 void GLViewer_Polyline::setYCoord( GLfloat* yCoord, int size )
1197 {
1198   myYCoord = new GLfloat[ size ];
1199   for( int i = 0; i < size; i++ )
1200      myYCoord[i] = yCoord[i];
1201 }
1202
1203 /*!
1204   Sets number of points
1205   \param number - new number of points
1206 */
1207 void GLViewer_Polyline::setNumber( GLint number )
1208 {
1209   if ( myNumber == number )
1210     return;
1211     
1212   if ( myXCoord && myYCoord )
1213   {
1214     delete[] myXCoord;
1215     delete[] myYCoord;
1216   }
1217
1218   myNumber = number;
1219   myXCoord = new GLfloat[ myNumber ];
1220   myYCoord = new GLfloat[ myNumber ];
1221 }
1222
1223 /*!
1224   Export numbers of highlighted/selected lines
1225 */
1226 void GLViewer_Polyline::exportNumbers( QList<int>& highlight,
1227                      QList<int>& unhighlight,
1228                      QList<int>& select,
1229                      QList<int>& unselect )
1230 {
1231   highlight = myHNumbers;
1232   unhighlight = myUHNumbers;
1233   select = mySelNumbers;
1234   unselect = myUSelNumbers;
1235 }
1236
1237 /*!
1238   Moves object by recomputing
1239   \param dx        - moving along X coord
1240   \param dy        - moving along Y coord
1241   \param fromGroup - is true if this method called from group
1242 */
1243 void GLViewer_Polyline::moveObject( float theX, float theY, bool fromGroup )
1244 {
1245   if( !fromGroup && myGroup)
1246   {
1247     myGroup->dragingObjects( theX, theY );
1248     return;
1249   }
1250   for( int i = 0; i < myNumber;  i++ )
1251   {
1252       myXCoord[i] = myXCoord[i] + theX;
1253       myYCoord[i] = myYCoord[i] + theY;
1254   }
1255   compute();    
1256 }
1257
1258 /*!
1259   Codes polyline as byte copy
1260   \return byte array
1261 */
1262 QByteArray GLViewer_Polyline::getByteCopy()
1263 {
1264     int i = 0;
1265     int anISize = sizeof( GLint );
1266     int aFSize = sizeof( GLfloat );
1267     int aBSize = sizeof( GLboolean );
1268
1269     QByteArray aObject = GLViewer_Object::getByteCopy();
1270
1271     QByteArray aResult;
1272     aResult.resize( aFSize*myNumber*2 + anISize + 2*aBSize + aObject.size());
1273
1274     char* aPointer = (char*)&myNumber;
1275     for( i = 0; i < anISize; i++, aPointer++ )
1276         aResult[i] = *aPointer;
1277
1278     aPointer = (char*)myXCoord;
1279     for( ; i < anISize + aFSize*myNumber; i++, aPointer++ )
1280         aResult[i] = *aPointer;
1281     aPointer = (char*)myYCoord;
1282     for( ; i < anISize + 2*aFSize*myNumber; i++, aPointer++ )
1283         aResult[i] = *aPointer;
1284     
1285     aPointer = (char*)&myIsClosed;
1286     for( ; i < anISize + 2*aFSize*myNumber + aBSize; i++, aPointer++ )
1287         aResult[i] = *aPointer;
1288     aPointer = (char*)&myHighSelAll;
1289     for( ; i < anISize + 2*aFSize*myNumber + 2*aBSize; i++, aPointer++ )
1290         aResult[i] = *aPointer;
1291
1292     for ( ; i < (int)aResult.size(); i++ )
1293         aResult[i] = aObject[i - anISize - 2*aFSize*myNumber - 2*aBSize];
1294
1295     return aResult;
1296 }
1297
1298
1299 /*!
1300   Initialize polyline by byte array
1301   \param theArray - byte array
1302 */
1303 bool GLViewer_Polyline::initializeFromByteCopy( QByteArray theArray )
1304 {
1305     int i = 0;
1306     int anISize = sizeof( GLint );
1307     int aFSize = sizeof( GLfloat );
1308     int aBSize = sizeof( GLboolean );
1309
1310     char* aPointer = (char*)&myNumber;
1311     for( i = 0; i < anISize; i++, aPointer++ )
1312         *aPointer = theArray[i];
1313
1314     int aSize = theArray.size();
1315     if( aSize < aFSize*myNumber*2 + anISize + 2*aBSize )
1316         return false;
1317
1318     myXCoord = new GLfloat[myNumber];
1319     myYCoord = new GLfloat[myNumber];
1320     aPointer = (char*)myXCoord;
1321     for( ; i < anISize + aFSize*myNumber; i++, aPointer++ )
1322         *aPointer = theArray[i];
1323     aPointer = (char*)myYCoord;
1324     for( ; i < anISize + 2*aFSize*myNumber; i++, aPointer++ )
1325         *aPointer = theArray[i];
1326
1327     aPointer = (char*)&myIsClosed;
1328     for( ; i < anISize + 2*aFSize*myNumber + aBSize; i++, aPointer++ )
1329          *aPointer = theArray[i];
1330     aPointer = (char*)&myHighSelAll;
1331     for( ; i < anISize + 2*aFSize*myNumber + 2*aBSize; i++, aPointer++ )
1332          *aPointer = theArray[i];
1333
1334     int aCurIndex = anISize + 2*aFSize*myNumber + 2*aBSize;
1335     QByteArray aObject;
1336     aObject.resize( aSize - aCurIndex );
1337     for( ; i < aSize; i++ )
1338         aObject[i - aCurIndex] = theArray[i];
1339
1340     if( !GLViewer_Object::initializeFromByteCopy( aObject ) || myType != "GLViewer_Polyline" )
1341         return false;
1342
1343     myHNumbers.clear();
1344     myUHNumbers.clear();
1345     mySelNumbers.clear();
1346     myUSelNumbers.clear();
1347     myCurSelNumbers.clear();
1348     myPrevHNumbers.clear();
1349
1350     return true;        
1351 }
1352
1353
1354
1355 /*!
1356   Constructor
1357   \param theStr - text string
1358   \param xPos - x position
1359   \param yPos - y position
1360   \param color - color of text
1361   \param toolTip - tooltip of text object
1362 */
1363 GLViewer_TextObject::GLViewer_TextObject( const QString& theStr, float xPos, float yPos, 
1364                                     const QColor& color, const QString& toolTip )
1365                                     : GLViewer_Object()
1366 {
1367     myGLText = new GLViewer_Text( theStr, xPos, yPos, color );
1368     myWidth = 0;
1369     myHeight = 0;
1370
1371     myHighFlag = GL_TRUE;
1372
1373     myToolTipText = toolTip;
1374 }
1375
1376 /*!
1377   Destructor
1378 */
1379 GLViewer_TextObject::~GLViewer_TextObject()
1380 {
1381   if ( myGLText )
1382     delete myGLText;
1383 }
1384
1385 /*!
1386   Saves text object to file PostScript
1387   \param hFile - file instance
1388   \param aViewerCS - viewer co-ordinates system
1389   \param aPSCS - paper co-ordinates system
1390 */
1391 bool GLViewer_TextObject::translateToPS( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS )
1392 {
1393     QString aText = myGLText->getText();    
1394     float xPos, yPos;
1395     myGLText->getPosition( xPos, yPos );
1396
1397     QString aBuffer = "/Times-Roman findfont\n";
1398     aBuffer += "12 scalefont setfont\n";
1399
1400     AddCoordsToPS( aBuffer, "moveto", aViewerCS, aPSCS, double(xPos), double(yPos) );
1401     aBuffer += "(" + aText + ") show\n";
1402
1403     hFile.write( aBuffer.toAscii() );
1404
1405     return true;
1406 }
1407
1408 /*!
1409   Saves text object to file HPGL
1410   \param hFile - file instance
1411   \param aViewerCS - viewer co-ordinates system
1412   \param aHPGLCS - paper co-ordinates system
1413 */
1414 bool GLViewer_TextObject::translateToHPGL( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aHPGLCS )
1415 {
1416     QString aText = myGLText->getText();    
1417     float xPos, yPos;
1418     myGLText->getPosition( xPos, yPos );
1419
1420     QString aBuffer = "";
1421     AddCoordsToHPGL( aBuffer, "PA", aViewerCS, aHPGLCS, double(xPos), double(yPos) );
1422     
1423     aBuffer = "LB" + aText + "#;";
1424     
1425     hFile.write( aBuffer.toAscii() );
1426
1427     return true;
1428 }
1429
1430 #ifdef WIN32
1431 /*!
1432   Saves text object to EMF image
1433   \param dc - EMF image descriptor
1434   \param aViewerCS - viewer co-ordinates system
1435   \param aEMFCS - paper co-ordinates system
1436 */
1437 bool GLViewer_TextObject::translateToEMF( HDC dc, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aEMFCS )
1438 {
1439     QString aText = myGLText->getText();    
1440     float xPos, yPos;
1441     myGLText->getPosition( xPos, yPos );
1442
1443     double x = double( xPos ), 
1444            y = double( yPos );
1445
1446     aViewerCS->transform( *aEMFCS, x, y );
1447     const char* str = aText.toAscii();
1448
1449     int nHeight = 35*14;       // height of font
1450     int nWidth = 35*12;        // average character width
1451     int nEscapement = 0;       // angle of escapement
1452     int nOrientation = 0;      // base-line orientation angle
1453     int fnWeight = FW_NORMAL;  // font weight
1454     DWORD fdwItalic = FALSE;    // italic attribute option
1455     DWORD fdwUnderline = FALSE; // underline attribute option
1456     DWORD fdwStrikeOut = FALSE; // strikeout attribute option
1457     DWORD fdwCharSet = ANSI_CHARSET; // character set identifier
1458     DWORD fdwOutputPrecision = OUT_DEFAULT_PRECIS;  // output precision
1459     DWORD fdwClipPrecision = CLIP_DEFAULT_PRECIS;    // clipping precision
1460     DWORD fdwQuality = PROOF_QUALITY;          // output quality
1461     DWORD fdwPitchAndFamily = FIXED_PITCH | FF_DONTCARE;   // pitch and family
1462     LPCTSTR lpszFace = NULL;         // typeface name
1463
1464
1465     HFONT aFont = CreateFont( nHeight, nWidth, nEscapement, nOrientation, fnWeight, fdwItalic,
1466                               fdwUnderline, fdwStrikeOut, fdwCharSet, fdwOutputPrecision, 
1467                               fdwClipPrecision, fdwQuality, fdwPitchAndFamily, lpszFace );
1468     LOGBRUSH aBrushData;
1469     aBrushData.lbStyle = BS_HOLLOW;
1470
1471     HBRUSH aBrush = CreateBrushIndirect( &aBrushData );
1472
1473     HGDIOBJ old1 = SelectObject( dc, aFont );
1474     HGDIOBJ old2 = SelectObject( dc, aBrush );
1475
1476     TextOut( dc, x, y, str, aText.length() );
1477
1478     SelectObject ( dc, old1 );
1479     SelectObject ( dc, old2 );
1480
1481     DeleteObject( aFont );
1482
1483     return true;
1484 }
1485 #endif
1486
1487 /*!
1488   Creates corresponding drawer
1489 */
1490 GLViewer_Drawer* GLViewer_TextObject::createDrawer()
1491 {
1492     myDrawer = new GLViewer_TextDrawer();
1493     compute();
1494     return myDrawer;
1495 }
1496
1497 /*! 
1498   Computes all necessary information about object for presentation in drawer
1499 */
1500 void GLViewer_TextObject::compute()
1501 {
1502     float xPos, yPos;
1503     QString aStr = myGLText->getText();
1504     myGLText->getPosition( xPos, yPos );
1505
1506     myWidth = myGLText->getWidth();
1507     myHeight = myGLText->getHeight();
1508     myRect->setLeft( xPos );
1509     myRect->setTop( yPos + myHeight  ); 
1510     myRect->setRight( xPos + myWidth );
1511     myRect->setBottom( yPos );
1512 }
1513
1514 /*!
1515   Installing already exist drawer with same type
1516   \param theDrawer - new drawer
1517 */
1518 void GLViewer_TextObject::setDrawer( GLViewer_Drawer* theDrawer )
1519 {
1520     myDrawer = theDrawer;
1521     //compute();
1522 }
1523
1524 /*!
1525   \return update object rectangle
1526   Does not equal getRect() if object have a persistence to some viewer transformations
1527 */
1528 GLViewer_Rect* GLViewer_TextObject::getUpdateRect()
1529 {    
1530     GLViewer_Rect* rect = new GLViewer_Rect();
1531
1532     float xPos, yPos;
1533     QString aStr = myGLText->getText();
1534     myGLText->getPosition( xPos, yPos );
1535
1536     rect->setLeft( myRect->left() + myXGap - myWidth / myXScale );
1537     rect->setTop( myRect->top() + myYGap + myHeight / myYScale );
1538     rect->setRight( myRect->right() - myXGap + myWidth / myXScale );
1539     rect->setBottom( myRect->bottom() - myYGap - myHeight / myYScale );
1540
1541     return rect;
1542 }
1543
1544 /*!
1545   Computes highlight presentation
1546   \param x        - x coord
1547   \param y        - y coord
1548   \param tol      - tolerance of detecting
1549   \param isCircle - true if sensitive area of detection is round
1550   \return true if highlight status is changed
1551 */
1552 GLboolean GLViewer_TextObject::highlight( GLfloat theX, GLfloat theY, GLfloat theTol, GLboolean isCircle )
1553 {
1554     if( !myIsVisible )
1555         return false;
1556
1557     float xPos, yPos;
1558     myGLText->getPosition( xPos, yPos );
1559
1560     QRect aRect;
1561     aRect.setLeft( (int)xPos );
1562     aRect.setRight( (int)(xPos + myWidth / myXScale) );
1563     aRect.setTop( (int)yPos );// - myHeight / myYScale );
1564     aRect.setBottom( (int)(yPos + myHeight / myYScale) );
1565
1566     //cout << "theX: " << theX << "  theY: " << theY << endl;
1567     //cout << "aRect.left(): " << aRect.left() << "  aRect.right(): " << aRect.right() << endl;
1568     //cout << "aRect.top(): " << aRect.top() << "  aRect.bottom(): " << aRect.bottom() << endl;
1569
1570     QRegion obj( aRect );
1571     QRegion intersection;
1572     QRect region;
1573
1574     region.setLeft( (int)(theX - theTol) );
1575     region.setRight( (int)(theX + theTol) );
1576     region.setTop( (int)(theY - theTol) );
1577     region.setBottom( (int)(theY + theTol) );
1578
1579     QRegion circle( (int)(theX - theTol), (int)(theY - theTol),
1580                       (int)(2 * theTol), (int)(2 * theTol), QRegion::Ellipse );
1581     if( isCircle )
1582         intersection = obj.intersect( circle );
1583     else
1584         intersection = obj.intersect( region );
1585     
1586     if( intersection.isEmpty() )
1587         myIsHigh = false;
1588     else
1589         myIsHigh = true;
1590     
1591     if( !myHighFlag && myIsHigh )
1592         myIsHigh = GL_FALSE;
1593     else
1594         myHighFlag = GL_TRUE;
1595
1596     return myIsHigh;
1597 }
1598
1599 /*!
1600   Unhilights object
1601 */
1602 GLboolean GLViewer_TextObject::unhighlight()
1603 {
1604     if( myIsHigh )
1605     {
1606         myIsHigh = GL_FALSE;
1607         return GL_TRUE;
1608     }
1609
1610     return GL_FALSE;
1611 }
1612
1613 /*!
1614   Selects text object
1615   /param x, y - co-ordinates of mouse
1616   /param tol - tolerance
1617   /param rect - rectangle (in case of rectangular selection)
1618   /param isFull - if it is true, then object may selected only if it lays whole in selection zone
1619   \param isCircle - true if sensitive area of detection is round
1620   \param isShift  - true if selection exec with append option
1621 */
1622 GLboolean GLViewer_TextObject::select( GLfloat theX, GLfloat theY, GLfloat theTol, GLViewer_Rect rect,
1623                                        GLboolean isFull, GLboolean isCircle, GLboolean isShift )
1624
1625     if( !myIsVisible )
1626         return false;
1627
1628     QRegion obj( myRect->toQRect() );
1629     QRegion intersection;
1630     QRect region;
1631
1632     region.setLeft( (int)(theX - theTol) );
1633     region.setRight( (int)(theX + theTol) );
1634     region.setTop( (int)(theY - theTol) );
1635     region.setBottom( (int)(theY + theTol) );
1636
1637     QRegion circle( (int)(theX - theTol), (int)(theY - theTol),
1638                       (int)(2 * theTol), (int)(2 * theTol), QRegion::Ellipse );
1639     if( isCircle )
1640         intersection = obj.intersect( circle );
1641     else
1642         intersection = obj.intersect( region );
1643     
1644     if( intersection.isEmpty() )
1645         myIsSel = false;
1646     else
1647         myIsSel = true;
1648
1649     if ( myIsSel )
1650     {
1651         myHighFlag = GL_FALSE;
1652         myIsHigh = GL_FALSE;
1653     }
1654     else
1655         myHighFlag = GL_TRUE;
1656
1657     return myIsSel;
1658 }
1659
1660 /*!
1661   Unselects text object
1662 */
1663 GLboolean GLViewer_TextObject::unselect()
1664 {
1665     if( myIsSel )
1666     {
1667         myIsSel = GL_FALSE;
1668         return GL_TRUE;
1669     }
1670
1671     return GL_FALSE;
1672 }
1673
1674 /*!
1675   Moves object by recomputing
1676   \param dx        - moving along X coord
1677   \param dy        - moving along Y coord
1678   \param fromGroup - is true if this method called from group
1679 */
1680 void GLViewer_TextObject::moveObject( float theX, float theY, bool fromGroup )
1681 {
1682   if( !fromGroup && myGroup)
1683   {
1684     myGroup->dragingObjects( theX, theY );
1685     return;
1686   }
1687   float aX, anY;
1688   myGLText->getPosition( aX, anY );
1689   aX += theX;
1690   anY += theY;
1691   myGLText->setPosition( aX, anY );
1692   compute();
1693 }
1694
1695 /*!
1696   Codes text object as byte copy
1697   \return byte array
1698 */
1699 QByteArray GLViewer_TextObject::getByteCopy()
1700 {
1701     QByteArray aObject = GLViewer_Object::getByteCopy();
1702
1703     return aObject;
1704 }
1705
1706 /*!
1707   Initialize text object by byte array
1708   \param theArray - byte array
1709 */
1710 bool GLViewer_TextObject::initializeFromByteCopy( QByteArray theArray )
1711 {
1712     if( !GLViewer_Object::initializeFromByteCopy( theArray ) || myType != "GLViewer_TextObject" )
1713         return false;
1714
1715     myHighFlag = true;
1716     return true;        
1717 }