0030853: Visualization, AIS_ViewController - fix 1 pixel Y shift while zooming
[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>
29#include <Prs3d_LineAspect.hxx>
30#include <Prs3d_Root.hxx>
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 }
7a324550 81}
82
83//=======================================================================
4b3d6eb1 84//function : AIS_ColorScale
7a324550 85//purpose :
86//=======================================================================
4b3d6eb1 87AIS_ColorScale::AIS_ColorScale()
88: myMin (0.0),
89 myMax (1.0),
90 myColorHlsMin (230.0, 1.0, 1.0),
91 myColorHlsMax (0.0, 1.0, 1.0),
92 myFormat ("%.4g"),
93 myNbIntervals (10),
94 myColorType (Aspect_TOCSD_AUTO),
95 myLabelType (Aspect_TOCSD_AUTO),
96 myIsLabelAtBorder (Standard_True),
97 myIsReversed (Standard_False),
98 myIsLogarithmic (Standard_False),
99 myIsSmooth (Standard_False),
100 myLabelPos (Aspect_TOCSP_RIGHT),
101 myTitlePos (Aspect_TOCSP_LEFT),
102 myXPos (0),
103 myYPos (0),
104 myBreadth (0),
105 myHeight (0),
106 mySpacing (5),
107 myTextHeight (20)
108{
109 SetDisplayMode (0);
2a332745 110 myDrawer->SetupOwnShadingAspect();
111 myDrawer->ShadingAspect()->Aspect()->SetShadingModel (Graphic3d_TOSM_UNLIT);
112 myDrawer->ShadingAspect()->Aspect()->SetAlphaMode (Graphic3d_AlphaMode_Opaque);
113 myDrawer->ShadingAspect()->Aspect()->SetInteriorColor (Quantity_NOC_WHITE);
7a324550 114}
115
116//=======================================================================
117//function : GetLabel
118//purpose :
119//=======================================================================
120TCollection_ExtendedString AIS_ColorScale::GetLabel (const Standard_Integer theIndex) const
121{
4b3d6eb1 122 if (myLabelType == Aspect_TOCSD_USER)
7a324550 123 {
4b3d6eb1 124 if (theIndex >= myLabels.Lower()
125 || theIndex <= myLabels.Upper())
7a324550 126 {
4b3d6eb1 127 return myLabels.Value(theIndex);
7a324550 128 }
4b3d6eb1 129 return TCollection_ExtendedString();
7a324550 130 }
180f89a2 131
132 // value to be shown depends on label position
4b3d6eb1 133 const Standard_Real aVal = myIsLabelAtBorder
134 ? GetIntervalValue (theIndex - 1)
135 : (0.5 * (GetIntervalValue (theIndex - 1) + GetIntervalValue (theIndex)));
180f89a2 136
4b3d6eb1 137 char aBuf[1024];
138 sprintf (aBuf, myFormat.ToCString(), aVal);
7a324550 139 return TCollection_ExtendedString (aBuf);
140}
141
142//=======================================================================
180f89a2 143//function : GetIntervalColor
7a324550 144//purpose :
145//=======================================================================
180f89a2 146Quantity_Color AIS_ColorScale::GetIntervalColor (const Standard_Integer theIndex) const
7a324550 147{
4b3d6eb1 148 if (myColorType== Aspect_TOCSD_USER)
7a324550 149 {
180f89a2 150 if (theIndex <= 0 || theIndex > myColors.Length())
7a324550 151 {
152 return Quantity_Color();
153 }
180f89a2 154 return myColors.Value (theIndex);
7a324550 155 }
180f89a2 156
4b3d6eb1 157 return colorFromValue (theIndex - 1, 0, myNbIntervals - 1);
7a324550 158}
159
160//=======================================================================
161//function : GetLabels
162//purpose :
163//=======================================================================
164void AIS_ColorScale::GetLabels (TColStd_SequenceOfExtendedString& theLabels) const
165{
166 theLabels.Clear();
4b3d6eb1 167 for (TColStd_SequenceOfExtendedString::Iterator aLabIter (myLabels); aLabIter.More(); aLabIter.Next())
168 {
169 theLabels.Append (aLabIter.Value());
170 }
7a324550 171}
172
173//=======================================================================
174//function : GetColors
175//purpose :
176//=======================================================================
177void AIS_ColorScale::GetColors (Aspect_SequenceOfColor& theColors) const
178{
179 theColors.Clear();
4b3d6eb1 180 for (Aspect_SequenceOfColor::Iterator aColorIter (myColors); aColorIter.More(); aColorIter.Next())
181 {
182 theColors.Append (aColorIter.Value());
183 }
7a324550 184}
185
186//=======================================================================
187//function : SetRange
188//purpose :
189//=======================================================================
190void AIS_ColorScale::SetRange (const Standard_Real theMin, const Standard_Real theMax)
191{
7a324550 192 myMin = Min (theMin, theMax);
193 myMax = Max (theMin, theMax);
194}
195
7a324550 196//=======================================================================
197//function : SetNumberOfIntervals
198//purpose :
199//=======================================================================
200void AIS_ColorScale::SetNumberOfIntervals (const Standard_Integer theNum)
201{
4b3d6eb1 202 if (theNum < 1)
203 {
7a324550 204 return;
4b3d6eb1 205 }
7a324550 206
4b3d6eb1 207 myNbIntervals = theNum;
7a324550 208}
209
210//=======================================================================
211//function : SetLabel
212//purpose :
213//=======================================================================
4b3d6eb1 214void AIS_ColorScale::SetLabel (const TCollection_ExtendedString& theLabel,
215 const Standard_Integer theIndex)
7a324550 216{
4b3d6eb1 217 const Standard_Integer aLabIndex = (theIndex <= 0 ? myLabels.Length() + 1 : theIndex);
218 while (myLabels.Length() < aLabIndex)
219 {
180f89a2 220 myLabels.Append (TCollection_ExtendedString());
4b3d6eb1 221 }
222 myLabels.SetValue (aLabIndex, theLabel);
7a324550 223}
224
225//=======================================================================
180f89a2 226//function : SetIntervalColor
7a324550 227//purpose :
228//=======================================================================
4b3d6eb1 229void AIS_ColorScale::SetIntervalColor (const Quantity_Color& theColor,
230 const Standard_Integer theIndex)
7a324550 231{
4b3d6eb1 232 const Standard_Integer aColorIndex = (theIndex <= 0 ? myColors.Length() + 1 : theIndex);
233 while (myColors.Length() < aColorIndex)
234 {
180f89a2 235 myColors.Append (Quantity_Color());
4b3d6eb1 236 }
237 myColors.SetValue (aColorIndex, theColor);
7a324550 238}
239
240//=======================================================================
241//function : SetLabels
242//purpose :
243//=======================================================================
244void AIS_ColorScale::SetLabels (const TColStd_SequenceOfExtendedString& theSeq)
245{
246 myLabels.Clear();
4b3d6eb1 247 for (TColStd_SequenceOfExtendedString::Iterator aLabIter (theSeq); aLabIter.More(); aLabIter.Next())
248 {
249 myLabels.Append (aLabIter.Value());
250 }
7a324550 251}
252
253//=======================================================================
254//function : SetColors
255//purpose :
256//=======================================================================
257void AIS_ColorScale::SetColors (const Aspect_SequenceOfColor& theSeq)
258{
259 myColors.Clear();
4b3d6eb1 260 for (Aspect_SequenceOfColor::Iterator aColorIter (theSeq); aColorIter.More(); aColorIter.Next())
261 {
262 myColors.Append (aColorIter.Value());
263 }
7a324550 264}
265
266//=======================================================================
267//function : SizeHint
268//purpose :
269//=======================================================================
270void AIS_ColorScale::SizeHint (Standard_Integer& theWidth, Standard_Integer& theHeight) const
271{
4b3d6eb1 272 const Standard_Integer aTextHeight = TextHeight ("");
273 const Standard_Integer aColorWidth = 20;
7a324550 274 Standard_Integer aTextWidth = 0;
4b3d6eb1 275 if (myLabelPos != Aspect_TOCSP_NONE)
180f89a2 276 {
4b3d6eb1 277 for (Standard_Integer aLabIter = (myIsLabelAtBorder ? 0 : 1); aLabIter <= myNbIntervals; ++aLabIter)
278 {
279 aTextWidth = Max (aTextWidth, TextWidth (GetLabel (aLabIter)));
280 }
180f89a2 281 }
7a324550 282
4b3d6eb1 283 const Standard_Integer aScaleWidth = aColorWidth + aTextWidth + (aTextWidth ? 3 : 2) * mySpacing;
284 const Standard_Integer aScaleHeight = (Standard_Integer)(1.5 * (myNbIntervals + (myIsLabelAtBorder ? 2 : 1)) * aTextHeight);
7a324550 285
4b3d6eb1 286 Standard_Integer aTitleWidth = 0;
180f89a2 287 Standard_Integer aTitleHeight = 0;
4b3d6eb1 288 if (!myTitle.IsEmpty())
7a324550 289 {
4b3d6eb1 290 aTitleHeight = TextHeight (myTitle) + mySpacing;
291 aTitleWidth = TextWidth (myTitle) + mySpacing * 2;
7a324550 292 }
293
4b3d6eb1 294 theWidth = Max (aTitleWidth, aScaleWidth);
7a324550 295 theHeight = aScaleHeight + aTitleHeight;
296}
297
7a324550 298//=======================================================================
180f89a2 299//function : GetIntervalValue
7a324550 300//purpose :
301//=======================================================================
180f89a2 302Standard_Real AIS_ColorScale::GetIntervalValue (const Standard_Integer theIndex) const
7a324550 303{
4b3d6eb1 304 if (myNbIntervals <= 0)
305 {
306 return 0.0;
307 }
7a324550 308
180f89a2 309 if (IsLogarithmic())
24a88697 310 {
4b3d6eb1 311 Standard_Real aMin = myMin > 0 ? myMin : 1.0;
312 Standard_Real aDivisor = std::pow (myMax / aMin, 1.0 / myNbIntervals);
313 return aMin * std::pow (aDivisor,theIndex);
24a88697 314 }
180f89a2 315
316 Standard_Real aNum = 0;
4b3d6eb1 317 if (myNbIntervals > 0)
318 {
319 aNum = GetMin() + theIndex * (Abs (GetMax() - GetMin()) / myNbIntervals);
320 }
180f89a2 321 return aNum;
24a88697 322}
323
324//=======================================================================
4b3d6eb1 325//function : colorFromValue
7a324550 326//purpose :
327//=======================================================================
4b3d6eb1 328Quantity_Color AIS_ColorScale::colorFromValue (const Standard_Real theValue,
329 const Standard_Real theMin,
330 const Standard_Real theMax) const
7a324550 331{
4b3d6eb1 332 return colorFromValueEx (theValue, theMin, theMax, myColorHlsMin, myColorHlsMax);
7a324550 333}
334
335//=======================================================================
336//function : FindColor
337//purpose :
338//=======================================================================
339Standard_Boolean AIS_ColorScale::FindColor (const Standard_Real theValue,
340 Quantity_Color& theColor) const
341{
d5514578 342 if (theValue < myMin || theValue > myMax || myMax < myMin)
343 {
344 theColor = Quantity_Color();
345 return Standard_False;
346 }
347
4b3d6eb1 348 if (myColorType == Aspect_TOCSD_USER)
d5514578 349 {
350 Standard_Integer anIndex = 0;
351 if (Abs (myMax - myMin) > Precision::Approximation())
352 {
353 anIndex = (theValue - myMin < Precision::Confusion())
354 ? 1
4b3d6eb1 355 : Standard_Integer (Ceiling (( theValue - myMin ) / ( (myMax - myMin) / myNbIntervals)));
d5514578 356 }
357
358 if (anIndex <= 0 || anIndex > myColors.Length())
359 {
360 theColor = Quantity_Color();
361 return Standard_False;
362 }
363
364 theColor = myColors.Value (anIndex);
365 return Standard_True;
366 }
367
4b3d6eb1 368 return FindColor (theValue, myMin, myMax, myNbIntervals, theColor);
7a324550 369}
370
371//=======================================================================
372//function : FindColor
373//purpose :
374//=======================================================================
375Standard_Boolean AIS_ColorScale::FindColor (const Standard_Real theValue,
376 const Standard_Real theMin,
377 const Standard_Real theMax,
378 const Standard_Integer theColorsCount,
4b3d6eb1 379 const Graphic3d_Vec3d& theColorHlsMin,
380 const Graphic3d_Vec3d& theColorHlsMax,
7a324550 381 Quantity_Color& theColor)
382{
383 if (theValue < theMin || theValue > theMax || theMax < theMin)
4b3d6eb1 384 {
7a324550 385 return Standard_False;
4b3d6eb1 386 }
7a324550 387
4b3d6eb1 388 Standard_Real anInterval = 0.0;
389 if (Abs (theMax - theMin) > Precision::Approximation())
7a324550 390 {
4b3d6eb1 391 anInterval = Floor (Standard_Real (theColorsCount) * (theValue - theMin) / (theMax - theMin));
392 }
7a324550 393
4b3d6eb1 394 theColor = colorFromValueEx (anInterval, 0, theColorsCount - 1, theColorHlsMin, theColorHlsMax);
395 return Standard_True;
396}
7a324550 397
4b3d6eb1 398//=======================================================================
399//function : computeMaxLabelWidth
400//purpose :
401//=======================================================================
402Standard_Integer AIS_ColorScale::computeMaxLabelWidth (const TColStd_SequenceOfExtendedString& theLabels) const
403{
404 {
405 Handle(V3d_Viewer) aViewer = GetContext()->CurrentViewer();
406 aViewer->InitActiveViews(); // for AIS_ColorScale::TextSize()
407 }
7a324550 408
4b3d6eb1 409 Standard_Integer aWidthMax = 0;
410 for (TColStd_SequenceOfExtendedString::Iterator aLabIter (theLabels); aLabIter.More(); aLabIter.Next())
411 {
412 if (!aLabIter.Value().IsEmpty())
413 {
414 aWidthMax = Max (aWidthMax, TextWidth (aLabIter.Value()));
415 }
7a324550 416 }
4b3d6eb1 417 return aWidthMax;
418}
419
420//=======================================================================
421//function : updateTextAspect
422//purpose :
423//=======================================================================
424void AIS_ColorScale::updateTextAspect()
425{
426 // update text aspect
427 const Quantity_Color aFgColor (hasOwnColor ? myDrawer->Color() : Quantity_NOC_WHITE);
428 if (!myDrawer->HasOwnTextAspect())
429 {
430 myDrawer->SetTextAspect (new Prs3d_TextAspect());
431 *myDrawer->TextAspect()->Aspect() = *myDrawer->Link()->TextAspect()->Aspect();
432 }
433
434 const Handle(Prs3d_TextAspect)& anAspect = myDrawer->TextAspect();
435 anAspect->SetColor (aFgColor);
436 anAspect->SetHeight (myTextHeight);
437 anAspect->SetHorizontalJustification (Graphic3d_HTA_LEFT);
438 anAspect->SetVerticalJustification (Graphic3d_VTA_BOTTOM);
439 anAspect->Aspect()->SetTextZoomable (Standard_True);
7a324550 440}
441
442//=======================================================================
443//function : Compute
444//purpose :
445//=======================================================================
4b3d6eb1 446void AIS_ColorScale::Compute (const Handle(PrsMgr_PresentationManager3d)& ,
447 const Handle(Prs3d_Presentation)& thePrs,
448 const Standard_Integer theMode)
7a324550 449{
4b3d6eb1 450 if (theMode != 0)
451 {
452 return;
453 }
7a324550 454
4b3d6eb1 455 // update text aspect
456 updateTextAspect();
457
458 const Standard_Integer aTitleOffset = !myTitle.IsEmpty() ? (myTextHeight + mySpacing) : 0;
459
460 const Standard_Integer aBarYOffset = myTextHeight / 2 + 2 * mySpacing; // a half-label offset
461 const Standard_Integer aBarBottom = myYPos + aBarYOffset;
462 const Standard_Integer aBarTop = myYPos + myHeight - aTitleOffset - aBarYOffset;
463 const Standard_Integer aBarHeight = aBarTop - aBarBottom;
464
4b3d6eb1 465 TColStd_SequenceOfExtendedString aLabels;
466 if (myLabelType == Aspect_TOCSD_USER)
467 {
468 aLabels = myLabels;
469 }
470 else
471 {
472 const Standard_Integer aNbLabels = myIsLabelAtBorder ? myNbIntervals + 1 : myNbIntervals;
473 for (Standard_Integer aLabIter = 1; aLabIter <= aNbLabels; ++aLabIter)
474 {
475 if (myIsReversed)
476 {
477 aLabels.Prepend (GetLabel (aLabIter));
478 }
479 else
480 {
481 aLabels.Append (GetLabel (aLabIter));
482 }
483 }
484 }
7a324550 485
4b3d6eb1 486 const Standard_Integer aTextWidth = myLabelPos != Aspect_TOCSP_NONE ? computeMaxLabelWidth (aLabels) : 0;
487 Standard_Integer aColorBreadth = Max (5, Min (20, myBreadth - aTextWidth - 3 * mySpacing));
488 if (myLabelPos == Aspect_TOCSP_CENTER
489 || myLabelPos == Aspect_TOCSP_NONE)
7a324550 490 {
4b3d6eb1 491 aColorBreadth += aTextWidth;
7a324550 492 }
493
2a332745 494 // draw title
495 Handle(Graphic3d_Group) aLabelsGroup;
496 if (!myTitle.IsEmpty()
497 || !aLabels.IsEmpty())
498 {
499 aLabelsGroup = thePrs->NewGroup();
500 aLabelsGroup->SetGroupPrimitivesAspect (myDrawer->TextAspect()->Aspect());
501 }
502 if (!myTitle.IsEmpty())
503 {
504 drawText (aLabelsGroup, myTitle,
505 myXPos + mySpacing,
506 aBarTop + aBarYOffset,
507 Graphic3d_VTA_BOTTOM);
508 }
509
4b3d6eb1 510 // draw colors
511 drawColorBar (thePrs, aBarBottom, aBarHeight, aTextWidth, aColorBreadth);
512
513 // draw Labels
2a332745 514 drawLabels (aLabelsGroup, aLabels, aBarBottom, aBarHeight, aTextWidth, aColorBreadth);
4b3d6eb1 515}
516
517//=======================================================================
518//function : drawColorBar
519//purpose :
520//=======================================================================
521void AIS_ColorScale::drawColorBar (const Handle(Prs3d_Presentation)& thePrs,
522 const Standard_Integer theBarBottom,
523 const Standard_Integer theBarHeight,
524 const Standard_Integer theMaxLabelWidth,
525 const Standard_Integer theColorBreadth)
526{
527 const Standard_Real aStepY = Standard_Real(theBarHeight) / Standard_Real(myNbIntervals);
528 if (aStepY <= 0.0)
529 {
530 return;
531 }
532
533 // Draw colors
534 const Standard_Integer anXLeft = myLabelPos == Aspect_TOCSP_LEFT
535 ? myXPos + mySpacing + theMaxLabelWidth + (theMaxLabelWidth != 0 ? 1 : 0) * mySpacing
536 : myXPos + mySpacing;
7a324550 537
538 Aspect_SequenceOfColor aColors;
4b3d6eb1 539 for (Standard_Integer anIntervalIter = 1; anIntervalIter <= myNbIntervals; ++anIntervalIter)
7a324550 540 {
4b3d6eb1 541 if (myIsReversed)
7a324550 542 {
4b3d6eb1 543 aColors.Prepend (GetIntervalColor (anIntervalIter));
7a324550 544 }
545 else
546 {
4b3d6eb1 547 aColors.Append (GetIntervalColor (anIntervalIter));
7a324550 548 }
549 }
550
4b3d6eb1 551 Handle(Graphic3d_ArrayOfTriangles) aTriangles;
552 if (myIsSmooth
553 && myColorType == Aspect_TOCSD_USER)
7a324550 554 {
4b3d6eb1 555 // Smooth custom intervals, so that the color in the center of interval is equal to specified one
556 // (thus the halves of first and last intervals have solid color)
557 aTriangles = new Graphic3d_ArrayOfTriangles ((aColors.Length() + 1) * 4, // quads
558 (aColors.Length() + 1) * 2 * 3, // quads as triangles
559 false, true); // per-vertex colors
560 Quantity_Color aColor1 (aColors.Value (1)), aColor2;
561 Standard_Integer aSizeY = Standard_Integer(aStepY / 2);
562 const Standard_Integer anYBottom = theBarBottom + aSizeY;
563 Standard_Integer anYBottomIter = anYBottom;
564 addColoredQuad (aTriangles,
565 anXLeft, theBarBottom,
566 theColorBreadth, aSizeY,
567 aColor1, aColor1);
568 for (Standard_Integer aColorIter = 0; aColorIter < myNbIntervals - 1; ++aColorIter)
180f89a2 569 {
4b3d6eb1 570 aColor1 = aColors.Value (aColorIter + 1);
571 aColor2 = aColors.Value (aColorIter + 2);
572 aSizeY = anYBottom + Standard_Integer((aColorIter + 1) * aStepY) - anYBottomIter;
573 addColoredQuad (aTriangles,
574 anXLeft, anYBottomIter,
575 theColorBreadth, aSizeY,
576 aColor1, aColor2);
577 anYBottomIter += aSizeY;
180f89a2 578 }
4b3d6eb1 579 aColor2 = aColors.Value (myNbIntervals);
580 aSizeY = theBarBottom + theBarHeight - anYBottomIter;
581 addColoredQuad (aTriangles,
582 anXLeft, anYBottomIter,
583 theColorBreadth, aSizeY,
584 aColor2, aColor2);
585 }
586 else if (myIsSmooth)
587 {
588 // smooth transition between standard colors - without solid color regions at the beginning and end of full color range
589 const Quantity_Color aColorsFixed[5] =
590 {
591 colorFromValue (0, 0, 4),
592 colorFromValue (1, 0, 4),
593 colorFromValue (2, 0, 4),
594 colorFromValue (3, 0, 4),
595 colorFromValue (4, 0, 4)
596 };
597 aTriangles = new Graphic3d_ArrayOfTriangles (4 * 4, // quads
598 4 * 2 * 3, // quads as triangles
599 false, true); // per-vertex colors
600 Standard_Integer anYBottomIter = theBarBottom;
601 addColoredQuad (aTriangles,
602 anXLeft, theBarBottom,
603 theColorBreadth, theBarHeight / 4,
604 aColorsFixed[0], aColorsFixed[1]);
605 anYBottomIter += theBarHeight / 4;
606 addColoredQuad (aTriangles,
607 anXLeft, anYBottomIter,
608 theColorBreadth, theBarHeight / 4,
609 aColorsFixed[1], aColorsFixed[2]);
610 anYBottomIter += theBarHeight / 4;
611 addColoredQuad (aTriangles,
612 anXLeft, anYBottomIter,
613 theColorBreadth, theBarHeight / 4,
614 aColorsFixed[2], aColorsFixed[3]);
615 anYBottomIter += theBarHeight / 4;
616 const Standard_Integer aLastSizeY = theBarBottom + theBarHeight - anYBottomIter;
617 addColoredQuad (aTriangles,
618 anXLeft, anYBottomIter,
619 theColorBreadth, aLastSizeY,
620 aColorsFixed[3], aColorsFixed[4]);
621 }
622 else
623 {
624 // no color smoothing
625 aTriangles = new Graphic3d_ArrayOfTriangles (aColors.Length() * 4, // quads
626 aColors.Length() * 2 * 3, // quads as triangles
627 false, true); // per-vertex colors
628 Standard_Integer anYBottomIter = theBarBottom;
629 for (Standard_Integer aColorIter = 0; aColorIter < myNbIntervals; ++aColorIter)
180f89a2 630 {
4b3d6eb1 631 const Quantity_Color& aColor = aColors.Value (aColorIter + 1);
632 const Standard_Integer aSizeY = theBarBottom + Standard_Integer((aColorIter + 1) * aStepY) - anYBottomIter;
633 addColoredQuad (aTriangles,
634 anXLeft, anYBottomIter,
635 theColorBreadth, aSizeY,
636 aColor, aColor);
637 anYBottomIter += aSizeY;
180f89a2 638 }
7a324550 639 }
640
2a332745 641 Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
642 aGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
4b3d6eb1 643 aGroup->AddPrimitiveArray (aTriangles);
7a324550 644
4b3d6eb1 645 const Quantity_Color aFgColor (hasOwnColor ? myDrawer->Color() : Quantity_NOC_WHITE);
646 drawFrame (thePrs,
647 anXLeft - 1, theBarBottom - 1,
648 theColorBreadth + 2,
649 theBarHeight + 2,
650 aFgColor);
651}
7a324550 652
4b3d6eb1 653//=======================================================================
654//function : drawLabels
655//purpose :
656//=======================================================================
2a332745 657void AIS_ColorScale::drawLabels (const Handle(Graphic3d_Group)& theGroup,
4b3d6eb1 658 const TColStd_SequenceOfExtendedString& theLabels,
659 const Standard_Integer theBarBottom,
660 const Standard_Integer theBarHeight,
661 const Standard_Integer theMaxLabelWidth,
662 const Standard_Integer theColorBreadth)
663{
664 if (myLabelPos == Aspect_TOCSP_NONE
665 || theLabels.IsEmpty())
666 {
667 return;
668 }
7a324550 669
4b3d6eb1 670 const Standard_Integer aNbLabels = theLabels.Size();
671 const Standard_Integer aNbIntervals = myIsLabelAtBorder ? aNbLabels - 1 : aNbLabels;
672 const Standard_Real aStepY = Standard_Real(theBarHeight) / Standard_Real(aNbIntervals);
673 if (aStepY <= 0.0)
674 {
675 return;
676 }
7a324550 677
4b3d6eb1 678 Standard_Integer aFilter = 0;
679 {
680 const Standard_Integer aTitleHeight = !myTitle.IsEmpty() ? (myTextHeight + 2 * mySpacing) : mySpacing;
681 const Standard_Integer aSpc = myHeight - aTitleHeight - ((Min (aNbLabels, 2) + Abs (aNbLabels - aNbIntervals - 1)) * myTextHeight);
682 if (aSpc <= 0)
683 {
684 return;
685 }
686
687 const Standard_Real aVal = Standard_Real(aNbLabels) * myTextHeight / aSpc;
688 Standard_Real anIPart = 0.0;
689 Standard_Real anFPart = std::modf (aVal, &anIPart);
690 aFilter = (Standard_Integer )anIPart + (anFPart != 0 ? 1 : 0);
691 }
692 if (aFilter <= 0)
693 {
694 return;
7a324550 695 }
7a324550 696
4b3d6eb1 697 Standard_Integer anXLeft = myXPos + mySpacing;
698 const Standard_Integer anAscent = 0;
699 switch (myLabelPos)
700 {
701 case Aspect_TOCSP_NONE:
702 case Aspect_TOCSP_LEFT:
703 {
704 break;
705 }
706 case Aspect_TOCSP_CENTER:
707 {
708 anXLeft += (theColorBreadth - theMaxLabelWidth) / 2;
709 break;
710 }
711 case Aspect_TOCSP_RIGHT:
712 {
713 anXLeft += theColorBreadth + mySpacing;
714 break;
715 }
716 }
7a324550 717
4b3d6eb1 718 Standard_Integer i1 = 0;
719 Standard_Integer i2 = aNbLabels - 1;
720 Standard_Integer aLast1 = i1;
721 Standard_Integer aLast2 = i2;
722 const Standard_Integer anYBottom = myIsLabelAtBorder
723 ? theBarBottom
724 : theBarBottom + Standard_Integer(aStepY / 2);
725 while (i2 - i1 >= aFilter || ( i2 == 0 && i1 == 0 ))
7a324550 726 {
4b3d6eb1 727 Standard_Integer aPos1 = i1;
728 Standard_Integer aPos2 = aNbLabels - 1 - i2;
729 if (aFilter && !(aPos1 % aFilter))
7a324550 730 {
2a332745 731 drawText (theGroup, theLabels.Value (i1 + 1),
4b3d6eb1 732 anXLeft, anYBottom + Standard_Integer(i1 * aStepY + anAscent),
733 Graphic3d_VTA_CENTER);
734 aLast1 = i1;
7a324550 735 }
4b3d6eb1 736 if (aFilter && !(aPos2 % aFilter))
7a324550 737 {
2a332745 738 drawText (theGroup, theLabels.Value (i2 + 1),
4b3d6eb1 739 anXLeft, anYBottom + Standard_Integer(i2 * aStepY + anAscent),
740 Graphic3d_VTA_CENTER);
741 aLast2 = i2;
7a324550 742 }
4b3d6eb1 743 i1++;
744 i2--;
745 }
746 Standard_Integer aPos = i1;
747 Standard_Integer i0 = -1;
748 while (aPos <= i2 && i0 == -1)
749 {
750 if (aFilter && !(aPos % aFilter)
751 && Abs (aPos - aLast1) >= aFilter
752 && Abs (aPos - aLast2) >= aFilter)
7a324550 753 {
4b3d6eb1 754 i0 = aPos;
7a324550 755 }
4b3d6eb1 756 aPos++;
757 }
7a324550 758
4b3d6eb1 759 if (i0 != -1)
760 {
2a332745 761 drawText (theGroup, theLabels.Value (i0 + 1),
4b3d6eb1 762 anXLeft, anYBottom + Standard_Integer(i0 * aStepY + anAscent),
763 Graphic3d_VTA_CENTER);
7a324550 764 }
765}
766
767//=======================================================================
7c65581d 768//function : drawFrame
7a324550 769//purpose :
770//=======================================================================
4b3d6eb1 771void AIS_ColorScale::drawFrame (const Handle(Prs3d_Presentation)& thePrs,
772 const Standard_Integer theX, const Standard_Integer theY,
773 const Standard_Integer theWidth, const Standard_Integer theHeight,
774 const Quantity_Color& theColor)
7a324550 775{
7a324550 776 Handle(Graphic3d_ArrayOfPolylines) aPrim = new Graphic3d_ArrayOfPolylines(5);
4b3d6eb1 777 aPrim->AddVertex (theX, theY, 0.0);
778 aPrim->AddVertex (theX + theWidth, theY, 0.0);
779 aPrim->AddVertex (theX + theWidth, theY + theHeight, 0.0);
780 aPrim->AddVertex (theX, theY + theHeight, 0.0);
781 aPrim->AddVertex (theX, theY, 0.0);
782
783 Handle(Graphic3d_AspectLine3d) anAspect = new Graphic3d_AspectLine3d (theColor, Aspect_TOL_SOLID, 1.0);
2a332745 784 Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
785 aGroup->SetGroupPrimitivesAspect (anAspect);
7a324550 786 aGroup->AddPrimitiveArray (aPrim);
787}
788
789//=======================================================================
7c65581d 790//function : drawText
7a324550 791//purpose :
792//=======================================================================
4b3d6eb1 793void AIS_ColorScale::drawText (const Handle(Graphic3d_Group)& theGroup,
794 const TCollection_ExtendedString& theText,
795 const Standard_Integer theX, const Standard_Integer theY,
796 const Graphic3d_VerticalTextAlignment theVertAlignment)
7a324550 797{
4b3d6eb1 798 const Handle(Prs3d_TextAspect)& anAspect = myDrawer->TextAspect();
4b3d6eb1 799 theGroup->Text (theText,
800 gp_Ax2 (gp_Pnt (theX, theY, 0.0), gp::DZ()),
801 anAspect->Height(),
802 anAspect->Angle(),
803 anAspect->Orientation(),
804 Graphic3d_HTA_LEFT,
805 theVertAlignment,
806 Standard_True,
807 Standard_False); // has own anchor
808
7a324550 809}
810
811//=======================================================================
812//function : TextWidth
813//purpose :
814//=======================================================================
815Standard_Integer AIS_ColorScale::TextWidth (const TCollection_ExtendedString& theText) const
816{
817 Standard_Integer aWidth, anAscent, aDescent;
4b3d6eb1 818 TextSize (theText, myTextHeight, aWidth, anAscent, aDescent);
7a324550 819 return aWidth;
820}
821
822//=======================================================================
823//function : TextHeight
824//purpose :
825//=======================================================================
826Standard_Integer AIS_ColorScale::TextHeight (const TCollection_ExtendedString& theText) const
827{
828 Standard_Integer aWidth, anAscent, aDescent;
4b3d6eb1 829 TextSize (theText, myTextHeight, aWidth, anAscent, aDescent);
830 return anAscent + aDescent;
7a324550 831}
832
833//=======================================================================
834//function : TextSize
835//purpose :
836//=======================================================================
4b3d6eb1 837void AIS_ColorScale::TextSize (const TCollection_ExtendedString& theText,
838 const Standard_Integer theHeight,
839 Standard_Integer& theWidth,
840 Standard_Integer& theAscent,
841 Standard_Integer& theDescent) const
7a324550 842{
4b3d6eb1 843 if (!HasInteractiveContext())
844 {
845 return;
846 }
847
848 Standard_ShortReal aWidth = 10.0f;
849 Standard_ShortReal anAscent = 1.0f;
850 Standard_ShortReal aDescent = 1.0f;
851 const TCollection_AsciiString aText (theText);
852
853 const Handle(V3d_Viewer)& aViewer = GetContext()->CurrentViewer();
854 const Handle(Graphic3d_CView)& aView = aViewer->ActiveViewIterator().Value()->View();
855 aViewer->Driver()->TextSize (aView, aText.ToCString(), (Standard_ShortReal)theHeight, aWidth, anAscent, aDescent);
856 theWidth = (Standard_Integer)aWidth;
857 theAscent = (Standard_Integer)anAscent;
7a324550 858 theDescent = (Standard_Integer)aDescent;
859}