0024428: Implementation of LGPL license
[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 titleWidth = 0;
436   Standard_Integer titleHeight = 0;
437
438   Standard_Integer aGray = (Standard_Integer)(255 * ( aBgColor.Red() * 11 + aBgColor.Green() * 16 + aBgColor.Blue() * 5 ) / 32);
439   Quantity_Color aFgColor( aGray < 128 ? Quantity_NOC_WHITE : Quantity_NOC_BLACK );
440
441   // Draw title
442   if ( aTitle.Length() ) {
443     titleWidth = TextWidth( aTitle );
444     titleHeight = TextHeight( aTitle ) + 2 * spacer;
445     PaintText( aTitle, X + spacer, Y + spacer, aFgColor );
446   }
447
448   Standard_Boolean reverse = IsReversed();
449
450   Aspect_SequenceOfColor colors;
451   TColStd_SequenceOfExtendedString labels;
452   for ( int idx = 0; idx < num; idx++ ) {
453     if ( reverse ) {
454       colors.Append( GetCurrentColor( idx ) );
455       labels.Append( GetCurrentLabel( idx ) );
456     }
457     else {
458       colors.Prepend( GetCurrentColor( idx ) );
459       labels.Prepend( GetCurrentLabel( idx ) );
460     }
461   }
462
463   if ( IsLabelAtBorder() ) {
464     if ( reverse )
465       labels.Append( GetCurrentLabel( num ) );
466     else
467       labels.Prepend( GetCurrentLabel( num ) );
468   }
469
470   if ( drawLabel )
471     for ( Standard_Integer i = 1; i <= labels.Length(); i++ )
472       textWidth = Max( textWidth, TextWidth( labels.Value( i ) ) );
473
474   Standard_Integer lab = labels.Length();
475
476   Standard_Real spc = ( H - ( ( Min( lab, 2 ) + Abs( lab - num - 1 ) ) * textHeight ) - titleHeight );
477   Standard_Real val = spc != 0 ? 1.0 * ( lab - Min( lab, 2 ) ) * textHeight / spc : 0;
478   Standard_Real iPart;
479   Standard_Real fPart = modf( val, &iPart );
480   Standard_Integer filter = (Standard_Integer)iPart + ( fPart != 0 ? 1 : 0 );
481
482   Standard_Real step = 1.0 * ( H - ( lab - num + Abs( lab - num - 1 ) ) * textHeight - titleHeight ) / num;
483
484   Standard_Integer ascent = 0;
485   Standard_Integer colorWidth = Max( 5, Min( 20, W - textWidth - 3 * spacer ) );
486   if ( labPos == Aspect_TOCSP_CENTER || !drawLabel )
487     colorWidth = W - 2 * spacer;
488
489   // Draw colors
490   Standard_Integer x = X + spacer;
491   if ( labPos == Aspect_TOCSP_LEFT )
492     x += textWidth + ( textWidth ? 1 : 0 ) * spacer;
493
494   Standard_Real offset = 1.0 * textHeight / 2 * ( lab - num + Abs( lab - num - 1 ) ) + titleHeight;
495   for ( Standard_Integer ci = 1; ci <= colors.Length() && step > 0; ci++ ) {
496     Standard_Integer y = (Standard_Integer)( Y + ( ci - 1 )* step + offset );
497     Standard_Integer h = (Standard_Integer)( Y + ( ci ) * step + offset ) - y;
498     PaintRect( x, y, colorWidth, h, colors.Value( ci ), Standard_True );
499   }
500
501   if ( step > 0 )
502     PaintRect( x - 1, (Standard_Integer)(Y + offset - 1), colorWidth + 2, (Standard_Integer)(colors.Length() * step + 2), aFgColor );
503
504   // Draw labels
505   offset = 1.0 * Abs( lab - num - 1 ) * ( step - textHeight ) / 2 + 1.0 * Abs( lab - num - 1 ) * textHeight / 2;
506   offset += titleHeight;
507   if ( drawLabel && labels.Length() && filter > 0 ) {
508     Standard_Integer i1 = 0;
509     Standard_Integer i2 = lab - 1;
510     Standard_Integer last1( i1 ), last2( i2 );
511     x = X + spacer;
512     switch ( labPos ) {
513     case Aspect_TOCSP_CENTER:
514       x += ( colorWidth - textWidth ) / 2;
515       break;
516     case Aspect_TOCSP_RIGHT:
517       x += colorWidth + spacer;
518       break;
519     }
520     while ( i2 - i1 >= filter || ( i2 == 0 && i1 == 0 ) ) {
521       Standard_Integer pos1 = i1;
522       Standard_Integer pos2 = lab - 1 - i2;
523       if ( filter && !( pos1 % filter ) ) {
524         PaintText( labels.Value( i1 + 1 ), x, (Standard_Integer)( Y + i1 * step + ascent + offset ), aFgColor );
525         last1 = i1;
526       }
527       if ( filter && !( pos2 % filter ) ) {
528         PaintText( labels.Value( i2 + 1 ), x, (Standard_Integer)( Y + i2 * step + ascent + offset ), aFgColor );
529         last2 = i2;
530       }
531       i1++;
532       i2--;
533     }
534     Standard_Integer pos = i1;
535     Standard_Integer i0 = -1;
536     while ( pos <= i2 && i0 == -1 ) {
537       if ( filter && !( pos % filter ) && Abs( pos - last1 ) >= filter && Abs( pos - last2 ) >= filter )
538         i0 = pos;
539       pos++;
540     }
541
542     if ( i0 != -1 )
543       PaintText( labels.Value( i0 + 1 ), x, (Standard_Integer)( Y + i0 * step + ascent + offset ), aFgColor );
544   }
545
546   EndPaint();
547 }
548
549 Standard_Boolean Aspect_ColorScale::BeginPaint()
550 {
551   return Standard_True;
552 }
553
554 Standard_Boolean Aspect_ColorScale::EndPaint()
555 {
556   return Standard_True;
557 }
558
559 void Aspect_ColorScale::UpdateColorScale()
560 {
561 }
562
563 TCollection_AsciiString Aspect_ColorScale::Format() const
564 {
565   return GetFormat();
566 }
567
568 TCollection_ExtendedString Aspect_ColorScale::GetCurrentLabel( const Standard_Integer anIndex ) const
569 {
570   TCollection_ExtendedString aLabel;
571   if ( GetLabelType() == Aspect_TOCSD_USER )
572     aLabel = GetLabel( anIndex );
573   else {
574     Standard_Real val = GetNumber( anIndex );
575     Standard_Character buf[1024];
576     TCollection_AsciiString aFormat = Format();
577     sprintf( buf, aFormat.ToCString(), val );
578     aLabel = TCollection_ExtendedString( buf );
579   }
580
581   return aLabel;
582 }
583
584 Quantity_Color Aspect_ColorScale::GetCurrentColor( const Standard_Integer anIndex ) const
585 {
586   Quantity_Color aColor;
587   if ( GetColorType() == Aspect_TOCSD_USER )
588     aColor = GetColor( anIndex );
589   else
590     aColor = Quantity_Color( HueFromValue( anIndex, 0, GetNumberOfIntervals() - 1 ), 1.0, 1.0, Quantity_TOC_HLS );
591   return aColor;
592 }
593
594 Standard_Real Aspect_ColorScale::GetNumber( const Standard_Integer anIndex ) const
595 {
596   Standard_Real aNum = 0;
597   if ( GetNumberOfIntervals() > 0 )
598     aNum = GetMin() + anIndex * ( Abs( GetMax() - GetMin() ) / GetNumberOfIntervals() );
599   return aNum;
600 }
601
602 Standard_Integer Aspect_ColorScale::HueFromValue( const Standard_Integer aValue,
603                                                   const Standard_Integer aMin, const Standard_Integer aMax )
604 {
605   Standard_Integer minLimit( 0 ), maxLimit( 230 );
606
607   Standard_Integer aHue = maxLimit;
608   if ( aMin != aMax )
609     aHue = (Standard_Integer)( maxLimit - ( maxLimit - minLimit ) * ( aValue - aMin ) / ( aMax - aMin ) );
610
611   aHue = Min( Max( minLimit, aHue ), maxLimit );
612
613   return aHue;
614 }
615
616 Standard_Integer  Aspect_ColorScale::GetTextHeight() const {
617   return myTextHeight;
618 }
619
620 void Aspect_ColorScale::SetTextHeight(const Standard_Integer aHeigh) {
621   myTextHeight = aHeigh;
622   UpdateColorScale ();
623 }
624
625
626 Standard_Boolean Aspect_ColorScale::FindColor( const Standard_Real aValue, 
627                                                Quantity_Color& aColor ) const
628 {
629   return FindColor( aValue, myMin, myMax, myInterval, aColor );
630 }
631
632
633 Standard_Boolean Aspect_ColorScale::FindColor( const Standard_Real aValue, 
634                                                const Standard_Real aMin,
635                                                const Standard_Real aMax,
636                                                const Standard_Integer ColorsCount,
637                                                Quantity_Color& aColor )
638 {
639   if( aValue<aMin || aValue>aMax || aMax<aMin )
640     return Standard_False;
641
642   else
643   {
644     Standard_Real IntervNumber = 0;
645     if( aValue<aMin )
646       IntervNumber = 0;
647     else if( aValue>aMax )
648       IntervNumber = ColorsCount-1;
649     else if( Abs( aMax-aMin ) > Precision::Approximation() )
650       IntervNumber = Ceiling( Standard_Real( ColorsCount ) * ( aValue - aMin ) / ( aMax - aMin ) );
651
652     Standard_Integer Interv = Standard_Integer( IntervNumber );
653
654     aColor = Quantity_Color( HueFromValue( Interv, 0, ColorsCount - 1 ), 1.0, 1.0, Quantity_TOC_HLS );
655
656     return Standard_True;
657   } 
658 }