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