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