0033661: Data Exchange, Step Import - Tessellated GDTs are not imported
[occt.git] / src / AIS / AIS_ColorScale.cxx
CommitLineData
7a324550 1// Created on: 2015-02-03
2// Copyright (c) 2015 OPEN CASCADE SAS
3//
4// This file is part of Open CASCADE Technology software library.
5//
6// This library is free software; you can redistribute it and/or modify it under
7// the terms of the GNU Lesser General Public License version 2.1 as published
8// by the Free Software Foundation, with special exception defined in the file
9// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10// distribution for complete text of the license and disclaimer of any warranty.
11//
12// Alternatively, this file may be used under the terms of Open CASCADE
13// commercial license or contractual agreement.
14
15#include <AIS_ColorScale.hxx>
4b3d6eb1 16
7a324550 17#include <AIS_InteractiveContext.hxx>
18#include <Aspect_TypeOfColorScaleData.hxx>
19#include <Aspect_TypeOfColorScalePosition.hxx>
7a324550 20#include <Geom_Line.hxx>
21#include <GeomAdaptor_Curve.hxx>
7a324550 22#include <Graphic3d_ArrayOfPolylines.hxx>
23#include <Graphic3d_AspectFillArea3d.hxx>
24#include <Graphic3d_AspectText3d.hxx>
25#include <Graphic3d_GraphicDriver.hxx>
26#include <Graphic3d_ArrayOfTriangles.hxx>
8ed07085 27#include <Graphic3d_Text.hxx>
7a324550 28#include <Prs3d_Text.hxx>
29#include <Prs3d_TextAspect.hxx>
7a324550 30#include <Select3D_SensitiveBox.hxx>
7a324550 31#include <StdPrs_Curve.hxx>
7a324550 32#include <V3d_View.hxx>
33
4b3d6eb1 34IMPLEMENT_STANDARD_RTTIEXT(AIS_ColorScale, AIS_InteractiveObject)
7a324550 35
4b3d6eb1 36namespace
7a324550 37{
4b3d6eb1 38 //! Method to add colored quad into array of triangles.
39 static void addColoredQuad (const Handle(Graphic3d_ArrayOfTriangles)& theTris,
40 const Standard_Integer theXLeft, const Standard_Integer theYBottom,
41 const Standard_Integer theSizeX, const Standard_Integer theSizeY,
42 const Quantity_Color& theColorBottom,
43 const Quantity_Color& theColorTop)
44 {
45 const Standard_Integer aVertIndex = theTris->VertexNumber() + 1;
46 theTris->AddVertex (gp_Pnt (theXLeft, theYBottom, 0.0), theColorBottom);
47 theTris->AddVertex (gp_Pnt (theXLeft + theSizeX, theYBottom, 0.0), theColorBottom);
48 theTris->AddVertex (gp_Pnt (theXLeft, theYBottom + theSizeY, 0.0), theColorTop);
49 theTris->AddVertex (gp_Pnt (theXLeft + theSizeX, theYBottom + theSizeY, 0.0), theColorTop);
fb60181a 50 theTris->AddEdges (aVertIndex, aVertIndex + 1, aVertIndex + 2);
51 theTris->AddEdges (aVertIndex + 1, aVertIndex + 2, aVertIndex + 3);
4b3d6eb1 52 }
53
54 //! Compute hue angle from specified value.
55 static Quantity_Color colorFromValueEx (const Standard_Real theValue,
56 const Standard_Real theMin,
57 const Standard_Real theMax,
58 const Graphic3d_Vec3d& theHlsMin,
59 const Graphic3d_Vec3d& theHlsMax)
60 {
61 const Standard_Real aValueDelta = theMax - theMin;
62 Standard_Real aValue = 0.0;
63 if (aValueDelta != 0.0)
64 {
65 aValue = (theValue - theMin) / aValueDelta;
66 }
67
68 Standard_Real aHue = NCollection_Lerp<Standard_Real>::Interpolate (theHlsMin[0], theHlsMax[0], aValue);
69 Standard_Real aLightness = NCollection_Lerp<Standard_Real>::Interpolate (theHlsMin[1], theHlsMax[1], aValue);
70 Standard_Real aSaturation = NCollection_Lerp<Standard_Real>::Interpolate (theHlsMin[2], theHlsMax[2], aValue);
71 return Quantity_Color (AIS_ColorScale::hueToValidRange (aHue), aLightness, aSaturation, Quantity_TOC_HLS);
72 }
61f73653 73
74 //! Return the index of discrete interval for specified value.
75 //! Note that when value lies exactly on the border between two intervals,
76 //! determining which interval to return is undefined operation;
77 //! Current implementation returns the following interval in this case.
78 //! @param theValue [in] value to map
79 //! @param theMin [in] values range, lower value
80 //! @param theMax [in] values range, upper value
81 //! @param theNbIntervals [in] number of discrete intervals
82 //! @return index of interval within [1, theNbIntervals] range
83 static Standard_Integer colorDiscreteInterval (Standard_Real theValue,
84 Standard_Real theMin,
85 Standard_Real theMax,
86 Standard_Integer theNbIntervals)
87 {
88 if (Abs (theMax - theMin) <= Precision::Approximation())
89 {
90 return 1;
91 }
92
93 Standard_Integer anInterval = 1 + (Standard_Integer )Floor (Standard_Real (theNbIntervals) * (theValue - theMin) / (theMax - theMin));
94 // map the very upper value (theValue==theMax) to the largest color interval
95 anInterval = Min (anInterval, theNbIntervals);
96 return anInterval;
97 }
7a324550 98}
99
100//=======================================================================
4b3d6eb1 101//function : AIS_ColorScale
7a324550 102//purpose :
103//=======================================================================
4b3d6eb1 104AIS_ColorScale::AIS_ColorScale()
105: myMin (0.0),
106 myMax (1.0),
107 myColorHlsMin (230.0, 1.0, 1.0),
108 myColorHlsMax (0.0, 1.0, 1.0),
109 myFormat ("%.4g"),
110 myNbIntervals (10),
111 myColorType (Aspect_TOCSD_AUTO),
112 myLabelType (Aspect_TOCSD_AUTO),
113 myIsLabelAtBorder (Standard_True),
114 myIsReversed (Standard_False),
115 myIsLogarithmic (Standard_False),
116 myIsSmooth (Standard_False),
117 myLabelPos (Aspect_TOCSP_RIGHT),
118 myTitlePos (Aspect_TOCSP_LEFT),
119 myXPos (0),
120 myYPos (0),
121 myBreadth (0),
122 myHeight (0),
123 mySpacing (5),
124 myTextHeight (20)
125{
126 SetDisplayMode (0);
2a332745 127 myDrawer->SetupOwnShadingAspect();
13b36bb1 128 myDrawer->ShadingAspect()->Aspect()->SetShadingModel (Graphic3d_TypeOfShadingModel_Unlit);
2a332745 129 myDrawer->ShadingAspect()->Aspect()->SetAlphaMode (Graphic3d_AlphaMode_Opaque);
130 myDrawer->ShadingAspect()->Aspect()->SetInteriorColor (Quantity_NOC_WHITE);
7a324550 131}
132
133//=======================================================================
134//function : GetLabel
135//purpose :
136//=======================================================================
137TCollection_ExtendedString AIS_ColorScale::GetLabel (const Standard_Integer theIndex) const
138{
4b3d6eb1 139 if (myLabelType == Aspect_TOCSD_USER)
7a324550 140 {
4b3d6eb1 141 if (theIndex >= myLabels.Lower()
142 || theIndex <= myLabels.Upper())
7a324550 143 {
4b3d6eb1 144 return myLabels.Value(theIndex);
7a324550 145 }
4b3d6eb1 146 return TCollection_ExtendedString();
7a324550 147 }
180f89a2 148
149 // value to be shown depends on label position
4b3d6eb1 150 const Standard_Real aVal = myIsLabelAtBorder
151 ? GetIntervalValue (theIndex - 1)
152 : (0.5 * (GetIntervalValue (theIndex - 1) + GetIntervalValue (theIndex)));
180f89a2 153
4b3d6eb1 154 char aBuf[1024];
155 sprintf (aBuf, myFormat.ToCString(), aVal);
7a324550 156 return TCollection_ExtendedString (aBuf);
157}
158
159//=======================================================================
180f89a2 160//function : GetIntervalColor
7a324550 161//purpose :
162//=======================================================================
180f89a2 163Quantity_Color AIS_ColorScale::GetIntervalColor (const Standard_Integer theIndex) const
7a324550 164{
4b3d6eb1 165 if (myColorType== Aspect_TOCSD_USER)
7a324550 166 {
180f89a2 167 if (theIndex <= 0 || theIndex > myColors.Length())
7a324550 168 {
169 return Quantity_Color();
170 }
180f89a2 171 return myColors.Value (theIndex);
7a324550 172 }
180f89a2 173
4b3d6eb1 174 return colorFromValue (theIndex - 1, 0, myNbIntervals - 1);
7a324550 175}
176
177//=======================================================================
178//function : GetLabels
179//purpose :
180//=======================================================================
181void AIS_ColorScale::GetLabels (TColStd_SequenceOfExtendedString& theLabels) const
182{
183 theLabels.Clear();
4b3d6eb1 184 for (TColStd_SequenceOfExtendedString::Iterator aLabIter (myLabels); aLabIter.More(); aLabIter.Next())
185 {
186 theLabels.Append (aLabIter.Value());
187 }
7a324550 188}
189
190//=======================================================================
191//function : GetColors
192//purpose :
193//=======================================================================
194void AIS_ColorScale::GetColors (Aspect_SequenceOfColor& theColors) const
195{
196 theColors.Clear();
4b3d6eb1 197 for (Aspect_SequenceOfColor::Iterator aColorIter (myColors); aColorIter.More(); aColorIter.Next())
198 {
199 theColors.Append (aColorIter.Value());
200 }
7a324550 201}
202
203//=======================================================================
204//function : SetRange
205//purpose :
206//=======================================================================
207void AIS_ColorScale::SetRange (const Standard_Real theMin, const Standard_Real theMax)
208{
7a324550 209 myMin = Min (theMin, theMax);
210 myMax = Max (theMin, theMax);
211}
212
7a324550 213//=======================================================================
214//function : SetNumberOfIntervals
215//purpose :
216//=======================================================================
217void AIS_ColorScale::SetNumberOfIntervals (const Standard_Integer theNum)
218{
4b3d6eb1 219 if (theNum < 1)
220 {
7a324550 221 return;
4b3d6eb1 222 }
7a324550 223
4b3d6eb1 224 myNbIntervals = theNum;
7a324550 225}
226
227//=======================================================================
228//function : SetLabel
229//purpose :
230//=======================================================================
4b3d6eb1 231void AIS_ColorScale::SetLabel (const TCollection_ExtendedString& theLabel,
232 const Standard_Integer theIndex)
7a324550 233{
4b3d6eb1 234 const Standard_Integer aLabIndex = (theIndex <= 0 ? myLabels.Length() + 1 : theIndex);
235 while (myLabels.Length() < aLabIndex)
236 {
180f89a2 237 myLabels.Append (TCollection_ExtendedString());
4b3d6eb1 238 }
239 myLabels.SetValue (aLabIndex, theLabel);
7a324550 240}
241
242//=======================================================================
180f89a2 243//function : SetIntervalColor
7a324550 244//purpose :
245//=======================================================================
4b3d6eb1 246void AIS_ColorScale::SetIntervalColor (const Quantity_Color& theColor,
247 const Standard_Integer theIndex)
7a324550 248{
4b3d6eb1 249 const Standard_Integer aColorIndex = (theIndex <= 0 ? myColors.Length() + 1 : theIndex);
250 while (myColors.Length() < aColorIndex)
251 {
180f89a2 252 myColors.Append (Quantity_Color());
4b3d6eb1 253 }
254 myColors.SetValue (aColorIndex, theColor);
7a324550 255}
256
257//=======================================================================
258//function : SetLabels
259//purpose :
260//=======================================================================
261void AIS_ColorScale::SetLabels (const TColStd_SequenceOfExtendedString& theSeq)
262{
263 myLabels.Clear();
4b3d6eb1 264 for (TColStd_SequenceOfExtendedString::Iterator aLabIter (theSeq); aLabIter.More(); aLabIter.Next())
265 {
266 myLabels.Append (aLabIter.Value());
267 }
7a324550 268}
269
270//=======================================================================
271//function : SetColors
272//purpose :
273//=======================================================================
274void AIS_ColorScale::SetColors (const Aspect_SequenceOfColor& theSeq)
275{
276 myColors.Clear();
4b3d6eb1 277 for (Aspect_SequenceOfColor::Iterator aColorIter (theSeq); aColorIter.More(); aColorIter.Next())
278 {
279 myColors.Append (aColorIter.Value());
280 }
7a324550 281}
282
14b741b0 283//=======================================================================
284//function : MakeUniformColors
285//purpose :
286//=======================================================================
287Aspect_SequenceOfColor AIS_ColorScale::MakeUniformColors (Standard_Integer theNbColors,
288 Standard_Real theLightness,
289 Standard_Real theHueFrom,
290 Standard_Real theHueTo)
291{
292 Aspect_SequenceOfColor aResult;
293
294 // adjust range to be within (0, 360], with sign according to theHueFrom and theHueTo
295 Standard_Real aHueRange = std::fmod (theHueTo - theHueFrom, 360.);
296 const Standard_Real aHueEps = Precision::Angular() * 180. / M_PI;
297 if (Abs (aHueRange) <= aHueEps)
298 {
299 aHueRange = (aHueRange < 0 ? -360. : 360.);
300 }
301
302 // treat limit cases
303 if (theNbColors < 1)
304 {
305 return aResult;
306 }
307 if (theNbColors == 1)
308 {
309 Standard_Real aHue = std::fmod (theHueFrom, 360.);
310 if (aHue < 0.)
311 {
312 aHue += 360.;
313 }
314 Quantity_Color aColor (theLightness, 130., aHue, Quantity_TOC_CIELch);
315 aResult.Append (aColor);
316 return aResult;
317 }
318
319 // discretize the range with 1 degree step
320 const int NBCOLORS = 2 + (int)Abs (aHueRange / 1.);
321 Standard_Real aHueStep = aHueRange / (NBCOLORS - 1);
322 NCollection_Array1<Quantity_Color> aGrid (0, NBCOLORS - 1);
323 for (Standard_Integer i = 0; i < NBCOLORS; i++)
324 {
325 Standard_Real aHue = std::fmod (theHueFrom + i * aHueStep, 360.);
326 if (aHue < 0.)
327 {
328 aHue += 360.;
329 }
330 aGrid(i).SetValues (theLightness, 130., aHue, Quantity_TOC_CIELch);
331 }
332
333 // and compute distances between each two colors in a grid
334 TColStd_Array1OfReal aMetric (0, NBCOLORS - 1);
335 Standard_Real aLength = 0.;
336 for (Standard_Integer i = 0, j = NBCOLORS - 1; i < NBCOLORS; j = i++)
337 {
338 aLength += (aMetric(i) = aGrid(i).DeltaE2000 (aGrid(j)));
339 }
340
341 // determine desired step by distance;
342 // normally we aim to distribute colors from start to end
343 // of the range, but if distance between first and last points of the range
344 // is less than that step (e.g. range is full 360 deg),
345 // then distribute by the whole 360 deg scope to ensure that first
346 // and last colors are sufficiently distanced
347 Standard_Real aDStep = (aLength - aMetric.First()) / (theNbColors - 1);
348 if (aMetric.First() < aDStep)
349 {
350 aDStep = aLength / theNbColors;
351 }
352
353 // generate sequence
354 aResult.Append(aGrid(0));
355 Standard_Real aParam = 0., aPrev = 0., aTarget = aDStep;
356 for (int i = 1; i < NBCOLORS; i++)
357 {
358 aParam = aPrev + aMetric(i);
359 while (aTarget <= aParam)
360 {
361 float aCoefPrev = float((aParam - aTarget) / (aParam - aPrev));
362 float aCoefCurr = float((aTarget - aPrev) / (aParam - aPrev));
363 Quantity_Color aColor (aGrid(i).Rgb() * aCoefCurr + aGrid(i-1).Rgb() * aCoefPrev);
364 aResult.Append (aColor);
365 aTarget += aDStep;
366 }
367 aPrev = aParam;
368 }
369 if (aResult.Length() < theNbColors)
370 {
371 aResult.Append (aGrid.Last());
372 }
373 Standard_ASSERT_VOID (aResult.Length() == theNbColors, "Failed to generate requested nb of colors");
374 return aResult;
375}
376
7a324550 377//=======================================================================
378//function : SizeHint
379//purpose :
380//=======================================================================
381void AIS_ColorScale::SizeHint (Standard_Integer& theWidth, Standard_Integer& theHeight) const
382{
4b3d6eb1 383 const Standard_Integer aTextHeight = TextHeight ("");
384 const Standard_Integer aColorWidth = 20;
7a324550 385 Standard_Integer aTextWidth = 0;
4b3d6eb1 386 if (myLabelPos != Aspect_TOCSP_NONE)
180f89a2 387 {
4b3d6eb1 388 for (Standard_Integer aLabIter = (myIsLabelAtBorder ? 0 : 1); aLabIter <= myNbIntervals; ++aLabIter)
389 {
390 aTextWidth = Max (aTextWidth, TextWidth (GetLabel (aLabIter)));
391 }
180f89a2 392 }
7a324550 393
4b3d6eb1 394 const Standard_Integer aScaleWidth = aColorWidth + aTextWidth + (aTextWidth ? 3 : 2) * mySpacing;
395 const Standard_Integer aScaleHeight = (Standard_Integer)(1.5 * (myNbIntervals + (myIsLabelAtBorder ? 2 : 1)) * aTextHeight);
7a324550 396
4b3d6eb1 397 Standard_Integer aTitleWidth = 0;
180f89a2 398 Standard_Integer aTitleHeight = 0;
4b3d6eb1 399 if (!myTitle.IsEmpty())
7a324550 400 {
4b3d6eb1 401 aTitleHeight = TextHeight (myTitle) + mySpacing;
402 aTitleWidth = TextWidth (myTitle) + mySpacing * 2;
7a324550 403 }
404
4b3d6eb1 405 theWidth = Max (aTitleWidth, aScaleWidth);
7a324550 406 theHeight = aScaleHeight + aTitleHeight;
407}
408
7a324550 409//=======================================================================
180f89a2 410//function : GetIntervalValue
7a324550 411//purpose :
412//=======================================================================
180f89a2 413Standard_Real AIS_ColorScale::GetIntervalValue (const Standard_Integer theIndex) const
7a324550 414{
4b3d6eb1 415 if (myNbIntervals <= 0)
416 {
417 return 0.0;
418 }
7a324550 419
180f89a2 420 if (IsLogarithmic())
24a88697 421 {
4b3d6eb1 422 Standard_Real aMin = myMin > 0 ? myMin : 1.0;
423 Standard_Real aDivisor = std::pow (myMax / aMin, 1.0 / myNbIntervals);
424 return aMin * std::pow (aDivisor,theIndex);
24a88697 425 }
180f89a2 426
427 Standard_Real aNum = 0;
4b3d6eb1 428 if (myNbIntervals > 0)
429 {
430 aNum = GetMin() + theIndex * (Abs (GetMax() - GetMin()) / myNbIntervals);
431 }
180f89a2 432 return aNum;
24a88697 433}
434
435//=======================================================================
4b3d6eb1 436//function : colorFromValue
7a324550 437//purpose :
438//=======================================================================
4b3d6eb1 439Quantity_Color AIS_ColorScale::colorFromValue (const Standard_Real theValue,
440 const Standard_Real theMin,
441 const Standard_Real theMax) const
7a324550 442{
4b3d6eb1 443 return colorFromValueEx (theValue, theMin, theMax, myColorHlsMin, myColorHlsMax);
7a324550 444}
445
446//=======================================================================
447//function : FindColor
448//purpose :
449//=======================================================================
450Standard_Boolean AIS_ColorScale::FindColor (const Standard_Real theValue,
451 Quantity_Color& theColor) const
452{
d5514578 453 if (theValue < myMin || theValue > myMax || myMax < myMin)
454 {
455 theColor = Quantity_Color();
456 return Standard_False;
457 }
458
4b3d6eb1 459 if (myColorType == Aspect_TOCSD_USER)
d5514578 460 {
61f73653 461 const Standard_Integer anInterval = colorDiscreteInterval (theValue, myMin, myMax, myNbIntervals);
462 if (anInterval < myColors.Lower() || anInterval > myColors.Upper())
d5514578 463 {
464 theColor = Quantity_Color();
465 return Standard_False;
466 }
467
61f73653 468 theColor = myColors.Value (anInterval);
d5514578 469 return Standard_True;
470 }
471
4b3d6eb1 472 return FindColor (theValue, myMin, myMax, myNbIntervals, theColor);
7a324550 473}
474
475//=======================================================================
476//function : FindColor
477//purpose :
478//=======================================================================
479Standard_Boolean AIS_ColorScale::FindColor (const Standard_Real theValue,
480 const Standard_Real theMin,
481 const Standard_Real theMax,
482 const Standard_Integer theColorsCount,
4b3d6eb1 483 const Graphic3d_Vec3d& theColorHlsMin,
484 const Graphic3d_Vec3d& theColorHlsMax,
7a324550 485 Quantity_Color& theColor)
486{
487 if (theValue < theMin || theValue > theMax || theMax < theMin)
4b3d6eb1 488 {
7a324550 489 return Standard_False;
4b3d6eb1 490 }
7a324550 491
61f73653 492 const Standard_Integer anInterval = colorDiscreteInterval (theValue, theMin, theMax, theColorsCount);
493 theColor = colorFromValueEx (anInterval - 1, 0, theColorsCount - 1, theColorHlsMin, theColorHlsMax);
4b3d6eb1 494 return Standard_True;
495}
7a324550 496
4b3d6eb1 497//=======================================================================
498//function : computeMaxLabelWidth
499//purpose :
500//=======================================================================
501Standard_Integer AIS_ColorScale::computeMaxLabelWidth (const TColStd_SequenceOfExtendedString& theLabels) const
502{
4b3d6eb1 503 Standard_Integer aWidthMax = 0;
504 for (TColStd_SequenceOfExtendedString::Iterator aLabIter (theLabels); aLabIter.More(); aLabIter.Next())
505 {
506 if (!aLabIter.Value().IsEmpty())
507 {
508 aWidthMax = Max (aWidthMax, TextWidth (aLabIter.Value()));
509 }
7a324550 510 }
4b3d6eb1 511 return aWidthMax;
512}
513
514//=======================================================================
515//function : updateTextAspect
516//purpose :
517//=======================================================================
518void AIS_ColorScale::updateTextAspect()
519{
520 // update text aspect
521 const Quantity_Color aFgColor (hasOwnColor ? myDrawer->Color() : Quantity_NOC_WHITE);
522 if (!myDrawer->HasOwnTextAspect())
523 {
524 myDrawer->SetTextAspect (new Prs3d_TextAspect());
525 *myDrawer->TextAspect()->Aspect() = *myDrawer->Link()->TextAspect()->Aspect();
526 }
527
528 const Handle(Prs3d_TextAspect)& anAspect = myDrawer->TextAspect();
529 anAspect->SetColor (aFgColor);
530 anAspect->SetHeight (myTextHeight);
531 anAspect->SetHorizontalJustification (Graphic3d_HTA_LEFT);
532 anAspect->SetVerticalJustification (Graphic3d_VTA_BOTTOM);
533 anAspect->Aspect()->SetTextZoomable (Standard_True);
7a324550 534}
535
536//=======================================================================
537//function : Compute
538//purpose :
539//=======================================================================
decbff0d 540void AIS_ColorScale::Compute (const Handle(PrsMgr_PresentationManager)& ,
4b3d6eb1 541 const Handle(Prs3d_Presentation)& thePrs,
542 const Standard_Integer theMode)
7a324550 543{
4b3d6eb1 544 if (theMode != 0)
545 {
546 return;
547 }
7a324550 548
4b3d6eb1 549 // update text aspect
550 updateTextAspect();
551
552 const Standard_Integer aTitleOffset = !myTitle.IsEmpty() ? (myTextHeight + mySpacing) : 0;
553
554 const Standard_Integer aBarYOffset = myTextHeight / 2 + 2 * mySpacing; // a half-label offset
555 const Standard_Integer aBarBottom = myYPos + aBarYOffset;
556 const Standard_Integer aBarTop = myYPos + myHeight - aTitleOffset - aBarYOffset;
557 const Standard_Integer aBarHeight = aBarTop - aBarBottom;
558
4b3d6eb1 559 TColStd_SequenceOfExtendedString aLabels;
560 if (myLabelType == Aspect_TOCSD_USER)
561 {
562 aLabels = myLabels;
563 }
564 else
565 {
566 const Standard_Integer aNbLabels = myIsLabelAtBorder ? myNbIntervals + 1 : myNbIntervals;
567 for (Standard_Integer aLabIter = 1; aLabIter <= aNbLabels; ++aLabIter)
568 {
569 if (myIsReversed)
570 {
571 aLabels.Prepend (GetLabel (aLabIter));
572 }
573 else
574 {
575 aLabels.Append (GetLabel (aLabIter));
576 }
577 }
578 }
7a324550 579
4b3d6eb1 580 const Standard_Integer aTextWidth = myLabelPos != Aspect_TOCSP_NONE ? computeMaxLabelWidth (aLabels) : 0;
581 Standard_Integer aColorBreadth = Max (5, Min (20, myBreadth - aTextWidth - 3 * mySpacing));
582 if (myLabelPos == Aspect_TOCSP_CENTER
583 || myLabelPos == Aspect_TOCSP_NONE)
7a324550 584 {
4b3d6eb1 585 aColorBreadth += aTextWidth;
7a324550 586 }
587
2a332745 588 // draw title
589 Handle(Graphic3d_Group) aLabelsGroup;
590 if (!myTitle.IsEmpty()
591 || !aLabels.IsEmpty())
592 {
593 aLabelsGroup = thePrs->NewGroup();
594 aLabelsGroup->SetGroupPrimitivesAspect (myDrawer->TextAspect()->Aspect());
595 }
596 if (!myTitle.IsEmpty())
597 {
598 drawText (aLabelsGroup, myTitle,
599 myXPos + mySpacing,
600 aBarTop + aBarYOffset,
601 Graphic3d_VTA_BOTTOM);
602 }
603
4b3d6eb1 604 // draw colors
605 drawColorBar (thePrs, aBarBottom, aBarHeight, aTextWidth, aColorBreadth);
606
607 // draw Labels
2a332745 608 drawLabels (aLabelsGroup, aLabels, aBarBottom, aBarHeight, aTextWidth, aColorBreadth);
4b3d6eb1 609}
610
611//=======================================================================
612//function : drawColorBar
613//purpose :
614//=======================================================================
615void AIS_ColorScale::drawColorBar (const Handle(Prs3d_Presentation)& thePrs,
616 const Standard_Integer theBarBottom,
617 const Standard_Integer theBarHeight,
618 const Standard_Integer theMaxLabelWidth,
619 const Standard_Integer theColorBreadth)
620{
621 const Standard_Real aStepY = Standard_Real(theBarHeight) / Standard_Real(myNbIntervals);
622 if (aStepY <= 0.0)
623 {
624 return;
625 }
626
627 // Draw colors
628 const Standard_Integer anXLeft = myLabelPos == Aspect_TOCSP_LEFT
629 ? myXPos + mySpacing + theMaxLabelWidth + (theMaxLabelWidth != 0 ? 1 : 0) * mySpacing
630 : myXPos + mySpacing;
7a324550 631
632 Aspect_SequenceOfColor aColors;
4b3d6eb1 633 for (Standard_Integer anIntervalIter = 1; anIntervalIter <= myNbIntervals; ++anIntervalIter)
7a324550 634 {
4b3d6eb1 635 if (myIsReversed)
7a324550 636 {
4b3d6eb1 637 aColors.Prepend (GetIntervalColor (anIntervalIter));
7a324550 638 }
639 else
640 {
4b3d6eb1 641 aColors.Append (GetIntervalColor (anIntervalIter));
7a324550 642 }
643 }
644
4b3d6eb1 645 Handle(Graphic3d_ArrayOfTriangles) aTriangles;
646 if (myIsSmooth
647 && myColorType == Aspect_TOCSD_USER)
7a324550 648 {
4b3d6eb1 649 // Smooth custom intervals, so that the color in the center of interval is equal to specified one
650 // (thus the halves of first and last intervals have solid color)
651 aTriangles = new Graphic3d_ArrayOfTriangles ((aColors.Length() + 1) * 4, // quads
652 (aColors.Length() + 1) * 2 * 3, // quads as triangles
653 false, true); // per-vertex colors
654 Quantity_Color aColor1 (aColors.Value (1)), aColor2;
655 Standard_Integer aSizeY = Standard_Integer(aStepY / 2);
656 const Standard_Integer anYBottom = theBarBottom + aSizeY;
657 Standard_Integer anYBottomIter = anYBottom;
658 addColoredQuad (aTriangles,
659 anXLeft, theBarBottom,
660 theColorBreadth, aSizeY,
661 aColor1, aColor1);
662 for (Standard_Integer aColorIter = 0; aColorIter < myNbIntervals - 1; ++aColorIter)
180f89a2 663 {
4b3d6eb1 664 aColor1 = aColors.Value (aColorIter + 1);
665 aColor2 = aColors.Value (aColorIter + 2);
666 aSizeY = anYBottom + Standard_Integer((aColorIter + 1) * aStepY) - anYBottomIter;
667 addColoredQuad (aTriangles,
668 anXLeft, anYBottomIter,
669 theColorBreadth, aSizeY,
670 aColor1, aColor2);
671 anYBottomIter += aSizeY;
180f89a2 672 }
4b3d6eb1 673 aColor2 = aColors.Value (myNbIntervals);
674 aSizeY = theBarBottom + theBarHeight - anYBottomIter;
675 addColoredQuad (aTriangles,
676 anXLeft, anYBottomIter,
677 theColorBreadth, aSizeY,
678 aColor2, aColor2);
679 }
680 else if (myIsSmooth)
681 {
682 // smooth transition between standard colors - without solid color regions at the beginning and end of full color range
683 const Quantity_Color aColorsFixed[5] =
684 {
685 colorFromValue (0, 0, 4),
686 colorFromValue (1, 0, 4),
687 colorFromValue (2, 0, 4),
688 colorFromValue (3, 0, 4),
689 colorFromValue (4, 0, 4)
690 };
691 aTriangles = new Graphic3d_ArrayOfTriangles (4 * 4, // quads
692 4 * 2 * 3, // quads as triangles
693 false, true); // per-vertex colors
694 Standard_Integer anYBottomIter = theBarBottom;
695 addColoredQuad (aTriangles,
696 anXLeft, theBarBottom,
697 theColorBreadth, theBarHeight / 4,
698 aColorsFixed[0], aColorsFixed[1]);
699 anYBottomIter += theBarHeight / 4;
700 addColoredQuad (aTriangles,
701 anXLeft, anYBottomIter,
702 theColorBreadth, theBarHeight / 4,
703 aColorsFixed[1], aColorsFixed[2]);
704 anYBottomIter += theBarHeight / 4;
705 addColoredQuad (aTriangles,
706 anXLeft, anYBottomIter,
707 theColorBreadth, theBarHeight / 4,
708 aColorsFixed[2], aColorsFixed[3]);
709 anYBottomIter += theBarHeight / 4;
710 const Standard_Integer aLastSizeY = theBarBottom + theBarHeight - anYBottomIter;
711 addColoredQuad (aTriangles,
712 anXLeft, anYBottomIter,
713 theColorBreadth, aLastSizeY,
714 aColorsFixed[3], aColorsFixed[4]);
715 }
716 else
717 {
718 // no color smoothing
719 aTriangles = new Graphic3d_ArrayOfTriangles (aColors.Length() * 4, // quads
720 aColors.Length() * 2 * 3, // quads as triangles
721 false, true); // per-vertex colors
722 Standard_Integer anYBottomIter = theBarBottom;
723 for (Standard_Integer aColorIter = 0; aColorIter < myNbIntervals; ++aColorIter)
180f89a2 724 {
4b3d6eb1 725 const Quantity_Color& aColor = aColors.Value (aColorIter + 1);
726 const Standard_Integer aSizeY = theBarBottom + Standard_Integer((aColorIter + 1) * aStepY) - anYBottomIter;
727 addColoredQuad (aTriangles,
728 anXLeft, anYBottomIter,
729 theColorBreadth, aSizeY,
730 aColor, aColor);
731 anYBottomIter += aSizeY;
180f89a2 732 }
7a324550 733 }
734
2a332745 735 Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
736 aGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
4b3d6eb1 737 aGroup->AddPrimitiveArray (aTriangles);
7a324550 738
4b3d6eb1 739 const Quantity_Color aFgColor (hasOwnColor ? myDrawer->Color() : Quantity_NOC_WHITE);
740 drawFrame (thePrs,
741 anXLeft - 1, theBarBottom - 1,
742 theColorBreadth + 2,
743 theBarHeight + 2,
744 aFgColor);
745}
7a324550 746
4b3d6eb1 747//=======================================================================
748//function : drawLabels
749//purpose :
750//=======================================================================
2a332745 751void AIS_ColorScale::drawLabels (const Handle(Graphic3d_Group)& theGroup,
4b3d6eb1 752 const TColStd_SequenceOfExtendedString& theLabels,
753 const Standard_Integer theBarBottom,
754 const Standard_Integer theBarHeight,
755 const Standard_Integer theMaxLabelWidth,
756 const Standard_Integer theColorBreadth)
757{
758 if (myLabelPos == Aspect_TOCSP_NONE
759 || theLabels.IsEmpty())
760 {
761 return;
762 }
7a324550 763
4b3d6eb1 764 const Standard_Integer aNbLabels = theLabels.Size();
765 const Standard_Integer aNbIntervals = myIsLabelAtBorder ? aNbLabels - 1 : aNbLabels;
766 const Standard_Real aStepY = Standard_Real(theBarHeight) / Standard_Real(aNbIntervals);
767 if (aStepY <= 0.0)
768 {
769 return;
770 }
7a324550 771
4b3d6eb1 772 Standard_Integer aFilter = 0;
773 {
774 const Standard_Integer aTitleHeight = !myTitle.IsEmpty() ? (myTextHeight + 2 * mySpacing) : mySpacing;
775 const Standard_Integer aSpc = myHeight - aTitleHeight - ((Min (aNbLabels, 2) + Abs (aNbLabels - aNbIntervals - 1)) * myTextHeight);
776 if (aSpc <= 0)
777 {
778 return;
779 }
780
781 const Standard_Real aVal = Standard_Real(aNbLabels) * myTextHeight / aSpc;
782 Standard_Real anIPart = 0.0;
783 Standard_Real anFPart = std::modf (aVal, &anIPart);
784 aFilter = (Standard_Integer )anIPart + (anFPart != 0 ? 1 : 0);
785 }
786 if (aFilter <= 0)
787 {
788 return;
7a324550 789 }
7a324550 790
4b3d6eb1 791 Standard_Integer anXLeft = myXPos + mySpacing;
792 const Standard_Integer anAscent = 0;
793 switch (myLabelPos)
794 {
795 case Aspect_TOCSP_NONE:
796 case Aspect_TOCSP_LEFT:
797 {
798 break;
799 }
800 case Aspect_TOCSP_CENTER:
801 {
802 anXLeft += (theColorBreadth - theMaxLabelWidth) / 2;
803 break;
804 }
805 case Aspect_TOCSP_RIGHT:
806 {
807 anXLeft += theColorBreadth + mySpacing;
808 break;
809 }
810 }
7a324550 811
4b3d6eb1 812 Standard_Integer i1 = 0;
813 Standard_Integer i2 = aNbLabels - 1;
814 Standard_Integer aLast1 = i1;
815 Standard_Integer aLast2 = i2;
816 const Standard_Integer anYBottom = myIsLabelAtBorder
817 ? theBarBottom
818 : theBarBottom + Standard_Integer(aStepY / 2);
819 while (i2 - i1 >= aFilter || ( i2 == 0 && i1 == 0 ))
7a324550 820 {
4b3d6eb1 821 Standard_Integer aPos1 = i1;
822 Standard_Integer aPos2 = aNbLabels - 1 - i2;
823 if (aFilter && !(aPos1 % aFilter))
7a324550 824 {
2a332745 825 drawText (theGroup, theLabels.Value (i1 + 1),
4b3d6eb1 826 anXLeft, anYBottom + Standard_Integer(i1 * aStepY + anAscent),
827 Graphic3d_VTA_CENTER);
828 aLast1 = i1;
7a324550 829 }
4b3d6eb1 830 if (aFilter && !(aPos2 % aFilter))
7a324550 831 {
2a332745 832 drawText (theGroup, theLabels.Value (i2 + 1),
4b3d6eb1 833 anXLeft, anYBottom + Standard_Integer(i2 * aStepY + anAscent),
834 Graphic3d_VTA_CENTER);
835 aLast2 = i2;
7a324550 836 }
4b3d6eb1 837 i1++;
838 i2--;
839 }
840 Standard_Integer aPos = i1;
841 Standard_Integer i0 = -1;
842 while (aPos <= i2 && i0 == -1)
843 {
844 if (aFilter && !(aPos % aFilter)
845 && Abs (aPos - aLast1) >= aFilter
846 && Abs (aPos - aLast2) >= aFilter)
7a324550 847 {
4b3d6eb1 848 i0 = aPos;
7a324550 849 }
4b3d6eb1 850 aPos++;
851 }
7a324550 852
4b3d6eb1 853 if (i0 != -1)
854 {
2a332745 855 drawText (theGroup, theLabels.Value (i0 + 1),
4b3d6eb1 856 anXLeft, anYBottom + Standard_Integer(i0 * aStepY + anAscent),
857 Graphic3d_VTA_CENTER);
7a324550 858 }
859}
860
861//=======================================================================
7c65581d 862//function : drawFrame
7a324550 863//purpose :
864//=======================================================================
4b3d6eb1 865void AIS_ColorScale::drawFrame (const Handle(Prs3d_Presentation)& thePrs,
866 const Standard_Integer theX, const Standard_Integer theY,
867 const Standard_Integer theWidth, const Standard_Integer theHeight,
868 const Quantity_Color& theColor)
7a324550 869{
7a324550 870 Handle(Graphic3d_ArrayOfPolylines) aPrim = new Graphic3d_ArrayOfPolylines(5);
4b3d6eb1 871 aPrim->AddVertex (theX, theY, 0.0);
872 aPrim->AddVertex (theX + theWidth, theY, 0.0);
873 aPrim->AddVertex (theX + theWidth, theY + theHeight, 0.0);
874 aPrim->AddVertex (theX, theY + theHeight, 0.0);
875 aPrim->AddVertex (theX, theY, 0.0);
876
877 Handle(Graphic3d_AspectLine3d) anAspect = new Graphic3d_AspectLine3d (theColor, Aspect_TOL_SOLID, 1.0);
2a332745 878 Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
879 aGroup->SetGroupPrimitivesAspect (anAspect);
7a324550 880 aGroup->AddPrimitiveArray (aPrim);
881}
882
883//=======================================================================
7c65581d 884//function : drawText
7a324550 885//purpose :
886//=======================================================================
4b3d6eb1 887void AIS_ColorScale::drawText (const Handle(Graphic3d_Group)& theGroup,
888 const TCollection_ExtendedString& theText,
889 const Standard_Integer theX, const Standard_Integer theY,
890 const Graphic3d_VerticalTextAlignment theVertAlignment)
7a324550 891{
4b3d6eb1 892 const Handle(Prs3d_TextAspect)& anAspect = myDrawer->TextAspect();
4b3d6eb1 893
8ed07085 894 Handle(Graphic3d_Text) aText = new Graphic3d_Text ((Standard_ShortReal)anAspect->Height());
895 aText->SetText (theText.ToExtString());
896 aText->SetOrientation (gp_Ax2 (gp_Pnt (theX, theY, 0.0), gp::DZ()));
897 aText->SetOwnAnchorPoint (Standard_False);
898 aText->SetVerticalAlignment (theVertAlignment);
899
900 theGroup->AddText (aText);
7a324550 901}
902
903//=======================================================================
904//function : TextWidth
905//purpose :
906//=======================================================================
907Standard_Integer AIS_ColorScale::TextWidth (const TCollection_ExtendedString& theText) const
908{
902b31b6 909 Standard_Integer aWidth = 0, anAscent = 0, aDescent = 0;
4b3d6eb1 910 TextSize (theText, myTextHeight, aWidth, anAscent, aDescent);
7a324550 911 return aWidth;
912}
913
914//=======================================================================
915//function : TextHeight
916//purpose :
917//=======================================================================
918Standard_Integer AIS_ColorScale::TextHeight (const TCollection_ExtendedString& theText) const
919{
902b31b6 920 Standard_Integer aWidth = 0, anAscent = 0, aDescent = 0;
4b3d6eb1 921 TextSize (theText, myTextHeight, aWidth, anAscent, aDescent);
922 return anAscent + aDescent;
7a324550 923}
924
925//=======================================================================
926//function : TextSize
927//purpose :
928//=======================================================================
4b3d6eb1 929void AIS_ColorScale::TextSize (const TCollection_ExtendedString& theText,
930 const Standard_Integer theHeight,
931 Standard_Integer& theWidth,
932 Standard_Integer& theAscent,
933 Standard_Integer& theDescent) const
7a324550 934{
902b31b6 935 Standard_ShortReal aWidth = 10.0f, anAscent = 1.0f, aDescent = 1.0f;
936 if (HasInteractiveContext())
4b3d6eb1 937 {
902b31b6 938 const TCollection_AsciiString aText (theText);
939 const Handle(V3d_Viewer)& aViewer = GetContext()->CurrentViewer();
940 const Handle(Graphic3d_CView)& aView = aViewer->ActiveViewIterator().Value()->View();
941 aViewer->Driver()->TextSize (aView, aText.ToCString(), (Standard_ShortReal)theHeight, aWidth, anAscent, aDescent);
4b3d6eb1 942 }
4b3d6eb1 943 theWidth = (Standard_Integer)aWidth;
944 theAscent = (Standard_Integer)anAscent;
7a324550 945 theDescent = (Standard_Integer)aDescent;
946}