0a009c98a54e374429d25f2d415ba6161163cd4b
[occt.git] / src / Aspect / Aspect_ColorScale.cxx
1 // Created on: 2004-06-22
2 // Created by: STV
3 // Copyright (c) 2004-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and / or modify it
8 // under the terms of the GNU Lesser General Public version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <Aspect_ColorScale.ixx>
17
18 #include <Aspect_ColorMap.hxx>
19 #include <Aspect_ColorMapEntry.hxx>
20 #include <Aspect_SequenceOfColor.hxx>
21 #include <Aspect_TypeOfColorScaleData.hxx>
22 #include <Aspect_TypeOfColorScalePosition.hxx>
23
24 #include <TCollection_AsciiString.hxx>
25 #include <TCollection_ExtendedString.hxx>
26 #include <TColStd_SequenceOfExtendedString.hxx>
27
28 #include <Precision.hxx>
29
30 #include <stdio.h>
31
32 Aspect_ColorScale::Aspect_ColorScale()
33 : MMgt_TShared(),
34 myMin( 0.0 ),
35 myMax( 1.0 ),
36 myTitle( "" ),
37 myFormat( "%.4g" ),
38 myInterval( 10 ),
39 myColorType( Aspect_TOCSD_AUTO ),
40 myLabelType( Aspect_TOCSD_AUTO ),
41 myAtBorder( Standard_True ),
42 myReversed( Standard_False ),
43 myLabelPos( Aspect_TOCSP_RIGHT ),
44 myTitlePos( Aspect_TOCSP_CENTER ),
45 myXPos( 0 ),
46 myYPos( 0 ),
47 myWidth( 0.2 ),
48 myHeight( 1 ),
49 myTextHeight(20)
50 {
51 }
52
53 Standard_Real Aspect_ColorScale::GetMin() const
54 {
55   return myMin;
56 }
57
58 Standard_Real Aspect_ColorScale::GetMax() const
59 {
60   return myMax;
61 }
62
63 void Aspect_ColorScale::GetRange( Standard_Real& aMin, Standard_Real& aMax ) const
64 {
65   aMin = myMin;
66   aMax = myMax;
67 }
68
69 Aspect_TypeOfColorScaleData Aspect_ColorScale::GetLabelType() const
70 {
71   return myLabelType;
72 }
73
74 Aspect_TypeOfColorScaleData Aspect_ColorScale::GetColorType() const
75 {
76   return myColorType;
77 }
78
79 Standard_Integer Aspect_ColorScale::GetNumberOfIntervals() const
80 {
81   return myInterval;
82 }
83
84 TCollection_ExtendedString Aspect_ColorScale::GetTitle() const
85 {
86   return myTitle;
87 }
88
89 TCollection_AsciiString Aspect_ColorScale::GetFormat() const
90 {
91   return myFormat;
92 }
93
94 TCollection_ExtendedString Aspect_ColorScale::GetLabel( const Standard_Integer anIndex ) const
95 {
96   TCollection_ExtendedString aLabel;
97   if ( anIndex >= 0 && anIndex < myLabels.Length() )
98     aLabel = myLabels.Value( anIndex + 1 );
99   return aLabel;
100 }
101
102 Quantity_Color Aspect_ColorScale::GetColor( const Standard_Integer anIndex ) const
103 {
104   Quantity_Color aColor;
105   if ( anIndex >= 0 && anIndex < myColors.Length() )
106     aColor = myColors.Value( anIndex + 1 );
107   return aColor;
108 }
109
110 void Aspect_ColorScale::GetLabels( TColStd_SequenceOfExtendedString& aLabels ) const
111 {
112   aLabels.Clear();
113   for ( Standard_Integer i = 1; i <= myLabels.Length(); i++ )
114     aLabels.Append( myLabels.Value( i ) );
115 }
116
117 void Aspect_ColorScale::GetColors( Aspect_SequenceOfColor& aColors ) const
118 {
119   aColors.Clear();
120   for ( Standard_Integer i = 1; i <= myColors.Length(); i++ )
121     aColors.Append( myColors.Value( i ) );
122 }
123
124 Aspect_TypeOfColorScalePosition Aspect_ColorScale::GetLabelPosition() const
125 {
126   return myLabelPos;
127 }
128
129 Aspect_TypeOfColorScalePosition Aspect_ColorScale::GetTitlePosition() const
130 {
131   return myTitlePos;
132 }
133
134 Standard_Boolean Aspect_ColorScale::IsReversed() const
135 {
136   return myReversed;
137 }
138
139 Standard_Boolean Aspect_ColorScale::IsLabelAtBorder() const
140 {
141   return myAtBorder;
142 }
143
144 void Aspect_ColorScale::SetMin( const Standard_Real aMin )
145 {
146   SetRange( aMin, GetMax() );
147 }
148
149 void Aspect_ColorScale::SetMax( const Standard_Real aMax )
150 {
151   SetRange( GetMin(), aMax );
152 }
153
154 void Aspect_ColorScale::SetRange( const Standard_Real aMin, const Standard_Real aMax )
155 {
156   if ( myMin == aMin && myMax == aMax )
157     return;
158  
159   myMin = Min( aMin, aMax );
160   myMax = Max( aMin, aMax );
161
162   if ( GetColorType() == Aspect_TOCSD_AUTO )
163     UpdateColorScale();
164 }
165
166 void Aspect_ColorScale::SetLabelType( const Aspect_TypeOfColorScaleData aType )
167 {
168   if ( myLabelType == aType )
169     return;
170
171   myLabelType = aType;
172   UpdateColorScale();
173 }
174
175 void Aspect_ColorScale::SetColorType( const Aspect_TypeOfColorScaleData aType )
176 {
177   if ( myColorType == aType )
178     return;
179
180   myColorType = aType;
181   UpdateColorScale();
182 }
183
184 void Aspect_ColorScale::SetNumberOfIntervals( const Standard_Integer aNum )
185 {
186   if ( myInterval == aNum || aNum < 1 )
187     return;
188
189   myInterval = aNum;
190   UpdateColorScale();
191 }
192
193 void Aspect_ColorScale::SetTitle( const TCollection_ExtendedString& aTitle )
194 {
195   if ( myTitle == aTitle )
196     return;
197
198   myTitle = aTitle;
199   UpdateColorScale();
200 }
201
202 void Aspect_ColorScale::SetFormat( const TCollection_AsciiString& aFormat )
203 {
204   if ( myFormat == aFormat )
205     return;
206
207   myFormat = aFormat;
208   if ( GetLabelType() == Aspect_TOCSD_AUTO )
209     UpdateColorScale();
210 }
211
212 void Aspect_ColorScale::SetLabel( const TCollection_ExtendedString& aLabel, const Standard_Integer anIndex )
213 {
214   Standard_Boolean changed = Standard_False;
215   Standard_Integer i = anIndex < 1 ? myLabels.Length() + 1 : anIndex;
216   if ( i <= myLabels.Length() ) {
217     changed = myLabels.Value( i ) != aLabel;
218     myLabels.SetValue( i, aLabel );
219   }
220   else {
221     changed = Standard_True;
222     while ( i > myLabels.Length() )
223       myLabels.Append( TCollection_ExtendedString() );
224     myLabels.SetValue( i, aLabel );
225   }
226   if ( changed )
227     UpdateColorScale();
228 }
229
230 void Aspect_ColorScale::SetColor(const Quantity_Color& aColor, const Standard_Integer anIndex )
231 {
232   Standard_Boolean changed = Standard_False;
233   Standard_Integer i = anIndex < 1 ? myLabels.Length() + 1 : anIndex;
234   if ( i <= myColors.Length() ) {
235     changed = myColors.Value( i ) != aColor;
236     myColors.SetValue( i, aColor );
237   }
238   else {
239     changed = Standard_True;
240     while ( i > myColors.Length() )
241       myColors.Append( Quantity_Color() );
242     myColors.SetValue( i, aColor );
243   }
244   if ( changed )
245     UpdateColorScale();
246 }
247
248 void Aspect_ColorScale::SetLabels( const TColStd_SequenceOfExtendedString& aSeq )
249 {
250   myLabels.Clear();
251   for ( Standard_Integer i = 1; i <= aSeq.Length(); i++ )
252     myLabels.Append( aSeq.Value( i ) );
253 }
254
255 void Aspect_ColorScale::SetColors( const Handle(Aspect_ColorMap)& aMap )
256 {
257   myColors.Clear();
258   if ( !aMap.IsNull() )
259     for ( Standard_Integer i = 1; i <= aMap->Size(); i++ )
260       myColors.Append( aMap->Entry( i ).Color() );
261 }
262
263 void Aspect_ColorScale::SetColors( const Aspect_SequenceOfColor& aSeq )
264 {
265   myColors.Clear();
266   for ( Standard_Integer i = 1; i <= aSeq.Length(); i++ )
267     myColors.Append( aSeq.Value( i ) );
268 }
269
270 void Aspect_ColorScale::SetLabelPosition( const Aspect_TypeOfColorScalePosition aPos )
271 {
272   if ( myLabelPos == aPos )
273     return;
274
275   myLabelPos = aPos;
276   UpdateColorScale();
277 }
278
279 void Aspect_ColorScale::SetTitlePosition( const Aspect_TypeOfColorScalePosition aPos )
280 {
281   if ( myTitlePos == aPos )
282     return;
283
284   myTitlePos = aPos;
285   UpdateColorScale();
286 }
287
288 void Aspect_ColorScale::SetReversed( const Standard_Boolean aReverse )
289 {
290   if ( myReversed == aReverse )
291     return;
292
293   myReversed = aReverse;
294   UpdateColorScale();
295 }
296
297 void Aspect_ColorScale::SetLabelAtBorder( const Standard_Boolean anOn )
298 {
299   if ( myAtBorder == anOn )
300     return;
301
302   myAtBorder = anOn;
303   UpdateColorScale();
304 }
305
306 void Aspect_ColorScale::GetPosition( Standard_Real& aX, Standard_Real& aY ) const
307 {
308   aX = myXPos;
309   aY = myYPos;
310 }
311
312 Standard_Real Aspect_ColorScale::GetXPosition() const
313 {
314   return myXPos;
315 }
316
317 Standard_Real Aspect_ColorScale::GetYPosition() const
318 {
319   return myYPos;
320 }
321
322 void Aspect_ColorScale::SetPosition( const Standard_Real aX, const Standard_Real aY )
323 {
324   if ( myXPos == aX && myYPos == aY )
325     return;
326
327   myXPos = aX;
328   myYPos = aY;
329
330   UpdateColorScale();
331 }
332
333 void Aspect_ColorScale::SetXPosition( const Standard_Real aX )
334 {
335   SetPosition( aX, GetYPosition() );
336 }
337
338 void Aspect_ColorScale::SetYPosition( const Standard_Real aY )
339 {
340   SetPosition( GetXPosition(), aY );
341 }
342
343 void Aspect_ColorScale::GetSize( Standard_Real& aWidth, Standard_Real& aHeight ) const
344 {
345   aWidth = myWidth;
346   aHeight = myHeight;
347 }
348
349 Standard_Real Aspect_ColorScale::GetWidth() const
350 {
351   return myWidth;
352 }
353
354 Standard_Real Aspect_ColorScale::GetHeight() const
355 {
356   return myHeight;
357 }
358
359 void Aspect_ColorScale::SetSize( const Standard_Real aWidth, const Standard_Real aHeight )
360 {
361   if ( myWidth == aWidth && myHeight == aHeight )
362     return;
363
364   myWidth = aWidth;
365   myHeight = aHeight;
366
367   UpdateColorScale();
368 }
369
370 void Aspect_ColorScale::SetWidth( const Standard_Real aWidth )
371 {
372   SetSize( aWidth, GetHeight() );
373 }
374
375 void Aspect_ColorScale::SetHeight( const Standard_Real aHeight )
376 {
377   SetSize( GetWidth(), aHeight );
378 }
379
380 void Aspect_ColorScale::SizeHint( Standard_Integer& aWidth, Standard_Integer& aHeight ) const
381 {
382   Standard_Integer num = GetNumberOfIntervals();
383
384   Standard_Integer spacer = 5;
385   Standard_Integer textWidth = 0;
386   Standard_Integer textHeight = TextHeight( "" );
387   Standard_Integer colorWidth = 20;
388
389   if ( GetLabelPosition() != Aspect_TOCSP_NONE )
390     for ( Standard_Integer idx = 0; idx < num; idx++ )
391       textWidth = Max( textWidth, TextWidth( GetCurrentLabel( idx + 1 ) ) );
392
393   Standard_Integer scaleWidth = 0;
394   Standard_Integer scaleHeight = 0;
395
396   Standard_Integer titleWidth = 0;
397   Standard_Integer titleHeight = 0;
398
399   if ( IsLabelAtBorder() ) {
400     num++;
401     if ( GetTitle().Length() )
402       titleHeight += 10;
403   }
404
405   scaleWidth = colorWidth + textWidth + ( textWidth ? 3 : 2 ) * spacer;
406   scaleHeight = (Standard_Integer)( 1.5 * ( num + 1 ) * textHeight );
407   
408   if ( GetTitle().Length() ) {
409     titleHeight = TextHeight( GetTitle() ) + spacer;
410     titleWidth =  TextWidth( GetTitle() ) + 10;
411   }
412
413   aWidth = Max( titleWidth, scaleWidth );
414   aHeight = scaleHeight + titleHeight;
415 }
416
417 void Aspect_ColorScale::DrawScale( const Quantity_Color& aBgColor,
418                                       const Standard_Integer X, const Standard_Integer Y,
419                                       const Standard_Integer W, const Standard_Integer H )
420 {
421   if ( !BeginPaint() )
422     return;
423
424   Standard_Integer num = GetNumberOfIntervals();
425   Aspect_TypeOfColorScalePosition labPos = GetLabelPosition();
426
427   Standard_Integer spacer = 5;
428   Standard_Integer textWidth = 0;
429   Standard_Integer textHeight = TextHeight( "" );
430
431   Standard_Boolean drawLabel = GetLabelPosition() != Aspect_TOCSP_NONE;
432
433   TCollection_ExtendedString aTitle = GetTitle();
434
435   Standard_Integer titleHeight = 0;
436
437   Standard_Integer aGray = (Standard_Integer)(255 * ( aBgColor.Red() * 11 + aBgColor.Green() * 16 + aBgColor.Blue() * 5 ) / 32);
438   Quantity_Color aFgColor( aGray < 128 ? Quantity_NOC_WHITE : Quantity_NOC_BLACK );
439
440   // Draw title
441   if ( aTitle.Length() ) {
442     titleHeight = TextHeight( aTitle ) + 2 * spacer;
443     PaintText( aTitle, X + spacer, Y + spacer, aFgColor );
444   }
445
446   Standard_Boolean reverse = IsReversed();
447
448   Aspect_SequenceOfColor colors;
449   TColStd_SequenceOfExtendedString labels;
450   for ( int idx = 0; idx < num; idx++ ) {
451     if ( reverse ) {
452       colors.Append( GetCurrentColor( idx ) );
453       labels.Append( GetCurrentLabel( idx ) );
454     }
455     else {
456       colors.Prepend( GetCurrentColor( idx ) );
457       labels.Prepend( GetCurrentLabel( idx ) );
458     }
459   }
460
461   if ( IsLabelAtBorder() ) {
462     if ( reverse )
463       labels.Append( GetCurrentLabel( num ) );
464     else
465       labels.Prepend( GetCurrentLabel( num ) );
466   }
467
468   if ( drawLabel )
469     for ( Standard_Integer i = 1; i <= labels.Length(); i++ )
470       textWidth = Max( textWidth, TextWidth( labels.Value( i ) ) );
471
472   Standard_Integer lab = labels.Length();
473
474   Standard_Real spc = ( H - ( ( Min( lab, 2 ) + Abs( lab - num - 1 ) ) * textHeight ) - titleHeight );
475   Standard_Real val = spc != 0 ? 1.0 * ( lab - Min( lab, 2 ) ) * textHeight / spc : 0;
476   Standard_Real iPart;
477   Standard_Real fPart = modf( val, &iPart );
478   Standard_Integer filter = (Standard_Integer)iPart + ( fPart != 0 ? 1 : 0 );
479
480   Standard_Real step = 1.0 * ( H - ( lab - num + Abs( lab - num - 1 ) ) * textHeight - titleHeight ) / num;
481
482   Standard_Integer ascent = 0;
483   Standard_Integer colorWidth = Max( 5, Min( 20, W - textWidth - 3 * spacer ) );
484   if ( labPos == Aspect_TOCSP_CENTER || !drawLabel )
485     colorWidth = W - 2 * spacer;
486
487   // Draw colors
488   Standard_Integer x = X + spacer;
489   if ( labPos == Aspect_TOCSP_LEFT )
490     x += textWidth + ( textWidth ? 1 : 0 ) * spacer;
491
492   Standard_Real offset = 1.0 * textHeight / 2 * ( lab - num + Abs( lab - num - 1 ) ) + titleHeight;
493   for ( Standard_Integer ci = 1; ci <= colors.Length() && step > 0; ci++ ) {
494     Standard_Integer y = (Standard_Integer)( Y + ( ci - 1 )* step + offset );
495     Standard_Integer h = (Standard_Integer)( Y + ( ci ) * step + offset ) - y;
496     PaintRect( x, y, colorWidth, h, colors.Value( ci ), Standard_True );
497   }
498
499   if ( step > 0 )
500     PaintRect( x - 1, (Standard_Integer)(Y + offset - 1), colorWidth + 2, (Standard_Integer)(colors.Length() * step + 2), aFgColor );
501
502   // Draw labels
503   offset = 1.0 * Abs( lab - num - 1 ) * ( step - textHeight ) / 2 + 1.0 * Abs( lab - num - 1 ) * textHeight / 2;
504   offset += titleHeight;
505   if ( drawLabel && labels.Length() && filter > 0 ) {
506     Standard_Integer i1 = 0;
507     Standard_Integer i2 = lab - 1;
508     Standard_Integer last1( i1 ), last2( i2 );
509     x = X + spacer;
510     switch ( labPos ) {
511     case Aspect_TOCSP_NONE:
512     case Aspect_TOCSP_LEFT:
513       break;
514     case Aspect_TOCSP_CENTER:
515       x += ( colorWidth - textWidth ) / 2;
516       break;
517     case Aspect_TOCSP_RIGHT:
518       x += colorWidth + spacer;
519       break;
520     }
521     while ( i2 - i1 >= filter || ( i2 == 0 && i1 == 0 ) ) {
522       Standard_Integer pos1 = i1;
523       Standard_Integer pos2 = lab - 1 - i2;
524       if ( filter && !( pos1 % filter ) ) {
525         PaintText( labels.Value( i1 + 1 ), x, (Standard_Integer)( Y + i1 * step + ascent + offset ), aFgColor );
526         last1 = i1;
527       }
528       if ( filter && !( pos2 % filter ) ) {
529         PaintText( labels.Value( i2 + 1 ), x, (Standard_Integer)( Y + i2 * step + ascent + offset ), aFgColor );
530         last2 = i2;
531       }
532       i1++;
533       i2--;
534     }
535     Standard_Integer pos = i1;
536     Standard_Integer i0 = -1;
537     while ( pos <= i2 && i0 == -1 ) {
538       if ( filter && !( pos % filter ) && Abs( pos - last1 ) >= filter && Abs( pos - last2 ) >= filter )
539         i0 = pos;
540       pos++;
541     }
542
543     if ( i0 != -1 )
544       PaintText( labels.Value( i0 + 1 ), x, (Standard_Integer)( Y + i0 * step + ascent + offset ), aFgColor );
545   }
546
547   EndPaint();
548 }
549
550 Standard_Boolean Aspect_ColorScale::BeginPaint()
551 {
552   return Standard_True;
553 }
554
555 Standard_Boolean Aspect_ColorScale::EndPaint()
556 {
557   return Standard_True;
558 }
559
560 void Aspect_ColorScale::UpdateColorScale()
561 {
562 }
563
564 TCollection_AsciiString Aspect_ColorScale::Format() const
565 {
566   return GetFormat();
567 }
568
569 TCollection_ExtendedString Aspect_ColorScale::GetCurrentLabel( const Standard_Integer anIndex ) const
570 {
571   TCollection_ExtendedString aLabel;
572   if ( GetLabelType() == Aspect_TOCSD_USER )
573     aLabel = GetLabel( anIndex );
574   else {
575     Standard_Real val = GetNumber( anIndex );
576     Standard_Character buf[1024];
577     TCollection_AsciiString aFormat = Format();
578     sprintf( buf, aFormat.ToCString(), val );
579     aLabel = TCollection_ExtendedString( buf );
580   }
581
582   return aLabel;
583 }
584
585 Quantity_Color Aspect_ColorScale::GetCurrentColor( const Standard_Integer anIndex ) const
586 {
587   Quantity_Color aColor;
588   if ( GetColorType() == Aspect_TOCSD_USER )
589     aColor = GetColor( anIndex );
590   else
591     aColor = Quantity_Color( HueFromValue( anIndex, 0, GetNumberOfIntervals() - 1 ), 1.0, 1.0, Quantity_TOC_HLS );
592   return aColor;
593 }
594
595 Standard_Real Aspect_ColorScale::GetNumber( const Standard_Integer anIndex ) const
596 {
597   Standard_Real aNum = 0;
598   if ( GetNumberOfIntervals() > 0 )
599     aNum = GetMin() + anIndex * ( Abs( GetMax() - GetMin() ) / GetNumberOfIntervals() );
600   return aNum;
601 }
602
603 Standard_Integer Aspect_ColorScale::HueFromValue( const Standard_Integer aValue,
604                                                   const Standard_Integer aMin, const Standard_Integer aMax )
605 {
606   Standard_Integer minLimit( 0 ), maxLimit( 230 );
607
608   Standard_Integer aHue = maxLimit;
609   if ( aMin != aMax )
610     aHue = (Standard_Integer)( maxLimit - ( maxLimit - minLimit ) * ( aValue - aMin ) / ( aMax - aMin ) );
611
612   aHue = Min( Max( minLimit, aHue ), maxLimit );
613
614   return aHue;
615 }
616
617 Standard_Integer  Aspect_ColorScale::GetTextHeight() const {
618   return myTextHeight;
619 }
620
621 void Aspect_ColorScale::SetTextHeight(const Standard_Integer aHeigh) {
622   myTextHeight = aHeigh;
623   UpdateColorScale ();
624 }
625
626
627 Standard_Boolean Aspect_ColorScale::FindColor( const Standard_Real aValue, 
628                                                Quantity_Color& aColor ) const
629 {
630   return FindColor( aValue, myMin, myMax, myInterval, aColor );
631 }
632
633
634 Standard_Boolean Aspect_ColorScale::FindColor( const Standard_Real aValue, 
635                                                const Standard_Real aMin,
636                                                const Standard_Real aMax,
637                                                const Standard_Integer ColorsCount,
638                                                Quantity_Color& aColor )
639 {
640   if( aValue<aMin || aValue>aMax || aMax<aMin )
641     return Standard_False;
642
643   else
644   {
645     Standard_Real IntervNumber = 0;
646     if( aValue<aMin )
647       IntervNumber = 0;
648     else if( aValue>aMax )
649       IntervNumber = ColorsCount-1;
650     else if( Abs( aMax-aMin ) > Precision::Approximation() )
651       IntervNumber = Ceiling( Standard_Real( ColorsCount ) * ( aValue - aMin ) / ( aMax - aMin ) );
652
653     Standard_Integer Interv = Standard_Integer( IntervNumber );
654
655     aColor = Quantity_Color( HueFromValue( Interv, 0, ColorsCount - 1 ), 1.0, 1.0, Quantity_TOC_HLS );
656
657     return Standard_True;
658   } 
659 }