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