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