ATLAS Offline Software
Loading...
Searching...
No Matches
VP1People.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5
7// //
8// Implementation of class VP1People //
9// //
10// Author: Riccardo Maria BIANCHI <riccardo.maria.bianchi@cern.ch> //
11// Initial version: November 2021 //
12// //
14
16
19
20#include <Inventor/nodes/SoMaterial.h>
21#include <Inventor/nodes/SoMaterialBinding.h>
22#include <Inventor/nodes/SoCube.h>
23#include <Inventor/nodes/SoSeparator.h>
24#include <Inventor/nodes/SoTransform.h>
25#include <Inventor/nodes/SoTranslation.h>
26#include <Inventor/nodes/SoRotationXYZ.h>
27#include <Inventor/nodes/SoScale.h>
28#include <Inventor/SbViewportRegion.h>
29#include <Inventor/actions/SoGetBoundingBoxAction.h>
30#include <Inventor/VRMLnodes/SoVRMLMaterial.h>
31
32#include <Inventor/actions/SoSearchAction.h>
33#include <Inventor/actions/SoWriteAction.h>
34#include <Inventor/nodes/SoSeparator.h>
35#include <Inventor/nodes/SoTexture2.h>
36#include <Inventor/SoDB.h>
37#include <Inventor/SoInput.h>
38#include <Inventor/SoOutput.h>
39
40#include <QFile>
41#include <QFileInfo>
42#include <QTemporaryDir>
43
44#include <algorithm>
45#include <vector>
46
47#ifdef BUILDVP1LIGHT
48 #include "CLHEP/Units/SystemOfUnits.h"
49 #define SYSTEM_OF_UNITS CLHEP
50#else
51 #include "GaudiKernel/SystemOfUnits.h"
52 #define SYSTEM_OF_UNITS Gaudi::Units
53#endif
54
55//____________________________________________________________________
57public:
58 Imp(VP1People *,
59 SoMaterial * mat,
60 SoSeparator * attachsep);
62 SoMaterial * material;
63 SoSeparator * attachSep;
64
65 SoSeparator* loadModel(const std::string& fpath);
66 double getScaleFactor(SoNode* node, double desiredHeight);
67
68 bool shown;
69 SbColor4f colourAndTransp;
70 double zpos;
71 double vertpos;
72
73 SoSeparator * sep;
74 SoTranslation * trans1;
75 SoTranslation * trans2;
76 SoTranslation * trans3;
77
78 void updateFields();
80 void updateColour();
81
82};
83
84//____________________________________________________________________
85VP1People::VP1People(SoMaterial * mat,SoSeparator * attachsep,
86 IVP1System * sys,QObject * parent)
87 : QObject(parent), VP1HelperClassBase(sys,"VP1People"), m_d(new Imp(this,mat,attachsep))
88{
89}
90
91//____________________________________________________________________
93{
94 setShown(false);
95 if (m_d->sep)
96 m_d->sep->unref();
97 if (m_d->trans1)
98 m_d->trans1->unref();
99 if (m_d->trans2)
100 m_d->trans2->unref();
101 m_d->material->unref();
102 m_d->attachSep->unref();
103 delete m_d;
104}
105
106//____________________________________________________________________
107VP1People::Imp::Imp(VP1People *tc,SoMaterial * mat,SoSeparator * as)
108 : theclass(tc), material(mat), attachSep(as), shown(false),
109 zpos(0),vertpos(0), sep(0), trans1(0), trans2(0), trans3(0)
110{
111 material->ref();
112 attachSep->ref();
113}
114
115
116
117//____________________________________________________________________
118SoSeparator* VP1People::Imp::loadModel(const std::string& fpath)
119{
120 SoDB::init();
121 SoInput myInput;
122 if (!myInput.openFile(fpath.c_str()))
123 exit (1);
124 SoSeparator *model = SoDB::readAll(&myInput);
125 if (model == NULL)
126 exit (1);
127
128 unsigned int nChildren = model->getNumChildren();
129 std::cout << "nChildren: " << nChildren << std::endl;
130 for (unsigned int i=0; i < nChildren; ++i) {
131 const SoNode* node = model->getChild(i);
132 std::cout << "node " << i << ": " << node << std::endl;
133 if (node->getTypeId() == SoVRMLMaterial::getClassTypeId()) {
134 std::cout << "Found a SoVRMLMaterial node!\n";
135 const SoNode * matvrmlnode = static_cast<const SoVRMLMaterial *>(node); // safe downward cast, knows the type
136 std::cout << "Material node: " << matvrmlnode << std::endl;
137 }
138 }
139
140 // WIP
141 /*
142 SoSearchAction sa;
143 sa.setType(SoVRMLMaterial::getClassTypeId());
144 sa.setInterest(SoSearchAction::ALL);
145 sa.setSearchingAll(TRUE);
146 sa.apply(model);
147 SoPathList & pl = sa.getPaths();
148 SbDict namedict;
149 double plLen = pl.getLength();
150 std::cout << "plLength: " << plLen << std::endl;
151
152 for (int i = 0; i < plLen; i++) {
153
154 SoFullPath * p = (SoFullPath*) pl[i];
155
156 if (p->getTail()->isOfType(SoVRMLMaterial::getClassTypeId())) {
157
158 std::cout << "Found a SoVRMLMaterial node in Search!\n";
159 SoVRMLMaterial* vmat = (SoVRMLMaterial*) p->getTail();
160
161 if (vmat->filename.getValue().getLength()) {
162 SbName name = tex->filename.getValue().getString();
163 unsigned long key = (unsigned long) ((void*) name.getString());
164 void * tmp;
165 if (!namedict.find(key, tmp)) {
166 // new texture. just insert into list
167 (void) namedict.enter(key, tex);
168 }
169 else if (tmp != (void*) tex) { // replace with node found in dict
170 SoGroup * parent = (SoGroup*) p->getNodeFromTail(1);
171 int idx = p->getIndexFromTail(0);
172 parent->replaceChild(idx, (SoNode*) tmp);
173 }
174 }
175 }
176 }
177
178 sa.reset();
179
180 // output fixed scene to stdout
181 SoOutput out;
182 SoWriteAction wa(&out);
183 wa.apply(model);
184 */
185
186 return model;
187}
188
189
190
191
192//
193double VP1People::Imp::getScaleFactor(SoNode* node, double desiredHeight)
194{
195
196 // Get the global BoundingBox of the imported model.
197 // NOTE:
198 // SoGet-BoundingBoxAction is typically called on a path,
199 // which enables you to obtain a bounding box for a specific object in world coordinates.
200 // This action returns an SbBox3f,
201 // which specifies a 3D box aligned with the x-, y-, and z-axes in world coordinate space.
202 SbViewportRegion dummyViewport; // we need one just for creating the action
203 SoGetBoundingBoxAction bboxAction(dummyViewport);
204 bboxAction.apply(node);
205 SbXfBox3f xfbox = bboxAction.getXfBoundingBox();
206 SbBox3f box = xfbox.project();
207 float minx, miny, minz, maxx, maxy, maxz;
208 box.getBounds(minx, miny, minz, maxx, maxy, maxz);
209 float cx,cy,cz;
210 box.getCenter().getValue(cx,cy,cz);
211
212 // get the height of the model (it's along Y axis)
213 float heightModel = (maxy - miny);
214 // set the desired final height for the model
215 float heightDesired = desiredHeight;
216 // get the required scale scale factor
217 double scaleFactor = heightDesired / heightModel;
218
219 /*
220 // DEBUG MSG
221 std::cout << miny << ", " << maxy
222 << ", heightModel: " << heightModel
223 << ", heightDesired: " << heightDesired
224 << ", scaleFactor: " << scaleFactor
225 << std::endl;
226 */
227 return scaleFactor;
228}
229
230
231//____________________________________________________________________
233{
234 if (sep)
235 return;
236 theclass->messageVerbose("Building 3D objects");
237 sep = new SoSeparator; sep->ref();
238 sep->addChild(material);
239
240
241 // Create people:
242 // at first we need to copy the 3D file in the Qt resources file to the local filesystem
243 // for the SoQt load method to be able to load it
244 // Then, we load the model into the Coin geometry tree
245 QTemporaryDir tempDir;
246 QFile w1 = QFile(":/vp1/data/models/worker1.wrl");
247 QFile w2 = QFile(":/vp1/data/models/worker2.wrl");
248 SoSeparator* worker1 = nullptr;
249 SoSeparator* worker2 = nullptr;
250 if (tempDir.isValid()) {
251 const QString tempFile1 = tempDir.path() + "/worker1.wrl";
252 if ( w1.copy(tempFile1) ) {
253 worker1 = loadModel( tempFile1.toStdString() );
254 } else {
255 std::cout << "ERROR!! QFile copy of Worker1 was NOT successful!\n";
256 }
257 const QString tempFile2 = tempDir.path() + "/worker2.wrl";
258 if ( w2.copy(tempFile2) ) {
259 worker2 = loadModel( tempFile2.toStdString() );
260 } else {
261 std::cout << "ERROR!! QFile copy of Worker2 was NOT successful!\n";
262 }
263 } else {
264 std::cout << "ERROR!! TempDir is NOT valid!\n";
265 }
266 if (worker1 == nullptr) {
267 std::cout << "\n\nERROR! The 3D model Worker1 could not be loaded!\n\n";
268 exit(1);
269 }
270 if (worker2 == nullptr) {
271 std::cout << "\n\nERROR! The 3D model Worker2 could not be loaded!\n\n";
272 exit(1);
273 }
274
275 // TEST CODE with a test shape
276 //SoCube* box = new SoCube(); // test shape
277 //worker1->materialBinding=SoMaterialBinding::OVERALL;
278 //SoMaterialBinding::OVERALL;
279 //
280 // get the required scale factor for the model
281 double scaleFactor1 = getScaleFactor(worker1, 1.80*SYSTEM_OF_UNITS::m);
282 double scaleFactor2 = getScaleFactor(worker2, 1.80*SYSTEM_OF_UNITS::m);
283
284 // set a scale transformation to apply the required scale factor:
285 SoScale* myScale1 = new SoScale();
286 myScale1->scaleFactor.setValue(scaleFactor1, scaleFactor1, scaleFactor1);
287 SoScale* myScale2 = new SoScale();
288 myScale2->scaleFactor.setValue(scaleFactor2, scaleFactor2, scaleFactor2);
289
290 // Translation for people models
291 trans1 = new SoTranslation;
292 trans1->ref();
293 trans2 = new SoTranslation;
294 trans2->ref();
295 trans3 = new SoTranslation;
296 trans3->ref();
297
298 // rotate the model around the Y axis
299 SoRotationXYZ * rotY = new SoRotationXYZ();
300 rotY->axis=SoRotationXYZ::Y;
301 rotY->angle = 45*SYSTEM_OF_UNITS::deg;
302
303 SoVRMLMaterial* matVRML = new SoVRMLMaterial();
304 matVRML->diffuseColor.setValue(0., 1., 1.);
305
306 // create a separator for the scaled/rotated model,
307 // then
308 // create a separator for the translated model
309 SoSeparator* sepScaledWorker1 = new SoSeparator();
310 sepScaledWorker1->addChild(matVRML);
311 sepScaledWorker1->addChild(myScale1);
312 sepScaledWorker1->addChild(rotY);
313 sepScaledWorker1->addChild(worker1);
314 //sepScaledWorker1->addChild(box); // test shape
315 SoSeparator* sepWorker1 = new SoSeparator();
316 sepWorker1->addChild(trans1);
317 sepWorker1->addChild(sepScaledWorker1);
318
319 SoSeparator* sepScaledWorker2 = new SoSeparator();
320 sepScaledWorker2->addChild(myScale2);
321 sepScaledWorker2->addChild(rotY);
322 sepScaledWorker2->addChild(worker2);
323 SoSeparator* sepWorker2 = new SoSeparator();
324 sepWorker2->addChild(trans2);
325 sepWorker2->addChild(sepScaledWorker2);
326
327 SoTranslation* xt = new SoTranslation();
328 xt->translation.setValue(2*SYSTEM_OF_UNITS::m, 0., 1*SYSTEM_OF_UNITS::m);
329 SoSeparator* sepWorker3 = new SoSeparator();
330 sepWorker3->addChild(trans3);
331 sepWorker3->addChild(sepScaledWorker1);
332 sepWorker3->addChild(xt);
333 sepWorker3->addChild(sepScaledWorker2);
334
335 // add the scaled model to the scenegraph
336 sep->addChild(sepWorker1);
337 sep->addChild(sepWorker2);
338 sep->addChild(sepWorker3);
339}
340
341//____________________________________________________________________
343{
345 theclass->messageVerbose("Updating fields");
346 trans1->translation.setValue(0, vertpos, zpos); // x,y,z
347 trans2->translation.setValue(4*SYSTEM_OF_UNITS::m, vertpos, zpos); // x,y,z
348 trans3->translation.setValue(8*SYSTEM_OF_UNITS::m, vertpos, zpos-10*SYSTEM_OF_UNITS::m); // x,y,z
349}
350
351//____________________________________________________________________
353{
354 theclass->messageVerbose("Updating packed colour");
355 if (!sep||sep->getNumChildren()<1)
356 return;
357 SoNode * n = sep->getChild(0);
358 if (!n||n->getTypeId()!=SoVRMLMaterial::getClassTypeId())
359 return;
360
361 SoVRMLMaterial* matVRML = static_cast<SoVRMLMaterial*>(n);
362 matVRML->diffuseColor.setValue( colourAndTransp.getValue() );
363}
364
365//____________________________________________________________________
367{
368 messageVerbose("Signal received: setShown("+str(b)+")");
369 if (m_d->shown==b)
370 return;
371 m_d->shown=b;
372 if (m_d->shown) {
373 m_d->updateFields();
374 if (m_d->attachSep->findChild(m_d->sep)<0)
375 m_d->attachSep->addChild(m_d->sep);
376 } else {
377 if (m_d->sep&&m_d->attachSep->findChild(m_d->sep)>=0)
378 m_d->attachSep->removeChild(m_d->sep);
379 }
380}
381
382//____________________________________________________________________
383void VP1People::setColourAndTransp(const SbColor4f&ct)
384{
385 messageVerbose("Signal received in setColourAndTransp slot.");
386 if (m_d->colourAndTransp==ct)
387 return;
388 m_d->colourAndTransp=ct;
389 if (m_d->shown)
390 m_d->updateColour();
391}
392
393//____________________________________________________________________
394void VP1People::setZPos(const double&p)
395{
396 messageVerbose("Signal received: setZPos("+str(p)+")");
397 if (m_d->zpos==p)
398 return;
399 m_d->zpos=p;
400 if (m_d->shown)
401 m_d->updateFields();
402}
403
404//____________________________________________________________________
406{
407 messageVerbose("Signal received: setVerticalPosition("+str(p)+")");
408 if (m_d->vertpos==p)
409 return;
410 m_d->vertpos=p;
411 if (m_d->shown)
412 m_d->updateFields();
413}
static Double_t tc
#define xt
VP1HelperClassBase(IVP1System *sys=0, QString helpername="")
void messageVerbose(const QString &) const
void updateColour()
SoSeparator * loadModel(const std::string &fpath)
SoSeparator * sep
Definition VP1People.cxx:73
SoTranslation * trans2
Definition VP1People.cxx:75
SoTranslation * trans1
Definition VP1People.cxx:74
double getScaleFactor(SoNode *node, double desiredHeight)
void updateFields()
Imp(VP1People *, SoMaterial *mat, SoSeparator *attachsep)
SoTranslation * trans3
Definition VP1People.cxx:76
VP1People * theclass
Definition VP1People.cxx:61
SbColor4f colourAndTransp
Definition VP1People.cxx:69
void ensureInit3DObjects()
SoMaterial * material
Definition VP1People.cxx:62
SoSeparator * attachSep
Definition VP1People.cxx:63
void setColourAndTransp(const SbColor4f &)
void setZPos(const double &)
void setShown(bool)
VP1People(SoMaterial *mat, SoSeparator *attachsep, IVP1System *sys, QObject *parent=0)
Definition VP1People.cxx:85
Imp * m_d
Definition VP1People.h:46
void setVerticalPosition(const double &)
virtual ~VP1People()
Definition VP1People.cxx:92
Definition node.h:24