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