1
/**************************************************************************\
3
* This file is part of the Coin 3D visualization library.
4
* Copyright (C) 1998-2005 by Systems in Motion. All rights reserved.
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License
8
* ("GPL") version 2 as published by the Free Software Foundation.
9
* See the file LICENSE.GPL at the root directory of this source
10
* distribution for additional information about the GNU GPL.
12
* For using Coin with software that can not be combined with the GNU
13
* GPL, and for taking advantage of the additional benefits of our
14
* support services, please contact Systems in Motion about acquiring
15
* a Coin Professional Edition License.
17
* See <URL:http://www.coin3d.org/> for more information.
19
* Systems in Motion, Postboks 1283, Pirsenteret, 7462 Trondheim, NORWAY.
20
* <URL:http://www.sim.no/>.
22
\**************************************************************************/
26
#endif /* HAVE_CONFIG_H */
28
#include <Inventor/errors/SoDebugError.h>
29
#include <Inventor/actions/SoGLRenderAction.h>
30
#include <Inventor/actions/SoHandleEventAction.h>
31
#include <Inventor/misc/SoState.h>
32
#include <Inventor/elements/SoLazyElement.h>
33
#include <Inventor/sensors/SoFieldSensor.h>
34
#include <Inventor/events/SoMouseButtonEvent.h>
35
#include <Inventor/events/SoLocation2Event.h>
36
#include <Inventor/SoPickedPoint.h>
37
#include <Inventor/SoLists.h>
39
#include <Inventor/nodes/SoSeparator.h>
40
#include <Inventor/nodes/SoMaterial.h>
41
#include <Inventor/nodes/SoTexture2.h>
42
#include <Inventor/nodes/SoCoordinate3.h>
43
#include <Inventor/nodes/SoTextureCoordinate2.h>
44
#include <Inventor/nodes/SoIndexedFaceSet.h>
45
#include <Inventor/nodes/SoIndexedLineSet.h>
47
#include <Inventor/Qt/common/gl.h>
48
#include <Inventor/Qt/SoQtBasic.h>
50
#include <Inventor/Qt/nodes/SoGuiPane.h>
51
#include <Inventor/Qt/nodes/SoGuiSlider1.h>
54
// *************************************************************************
57
\class SoGuiSlider1 Inventor/Qt/nodes/SoGuiSlider1.h
58
\brief A GUI component for a 1-dimensional slider.
60
The SoGuiSlider1 node is for creating 2D user interfaces with
67
orientation - not supported yet
71
// *************************************************************************
76
SoFieldSensor * sizeSensor;
77
SoFieldSensor * valueSensor;
78
SoFieldSensor * minSensor;
79
SoFieldSensor * maxSensor;
91
SbColor mincolor, maxcolor;
94
static void sizeChangeCB(void * closure, SoSensor * sensor);
95
static void valueChangeCB(void * closure, SoSensor * sensor);
96
static void minChangeCB(void * closure, SoSensor * sensor);
97
static void maxChangeCB(void * closure, SoSensor * sensor);
100
Slider1::Slider1(void)
103
this->sizeSensor = NULL;
104
this->valueSensor = NULL;
105
this->minSensor = NULL;
106
this->maxSensor = NULL;
107
this->grabbing = FALSE;
111
#define DELETE_SENSOR(sensor) \
112
if ( (sensor) != NULL ) { \
113
(sensor)->detach(); \
118
Slider1::~Slider1(void)
120
DELETE_SENSOR(this->sizeSensor);
121
DELETE_SENSOR(this->valueSensor);
122
DELETE_SENSOR(this->minSensor);
123
DELETE_SENSOR(this->maxSensor);
130
Slider1::sizeChangeCB(void * closure, SoSensor * sensor)
133
Slider1 * internals = (Slider1 *) closure;
134
assert(internals->kit);
135
internals->kit->sizeUpdate();
139
Slider1::valueChangeCB(void * closure, SoSensor * sensor)
142
Slider1 * internals = (Slider1 *) closure;
143
assert(internals->kit);
144
internals->kit->valueUpdate();
148
Slider1::minChangeCB(void * closure, SoSensor * sensor)
151
Slider1 * internals = (Slider1 *) closure;
152
assert(internals->kit);
153
internals->kit->minUpdate();
157
Slider1::maxChangeCB(void * closure, SoSensor * sensor)
160
Slider1 * internals = (Slider1 *) closure;
161
assert(internals->kit);
162
internals->kit->maxUpdate();
165
// *************************************************************************
167
#define PRIVATE(obj) ((Slider1 *) obj->internals)
170
SoGuiSlider1::initClass(void)
172
SO_KIT_INIT_CLASS(SoGuiSlider1, SoBaseKit, "BaseKit");
175
SO_KIT_SOURCE(SoGuiSlider1);
177
SoGuiSlider1::SoGuiSlider1(void)
179
this->internals = (void *) new Slider1;
180
PRIVATE(this)->kit = this;
182
SO_KIT_CONSTRUCTOR(SoGuiSlider1);
184
SO_KIT_ADD_FIELD(size, (SbVec3f(1.0f, 1.0f, 0.0f)));
185
SO_KIT_ADD_FIELD(orientation, (SoGuiSlider1::X));
186
SO_KIT_ADD_FIELD(min, (0.0f));
187
SO_KIT_ADD_FIELD(max, (1.0f));
188
SO_KIT_ADD_FIELD(value, (0.0f));
189
SO_KIT_ADD_FIELD(alwaysHook, (TRUE));
191
SO_KIT_DEFINE_ENUM_VALUE(Orientation, X);
192
SO_KIT_DEFINE_ENUM_VALUE(Orientation, Y);
194
SO_KIT_SET_SF_ENUM_TYPE(orientation, Orientation);
196
SO_KIT_ADD_CATALOG_ENTRY(knobLightLineSet, SoIndexedLineSet, FALSE, knobGeometry, "", FALSE);
197
SO_KIT_ADD_CATALOG_ENTRY(knobLightMaterial, SoMaterial, FALSE, knobGeometry, knobLightLineSet, TRUE);
198
SO_KIT_ADD_CATALOG_ENTRY(knobShadeLineSet, SoIndexedLineSet, FALSE, knobGeometry, knobLightMaterial, FALSE);
199
SO_KIT_ADD_CATALOG_ENTRY(knobShadeMaterial, SoMaterial, FALSE, knobGeometry, knobShadeLineSet, TRUE);
200
SO_KIT_ADD_CATALOG_ENTRY(knobFaceSet, SoIndexedFaceSet, FALSE, knobGeometry, knobShadeMaterial, FALSE);
201
SO_KIT_ADD_CATALOG_ENTRY(knobMaterial, SoMaterial, FALSE, knobGeometry, knobFaceSet, TRUE);
202
SO_KIT_ADD_CATALOG_ENTRY(knobCoords, SoCoordinate3, FALSE, knobGeometry, knobMaterial, FALSE);
204
SO_KIT_ADD_CATALOG_ENTRY(knobGeometry, SoSeparator, FALSE, topSeparator, "", FALSE);
205
SO_KIT_ADD_CATALOG_ENTRY(surfaceFaceSet, SoIndexedFaceSet, FALSE, surfaceGeometry, "", FALSE);
206
SO_KIT_ADD_CATALOG_ENTRY(surfaceCoords, SoCoordinate3, FALSE, surfaceGeometry, surfaceFaceSet, FALSE);
207
SO_KIT_ADD_CATALOG_ENTRY(surfaceTexCoords, SoTextureCoordinate2, FALSE, surfaceGeometry, surfaceCoords, FALSE);
208
SO_KIT_ADD_CATALOG_ENTRY(surfaceTexture, SoTexture2, TRUE, surfaceGeometry, surfaceTexCoords, TRUE);
209
SO_KIT_ADD_CATALOG_ENTRY(surfaceMaterial, SoMaterial, TRUE, surfaceGeometry, surfaceTexture, TRUE);
210
SO_KIT_ADD_CATALOG_ENTRY(surfaceGeometry, SoSeparator, FALSE, topSeparator, knobGeometry, FALSE);
211
SO_KIT_ADD_CATALOG_ENTRY(topSeparator, SoSeparator, FALSE, this, "", FALSE);
213
SO_KIT_INIT_INSTANCE();
215
static float surfacetexturecoordinates[][2] = { {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 0.0f} };
216
SoTextureCoordinate2 * surfacetexcoords = SO_GET_ANY_PART(this, "surfaceTexCoords", SoTextureCoordinate2);
217
assert(surfacetexcoords);
218
surfacetexcoords->point.setValues(0, 4, surfacetexturecoordinates);
220
static int32_t surfaceindices[] = { 0, 1, 2, -1, 0, 2, 3, -1 };
221
SoIndexedFaceSet * surfacefaceset = SO_GET_ANY_PART(this, "surfaceFaceSet", SoIndexedFaceSet);
222
assert(surfacefaceset);
223
surfacefaceset->textureCoordIndex.setValues(0, 8, surfaceindices);
224
surfacefaceset->coordIndex.setValues(0, 8, surfaceindices);
226
static int32_t knobindices[] = {
227
0, 1, 2, -1, 0, 2, 3, -1,
228
4, 5, 6, -1, 4, 6, 7, -1,
229
8, 2, 5, -1, 8, 5, 9, -1,
230
3, 11, 10, -1, 3, 10, 4, -1
232
SoIndexedFaceSet * knobfaceset = SO_GET_ANY_PART(this, "knobFaceSet", SoIndexedFaceSet);
234
knobfaceset->coordIndex.setValues(0, sizeof(knobindices)/sizeof(knobindices[0]), knobindices);
238
SoMaterial * knobmaterial = SO_GET_ANY_PART(this, "knobMaterial", SoMaterial);
239
assert(knobmaterial);
240
knobmaterial->ambientColor.setValue(0.6f, 0.6f, 0.6f);
241
knobmaterial->diffuseColor.setValue(0.6f, 0.6f, 0.6f);
242
knobmaterial->emissiveColor.setValue(0.6f, 0.6f, 0.6f);
244
SoMaterial * knoblightmaterial = SO_GET_ANY_PART(this, "knobLightMaterial", SoMaterial);
245
assert(knoblightmaterial);
246
knoblightmaterial->ambientColor.setValue(0.75f, 0.75f, 0.75f);
247
knoblightmaterial->diffuseColor.setValue(0.75f, 0.75f, 0.75f);
248
knoblightmaterial->emissiveColor.setValue(0.75f, 0.75f, 0.75f);
250
SoMaterial * knobshadowmaterial = SO_GET_ANY_PART(this, "knobShadeMaterial", SoMaterial);
251
assert(knobshadowmaterial);
252
knobshadowmaterial->ambientColor.setValue(0.4f, 0.4f, 0.4f);
253
knobshadowmaterial->diffuseColor.setValue(0.4f, 0.4f, 0.4f);
254
knobshadowmaterial->emissiveColor.setValue(0.4f, 0.4f, 0.4f);
256
// FIXME: move these to correct coordinates
257
SoIndexedLineSet * lightlineset = SO_GET_ANY_PART(this, "knobLightLineSet", SoIndexedLineSet);
258
assert(lightlineset);
259
static int32_t lightindices[] = { 16, 17, 18, -1, 12, 15, 14, -1 };
260
lightlineset->coordIndex.setValues(0, sizeof(lightindices) / sizeof(lightindices[0]), lightindices);
262
SoIndexedLineSet * shadelineset = SO_GET_ANY_PART(this, "knobShadeLineSet", SoIndexedLineSet);
263
assert(shadelineset);
264
static int32_t shadeindices[] = { 12, 13, 14, -1, 16, 19, 18, -1 };
265
shadelineset->coordIndex.setValues(0, sizeof(shadeindices) / sizeof(shadeindices[0]), shadeindices);
268
PRIVATE(this)->sizeSensor = new SoFieldSensor(Slider1::sizeChangeCB, PRIVATE(this));
269
PRIVATE(this)->sizeSensor->attach(&(this->size));
270
PRIVATE(this)->valueSensor = new SoFieldSensor(Slider1::valueChangeCB, PRIVATE(this));
271
PRIVATE(this)->valueSensor->attach(&(this->value));
272
PRIVATE(this)->minSensor = new SoFieldSensor(Slider1::minChangeCB, PRIVATE(this));
273
PRIVATE(this)->minSensor->attach(&(this->min));
274
PRIVATE(this)->maxSensor = new SoFieldSensor(Slider1::maxChangeCB, PRIVATE(this));
275
PRIVATE(this)->maxSensor->attach(&(this->max));
278
SoGuiSlider1::~SoGuiSlider1(void)
280
Slider1 * obj = PRIVATE(this);
282
this->internals = NULL;
286
SoGuiSlider1::setSurfaceColor(const SbColor & valuearg)
288
// FIXME: use Material or basecolor instead of texture
289
this->setSurfaceColor(valuearg, valuearg);
291
PRIVATE(this)->mincolor = valuearg;
292
PRIVATE(this)->maxcolor = valuearg;
293
this->setPart("surfaceTexture", NULL);
298
SoGuiSlider1::setSurfaceColor(const SbColor & minvalue, const SbColor & maxvalue)
300
PRIVATE(this)->mincolor = minvalue;
301
PRIVATE(this)->maxcolor = maxvalue;
303
this->setPart("surfaceMaterial", NULL);
304
SoTexture2 * texturenode = SO_GET_ANY_PART(this, "surfaceTexture", SoTexture2);
307
texturenode->image.setValue(SbVec2s(256, 1), 3, NULL);
308
texturenode->model.setValue(SoTexture2::DECAL);
312
unsigned char * buf = texturenode->image.startEditing(sizeval, nc);
313
float rmin = minvalue[0];
314
float gmin = minvalue[1];
315
float bmin = minvalue[2];
316
float rmax = maxvalue[0];
317
float gmax = maxvalue[1];
318
float bmax = maxvalue[2];
319
for ( int x = 0; x < sizeval[0]; x += 1 ) {
320
buf[x*nc+0] = (unsigned char) ((rmin + ((float) x / (float) (sizeval[0]-1)) * (rmax - rmin)) * 255.0f);
321
buf[x*nc+1] = (unsigned char) ((gmin + ((float) x / (float) (sizeval[0]-1)) * (gmax - gmin)) * 255.0f);
322
buf[x*nc+2] = (unsigned char) ((bmin + ((float) x / (float) (sizeval[0]-1)) * (bmax - bmin)) * 255.0f);
323
for ( int y = 1; y < sizeval[1]; y += 1 ) {
324
buf[(y*sizeval[0]+x)*nc+0] = buf[x*nc+0];
325
buf[(y*sizeval[0]+x)*nc+1] = buf[x*nc+1];
326
buf[(y*sizeval[0]+x)*nc+2] = buf[x*nc+2];
329
texturenode->image.finishEditing();
333
SoGuiSlider1::getValueAsColor(void) const
335
// FIXME: support custom textures
336
float val = this->value.getValue();
337
float minval = this->min.getValue();
338
float maxval = this->max.getValue();
339
float factor = (maxval - minval) / (val - minval);
340
float r = SoQtClamp(PRIVATE(this)->mincolor[0] + (PRIVATE(this)->maxcolor[0] - PRIVATE(this)->mincolor[0]) * factor, 0.0f, 1.0f);
341
float g = SoQtClamp(PRIVATE(this)->mincolor[1] + (PRIVATE(this)->maxcolor[1] - PRIVATE(this)->mincolor[1]) * factor, 0.0f, 1.0f);
342
float b = SoQtClamp(PRIVATE(this)->mincolor[2] + (PRIVATE(this)->maxcolor[2] - PRIVATE(this)->mincolor[2]) * factor, 0.0f, 1.0f);
343
return SbColor(r, g, b);
347
SoGuiSlider1::sizeUpdate(void)
349
SbVec3f sizeval = this->size.getValue();
350
if ( sizeval[0] != 0.0f && sizeval[1] != 0.0f ) {
351
float coordinates[][3] = { {0.0f, 0.0f, 0.0f}, {sizeval[0], 0.0f, 0.0f}, {sizeval[0], sizeval[1], 0.0f}, {0.0f, sizeval[1], 0.0f} };
352
SoCoordinate3 * coords = SO_GET_ANY_PART(this, "surfaceCoords", SoCoordinate3);
354
coords->point.setValues(0, sizeof(coordinates) / sizeof(coordinates[0]), coordinates);
360
SoGuiSlider1::valueUpdate(void)
362
SbVec3f sizeval = this->size.getValue();
363
float val = this->value.getValue();
364
float minval = this->min.getValue();
365
float maxval = this->max.getValue();
366
if ( minval < maxval ) {
367
if ( val < minval ) {
368
this->value.setValue(minval);
370
} else if ( val > maxval ) {
371
this->value.setValue(maxval);
375
// we also support inverse sliders where min > max
376
if ( val > minval ) {
377
this->value.setValue(minval);
379
} else if ( val < maxval ) {
380
this->value.setValue(maxval);
384
// store previous height & value to avoid redundant updates
385
float voff = (float) floor(((val - minval) / (maxval - minval)) * sizeval[0]);
386
float knobcoordinates[][3] = {
388
{-7.0f+voff, -4.0f, 0.0f}, {8.0f+voff, -4.0f, 0.0f}, {8.0f+voff, -1.0f, 0.0f}, {-7.0f+voff, -1.0f, 0.0f},
389
{-7.0f+voff, sizeval[1]+1.0f, 0.0f}, {8.0f+voff, sizeval[1]+1.0f, 0.0f}, {8.0f+voff, sizeval[1]+4.0f, 0.0f}, {-7.0f+voff, sizeval[1]+4.0f, 0.0f},
390
{3.0f+voff, -1.0f, 0.0f}, {3.0f+voff, sizeval[1]+1.0f, 0.0f}, {-2.0f+voff, sizeval[1]+1.0f, 0.0f}, {-2.0f+voff, -1.0f, 0.0f},
392
// also used in handleEvent() so don't change their significance based on index
393
{-8.0f+voff, -5.0f, 0.0f}, {8.0f+voff, -5.0f, 0.0f}, {8.0f+voff, sizeval[1]+4.0f, 0.0f}, {-8.0f+voff, sizeval[1]+4.0f, 0.0f},
395
{-2.0f+voff, -1.0f, 0.0f}, {2.0f+voff, -1.0f, 0.0f}, {2.0f+voff, sizeval[1], 0.0f}, {-2.0f+voff, sizeval[1], 0.0f}
397
SoCoordinate3 * knobcoords = SO_GET_ANY_PART(this, "knobCoords", SoCoordinate3);
399
knobcoords->point.setValues(0, sizeof(knobcoordinates) / sizeof(knobcoordinates[0]), knobcoordinates);
403
SoGuiSlider1::minUpdate(void)
405
float minval = this->min.getValue();
406
float maxval = this->max.getValue();
407
float val = this->value.getValue();
408
if ( minval < maxval ) {
409
if ( val < minval ) this->value.setValue(minval);
411
if ( val > minval ) this->value.setValue(minval);
416
SoGuiSlider1::maxUpdate(void)
418
float minval = this->min.getValue();
419
float maxval = this->max.getValue();
420
float val = this->value.getValue();
421
if ( minval < maxval ) {
422
if ( val > maxval ) this->value.setValue(maxval);
424
if ( val < maxval ) this->value.setValue(maxval);
429
SoGuiSlider1::handleEvent(SoHandleEventAction * action)
431
if ( action->isHandled() ) return;
432
const SoEvent * event = action->getEvent();
434
if ( PRIVATE(this)->grabbing ) { // click-and-drag
435
if ( event->isOfType(SoLocation2Event::getClassTypeId()) ) {
436
assert(PRIVATE(this)->pane != NULL);
437
// although the return value is discarded, we need to make this call to make
438
// sure the raypick action is run over the scene graph so the pane can return
440
action->getPickedPoint();
441
SbVec2f raypos = PRIVATE(this)->pane->getRayPickIntersectionPoint();
442
if ( raypos[0] != -1.0f ) {
443
float imagpos = raypos[0] + PRIVATE(this)->graboffset;
444
float minval = this->min.getValue();
445
float maxval = this->max.getValue();
447
if ( minval < maxval ) imagval = SoQtClamp(imagpos / this->size.getValue()[0], minval, maxval);
448
else imagval = SoQtClamp(imagpos / this->size.getValue()[0], maxval, minval);
449
this->value.setValue(imagval);
451
action->setHandled();
453
else if ( event->isOfType(SoMouseButtonEvent::getClassTypeId()) ) {
454
SoMouseButtonEvent * mbevent = (SoMouseButtonEvent *) event;
455
if ( (mbevent->getButton() == SoMouseButtonEvent::BUTTON1) &&
456
(mbevent->getState() == SoButtonEvent::UP) ) {
457
PRIVATE(this)->grabbing = FALSE;
458
PRIVATE(this)->pane = NULL;
459
action->setHandled();
463
else if ( event->isOfType(SoMouseButtonEvent::getClassTypeId()) ) {
464
SoMouseButtonEvent * mbevent = (SoMouseButtonEvent *) event;
465
if ( (mbevent->getButton() == SoMouseButtonEvent::BUTTON1) &&
466
(mbevent->getState() == SoButtonEvent::DOWN) ) {
467
action->setPickRadius(0);
468
const SoPickedPointList & pplist = action->getPickedPointList();
469
if ( pplist.getLength() > 0 ) {
471
for ( i = 0; i < pplist.getLength(); i++ ) {
472
if ( action->isHandled() ) break;
473
const SoPickedPoint * pp = pplist[i];
474
const SoPath * path = pp->getPath();
475
SoNode * node = ((SoFullPath *) path)->getTail();
476
if ( node == ((SoNode *) SO_GET_ANY_PART(this, "knobFaceSet", SoIndexedFaceSet)) ) {
477
SbVec3f point = pp->getObjectPoint();
478
SbVec3f sizeval = this->size.getValue();
479
SoCoordinate3 * knobcoords = SO_GET_ANY_PART(this, "knobCoords", SoCoordinate3);
481
SbVec3f knobmin = knobcoords->point[12];
482
SbVec3f knobmax = knobcoords->point[14];
483
if ( point[0] >= knobmin[0] && point[0] <= knobmax[0] &&
484
point[1] >= knobmin[1] && point[1] <= knobmax[1] ) {
485
PRIVATE(this)->grabbing = TRUE;
486
action->setHandled();
488
const SoFullPath * path = (const SoFullPath *) action->getCurPath();
489
int i = path->getLength() - 1;
490
SoNode * node = NULL;
491
for ( ; i >= 0; i-- ) {
492
node = path->getNode(i);
493
if ( node->isOfType(SoGuiPane::getClassTypeId()) ) break;
496
assert(node != NULL);
497
PRIVATE(this)->pane = (SoGuiPane *) node;
498
PRIVATE(this)->grabval = this->value.getValue();
499
PRIVATE(this)->pickpos = point[0];
501
SbVec2f raypos = PRIVATE(this)->pane->getRayPickIntersectionPoint();
502
PRIVATE(this)->grabpos = raypos[0];
503
float realval = ((this->value.getValue() - this->min.getValue()) /
504
(this->max.getValue() - this->min.getValue())) * this->size.getValue()[0];
505
PRIVATE(this)->graboffset = realval - raypos[0];
509
for ( i = 0; i < pplist.getLength(); i++ ) {
510
if ( action->isHandled() ) break;
511
const SoPickedPoint * pp = pplist[i];
512
const SoPath * path = pp->getPath();
513
SoNode * node = ((SoFullPath *) path)->getTail();
514
if ( node == ((SoNode *) SO_GET_ANY_PART(this, "surfaceFaceSet", SoIndexedFaceSet)) ) {
515
SbVec3f point = pp->getObjectPoint();
516
SbVec3f sizeval = this->size.getValue();
517
this->value = this->min.getValue() + ((point[0] / sizeval[0]) * (this->max.getValue() - this->min.getValue()));
518
action->setHandled();
519
if ( this->alwaysHook.getValue() ) {
520
PRIVATE(this)->grabbing = TRUE;
521
const SoFullPath * path = (const SoFullPath *) action->getCurPath();
522
int i = path->getLength() - 1;
523
SoNode * node = NULL;
524
for ( ; i >= 0; i-- ) {
525
node = path->getNode(i);
526
if ( node->isOfType(SoGuiPane::getClassTypeId()) ) break;
529
assert(node != NULL);
530
PRIVATE(this)->pane = (SoGuiPane *) node;
531
PRIVATE(this)->grabval = this->value.getValue();
532
PRIVATE(this)->pickpos = point[0];
533
SbVec2f raypos = PRIVATE(this)->pane->getRayPickIntersectionPoint();
534
PRIVATE(this)->grabpos = raypos[0];
535
float realval = ((this->value.getValue() - this->min.getValue()) /
536
(this->max.getValue() - this->min.getValue())) * this->size.getValue()[0];
537
PRIVATE(this)->graboffset = realval - raypos[0];