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 |
42 | IMPLEMENT_STANDARD_RTTIEXT(AIS_ColorScale, AIS_InteractiveObject) |
7a324550 |
43 | |
4b3d6eb1 |
44 | namespace |
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 |
87 | AIS_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 | //======================================================================= |
120 | TCollection_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 |
146 | Quantity_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 | //======================================================================= |
164 | void 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 | //======================================================================= |
177 | void 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 | //======================================================================= |
190 | void 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 | //======================================================================= |
200 | void 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 |
214 | void 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 |
229 | void 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 | //======================================================================= |
244 | void 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 | //======================================================================= |
257 | void 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 | //======================================================================= |
270 | void 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 |
302 | Standard_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 |
328 | Quantity_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 | //======================================================================= |
339 | Standard_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 | //======================================================================= |
375 | Standard_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 | //======================================================================= |
402 | Standard_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 | //======================================================================= |
424 | void 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 |
446 | void 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 | //======================================================================= |
521 | void 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 |
657 | void 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 |
771 | void 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 |
793 | void 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 | //======================================================================= |
815 | Standard_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 | //======================================================================= |
826 | Standard_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 |
837 | void 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 | } |