ATLAS Offline Software
VP1SoMaterialMixer.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 // Class: VP1SoMaterialMixer //
7 // First version: November 2007 //
8 // Author: Thomas.Kittelmann@cern.ch //
10 
12 #include "VP1Base/VP1Msg.h"
13 #include <Inventor/C/errors/debugerror.h>
14 #include <Inventor/nodes/SoMaterial.h>
15 #include <Inventor/sensors/SoNodeSensor.h>
16 
17 //____________________________________________________________________
19 public:
21  void setMaterialFieldsAsAverageOfMatList(SoMaterial*mat, const std::set<SoMaterial*>& matlist );
22  void setMaterialFieldsAsAverageOfMatList(SoMaterial*mat, const std::map<SoMaterial*,double>& matlist );
23  static float norm(const float& x) { return (x<0.0f?0.0f:(x>1.0f?1.0f:x));}
24 
25  //Callback used to monitor changes in materials:
26  static void materialChangedCB(void *data, SoSensor *);
27  static std::map<SoSensor*,VP1SoMaterialMixer::Imp*> sensor2matmixerimp;
28  void monitorMaterial(SoMaterial*);
29  void materialChanged(SoMaterial*);
30 
31  //For dealing with invalid input materials:
32  static bool inputMaterialValid(SoMaterial*);
33  SoMaterial *defmat;
34  SoMaterial * defaultMaterial()
35  {
36  if (!defmat) {
37  defmat = new SoMaterial;
38  defmat->ref();
39  }
40  return defmat;
41  }
42 
43  //Data members:
44  std::map<std::set<SoMaterial*>,SoMaterial*> matlists2mixedmats;
45  std::map<std::map<SoMaterial*,double>,SoMaterial*> matlists2mixedmats_weighted;
46  std::map<SoMaterial*,SoNodeSensor*> mat2sensors;
47 
48  //We could make it a bit more optimal by having different mat2sensor
49  //map + callback methods for weighted mixing. But since a given
50  //instance of the material mixer class is likely used mainly for
51  //either weighted or unweighted mixing, this is questionable how
52  //often this would actually help.
53 };
54 
55 std::map<SoSensor*,VP1SoMaterialMixer::Imp*> VP1SoMaterialMixer::Imp::sensor2matmixerimp;
56 
57 //____________________________________________________________________
59  : VP1HelperClassBase(sys,"VP1SoMaterialMixer"), m_d(new Imp)
60 {
61  m_d->theclass = this;
62  m_d->defmat = 0;
63 }
64 
65 //____________________________________________________________________
67 {
68  {
69  std::map<std::set<SoMaterial*>,SoMaterial*>::const_iterator it, itE = m_d->matlists2mixedmats.end();
71  for (it = m_d->matlists2mixedmats.begin();it!=itE;++it) {
72  for (it2=it->first.begin(), it2E=it->first.end();it2!=it2E;++it2)
73  (*it2)->unref();
74  it->second->unref();
75  }
76  }
77  {
78  std::map<std::map<SoMaterial*,double>,SoMaterial*>::iterator it, itE = m_d->matlists2mixedmats_weighted.end();
79  std::map<SoMaterial*,double>::const_iterator it2,it2E;
80  for (it = m_d->matlists2mixedmats_weighted.begin();it!=itE;++it) {
81  for (it2=it->first.begin(),it2E=it->first.end();it2!=it2E;++it2)
82  it2->first->unref();
83  it->second->unref();
84  }
85  }
86 
87  {
89  for (;it!=itE;++it) {
90  m_d->sensor2matmixerimp.erase(m_d->sensor2matmixerimp.find(it->second));
91  delete it->second;
92  it->first->unref();
93  }
94  }
95  if (m_d->defmat)
96  m_d->defmat->unref();
97 
98  //Print out warning if too many different mixed materials, to give
99  //the developers a chance to notice if they are doing something not
100  //optimal.
101 
102  if (m_d->matlists2mixedmats.size()+m_d->matlists2mixedmats_weighted.size()>100)
103  if(VP1Msg::debug()){
104  messageDebug("WARNING: Watched more than 100 ("
106  + ") different material combinations. Try to use fewer combinations for better performance!");
107  }
108  if (m_d->mat2sensors.size()>1000)
109  if(VP1Msg::debug()){
110  messageDebug("WARNING: Monitored more than 1000 (" +str(m_d->mat2sensors.size())+
111  ") different materials. Try to lower this number for better performance!");
112  }
113 
114  delete m_d;
115 }
116 
117 //____________________________________________________________________
119 {
120  return m
121  && m->ambientColor.getNum() == 1
122  && m->diffuseColor.getNum() == 1
123  && m->specularColor.getNum() == 1
124  && m->emissiveColor.getNum() == 1
125  && m->transparency.getNum() == 1
126  && m->shininess.getNum() == 1;
127 
128 }
129 
130 //____________________________________________________________________
131 void VP1SoMaterialMixer::Imp::materialChangedCB(void *data, SoSensor * sensor)
132 {
133  SoMaterial *material = (SoMaterial *)data;
134  if (!inputMaterialValid(material)) {
135  VP1Msg::message("ERROR: Monitored material changed to invalid state"
136  " (multiple values in a field). Ignore changes.");
137  return;
138  }
139 
140  std::map<SoSensor*,VP1SoMaterialMixer::Imp*>::iterator it = sensor2matmixerimp.find(sensor);
141  if (it!=sensor2matmixerimp.end())
142  it->second->materialChanged(material);
143 }
144 
145 //____________________________________________________________________
147 {
148  if (mat2sensors.find(mat)!=mat2sensors.end())
149  return;//We already monitor this material.
150 
151  SoNodeSensor * sensor = new SoNodeSensor(Imp::materialChangedCB, mat);
152  sensor->attach(mat);
153  sensor2matmixerimp[sensor] = this;
154  mat2sensors[mat]=sensor;
155  mat->ref();
156 
157 }
158 
159 //____________________________________________________________________
161 {
162  //First look in lists for un-weighted mixtures:
163  std::map<std::set<SoMaterial*>,SoMaterial*>::const_iterator it, itE = matlists2mixedmats.end();
164  for (it = matlists2mixedmats.begin();it!=itE;++it) {
165  std::set<SoMaterial*>::iterator it2(it->first.begin()),it2E(it->first.end());
166  for (;it2!=it2E;++it2) {
167  if (mat==*it2) {
168  setMaterialFieldsAsAverageOfMatList(it->second,it->first);
169  break;
170  }
171  }
172  }
173  //Then look in lists for weighted mixtures:
174  std::map<std::map<SoMaterial*,double>,SoMaterial*>::const_iterator it3, it3E = matlists2mixedmats_weighted.end();
175  for (it3 = matlists2mixedmats_weighted.begin();it3!=it3E;++it3) {
176  std::map<SoMaterial*,double>::const_iterator it4(it3->first.begin()),it4E(it3->first.end());
177  for (;it4!=it4E;++it4) {
178  if (mat==it4->first) {
179  setMaterialFieldsAsAverageOfMatList(it3->second,it3->first);
180  break;
181  }
182  }
183  }
184 
185 }
186 
187 //____________________________________________________________________
188 void VP1SoMaterialMixer::Imp::setMaterialFieldsAsAverageOfMatList(SoMaterial*mat, const std::set<SoMaterial*>& matlist )
189 {
190  float ambient_r(0.0f), ambient_g(0.0f), ambient_b(0.0f);
191  float diffuse_r(0.0f), diffuse_g(0.0f), diffuse_b(0.0f);
192  float specular_r(0.0f), specular_g(0.0f), specular_b(0.0f);
193  float emissive_r(0.0f), emissive_g(0.0f), emissive_b(0.0f);
194  float shininess(0.0f), transparency(0.0f);
195  float r,g,b;
196  std::set<SoMaterial*>::const_iterator it(matlist.begin()), itE(matlist.end());
197  for (;it!=itE;++it) {
198  (*it)->ambientColor[0].getValue(r,g,b); ambient_r += r; ambient_g += g; ambient_b += b;
199  (*it)->diffuseColor[0].getValue(r,g,b); diffuse_r += r; diffuse_g += g; diffuse_b += b;
200  (*it)->specularColor[0].getValue(r,g,b); specular_r += r; specular_g += g; specular_b += b;
201  (*it)->emissiveColor[0].getValue(r,g,b); emissive_r += r; emissive_g += g; emissive_b += b;
202  shininess += (*it)->shininess[0];
203  transparency += (*it)->transparency[0];
204  }
205 
206  float n = 1.0f/matlist.size();
207  bool save = mat->enableNotify(false);
208  mat->ambientColor.setValue(norm(n*ambient_r),norm(n*ambient_g),norm(n*ambient_b));
209  mat->diffuseColor.setValue(norm(n*diffuse_r),norm(n*diffuse_g),norm(n*diffuse_b));
210  mat->specularColor.setValue(norm(n*specular_r),norm(n*specular_g),norm(n*specular_b));
211  mat->emissiveColor.setValue(norm(n*emissive_r),norm(n*emissive_g),norm(n*emissive_b));
212  mat->shininess.setValue(norm(n*shininess));
213  mat->transparency.setValue(norm(n*transparency));
214  if (save) {
215  mat->enableNotify(true);
216  mat->touch();
217  if (VP1Msg::verbose()){
218  theclass->messageVerbose("Material ("+str(mat)+") updated and touched");
219  }
220  } else {
221  if (VP1Msg::verbose()){
222  theclass->messageVerbose("Material ("+str(mat)+") updated but notifications were off");
223  }
224  }
225 }
226 
227 //____________________________________________________________________
228 void VP1SoMaterialMixer::Imp::setMaterialFieldsAsAverageOfMatList(SoMaterial*mat, const std::map<SoMaterial*,double>& matlist )
229 {
230  float w, totweight(0.0f);
231  float ambient_r(0.0f), ambient_g(0.0f), ambient_b(0.0f);
232  float diffuse_r(0.0f), diffuse_g(0.0f), diffuse_b(0.0f);
233  float specular_r(0.0f), specular_g(0.0f), specular_b(0.0f);
234  float emissive_r(0.0f), emissive_g(0.0f), emissive_b(0.0f);
235  float shininess(0.0f), transparency(0.0f);
236  float r,g,b;
237  std::map<SoMaterial*,double>::const_iterator it(matlist.begin()), itE(matlist.end());
238  SoMaterial * m;
239  for (;it!=itE;++it) {
240  m = it->first;
241  w = it->second;
242  totweight += w;
243  m->ambientColor[0].getValue(r,g,b); ambient_r += w*r; ambient_g += w*g; ambient_b += w*b;
244  m->diffuseColor[0].getValue(r,g,b); diffuse_r += w*r; diffuse_g += w*g; diffuse_b += w*b;
245  m->specularColor[0].getValue(r,g,b); specular_r += w*r; specular_g += w*g; specular_b += w*b;
246  m->emissiveColor[0].getValue(r,g,b); emissive_r += w*r; emissive_g += w*g; emissive_b += w*b;
247  shininess += m->shininess[0]*w;
248  transparency += m->transparency[0]*w;
249  }
250 
251  float n = 1.0f/totweight;
252  bool save = mat->enableNotify(false);
253  mat->ambientColor.setValue(norm(n*ambient_r),norm(n*ambient_g),norm(n*ambient_b));
254  mat->diffuseColor.setValue(norm(n*diffuse_r),norm(n*diffuse_g),norm(n*diffuse_b));
255  mat->specularColor.setValue(norm(n*specular_r),norm(n*specular_g),norm(n*specular_b));
256  mat->emissiveColor.setValue(norm(n*emissive_r),norm(n*emissive_g),norm(n*emissive_b));
257  mat->shininess.setValue(norm(n*shininess));
258  mat->transparency.setValue(norm(n*transparency));
259  if (save) {
260  mat->enableNotify(true);
261  mat->touch();
262  if (VP1Msg::verbose()){
263  theclass->messageVerbose("Material ("+str(mat)+") updated and touched");
264  }
265  } else {
266  if (VP1Msg::verbose()){
267  theclass->messageVerbose("Material ("+str(mat)+") updated but notifications were off");
268  }
269  }
270 }
271 
272 //____________________________________________________________________
273 SoMaterial * VP1SoMaterialMixer::getMixedMaterial(const std::set<SoMaterial*>& matlist) {
274  //Check incoming materials!
275  bool error(false);
276  std::set<SoMaterial*>::const_iterator it(matlist.begin()), itE(matlist.end());
277  for (;it!=itE;++it) {
278  if (!m_d->inputMaterialValid(*it)) {
279  error=true;
280  break;
281  }
282  }
283  if (matlist.empty()) {
284  VP1Msg::message("ERROR: asked to handle empty material list.");
285  return m_d->defaultMaterial();
286  }
287  if (error) {
288  VP1Msg::message("ERROR: asked to handle invalid material list.");
289  return m_d->defaultMaterial();
290  }
291 
292  //Someone might be silly enough to call with just one material:
293  if (matlist.size()==1)
294  return *(matlist.begin());
295 
296  //Do we already have a mixed material for this list:
297  std::map<std::set<SoMaterial*>,SoMaterial*>::const_iterator it2 = m_d->matlists2mixedmats.find(matlist);
298  if (it2!=m_d->matlists2mixedmats.end())
299  return it2->second;
300 
301  //Create new mixed material:
302  SoMaterial * mixmat = new SoMaterial;
303  m_d->setMaterialFieldsAsAverageOfMatList(mixmat,matlist);
304 
305  //Set up monitoring, add to maps and refcount materials:
306  std::set<SoMaterial*>::const_iterator it3(matlist.begin()), it3E(matlist.end());
307  for (;it3!=it3E;++it3) {
308  m_d->monitorMaterial(*it3);
309  (*it3)->ref();//since we keep the pointer.
310  }
311  mixmat->ref();
312  m_d->matlists2mixedmats[matlist] = mixmat;
313 
314  return mixmat;
315 }
316 
317 //____________________________________________________________________
318 SoMaterial * VP1SoMaterialMixer::getMixedMaterial(const std::map<SoMaterial*,double>& matlist)
319 {
320  //Check incoming materials!
321  bool error(false);
322  std::map<SoMaterial*,double>::const_iterator it(matlist.begin()), itE(matlist.end());
323  for (;it!=itE;++it) {
324  if (!m_d->inputMaterialValid(it->first)||it->second<=0.0) {
325  error=true;
326  break;
327  }
328  }
329  if (matlist.empty()) {
330  VP1Msg::message("ERROR: asked to handle empty material list.");
331  return m_d->defaultMaterial();
332  }
333  if (error) {
334  VP1Msg::message("ERROR: asked to handle invalid material list.");
335  return m_d->defaultMaterial();
336  }
337 
338  //Someone might be silly enough to call with just one material:
339  if (matlist.size()==1)
340  return matlist.begin()->first;
341 
342  //Do we already have a mixed material for this list:
343  std::map<std::map<SoMaterial*,double>,SoMaterial*>::const_iterator it2 = m_d->matlists2mixedmats_weighted.find(matlist);
344  if (it2!=m_d->matlists2mixedmats_weighted.end())
345  return it2->second;
346 
347  //Create new mixed material:
348  SoMaterial * mixmat = new SoMaterial;
349  m_d->setMaterialFieldsAsAverageOfMatList(mixmat,matlist);
350 
351  //Set up monitoring, add to maps and refcount materials:
352  std::map<SoMaterial*,double>::const_iterator it3(matlist.begin()), it3E(matlist.end());
353  for (;it3!=it3E;++it3) {
354  m_d->monitorMaterial(it3->first);
355  it3->first->ref();//since we keep the pointer.
356  }
357  mixmat->ref();
358  m_d->matlists2mixedmats_weighted[matlist] = mixmat;
359 
360  return mixmat;
361 }
362 
363 //____________________________________________________________________
364 SoMaterial * VP1SoMaterialMixer::getMixedMaterial(SoMaterial*m1,SoMaterial*m2)
365 {
366  std::set<SoMaterial*> matlist;
367  matlist.insert(m1);
368  matlist.insert(m2);
369  return getMixedMaterial(matlist);
370 }
371 
372 //____________________________________________________________________
373 SoMaterial * VP1SoMaterialMixer::getMixedMaterial( SoMaterial* mat1, const double& weight1,
374  SoMaterial* mat2, const double& weight2 )
375 {
376  std::map<SoMaterial*,double> matlist;
377  matlist[mat1] = weight1;
378  matlist[mat2] = weight2;
379  return getMixedMaterial(matlist);
380 }
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
beamspotman.r
def r
Definition: beamspotman.py:676
data
char data[hepevt_bytes_allocation_ATLAS]
Definition: HepEvt.cxx:11
python.CaloRecoConfig.f
f
Definition: CaloRecoConfig.py:127
PlotCalibFromCool.norm
norm
Definition: PlotCalibFromCool.py:100
VP1SoMaterialMixer::VP1SoMaterialMixer
VP1SoMaterialMixer(IVP1System *sys=0)
Definition: VP1SoMaterialMixer.cxx:58
python.SystemOfUnits.m2
int m2
Definition: SystemOfUnits.py:92
VP1SoMaterialMixer::~VP1SoMaterialMixer
virtual ~VP1SoMaterialMixer()
Definition: VP1SoMaterialMixer.cxx:66
python.SystemOfUnits.m
int m
Definition: SystemOfUnits.py:91
VP1Msg.h
mat
GeoMaterial * mat
Definition: LArDetectorConstructionTBEC.cxx:53
CSV_InDetExporter.new
new
Definition: CSV_InDetExporter.py:145
skel.it
it
Definition: skel.GENtoEVGEN.py:423
VP1SoMaterialMixer::getMixedMaterial
SoMaterial * getMixedMaterial(const std::set< SoMaterial * > &)
Definition: VP1SoMaterialMixer.cxx:273
VP1Msg::debug
static bool debug()
Definition: VP1Msg.h:32
VP1SoMaterialMixer::Imp::materialChangedCB
static void materialChangedCB(void *data, SoSensor *)
Definition: VP1SoMaterialMixer.cxx:131
VP1SoMaterialMixer::Imp::setMaterialFieldsAsAverageOfMatList
void setMaterialFieldsAsAverageOfMatList(SoMaterial *mat, const std::set< SoMaterial * > &matlist)
Definition: VP1SoMaterialMixer.cxx:188
x
#define x
VP1String::str
static QString str(const QString &s)
Definition: VP1String.h:49
VP1HelperClassBase::messageDebug
void messageDebug(const QString &) const
Definition: VP1HelperClassBase.cxx:65
mapkey::sys
@ sys
Definition: TElectronEfficiencyCorrectionTool.cxx:42
TruthTest.itE
itE
Definition: TruthTest.py:25
VP1SoMaterialMixer::Imp::defaultMaterial
SoMaterial * defaultMaterial()
Definition: VP1SoMaterialMixer.cxx:34
checkTP.save
def save(self, fileName="./columbo.out")
Definition: checkTP.py:178
IVP1System
Definition: IVP1System.h:36
python.changerun.m1
m1
Definition: changerun.py:32
VP1SoMaterialMixer::Imp::matlists2mixedmats_weighted
std::map< std::map< SoMaterial *, double >, SoMaterial * > matlists2mixedmats_weighted
Definition: VP1SoMaterialMixer.cxx:45
VP1SoMaterialMixer.h
beamspotman.n
n
Definition: beamspotman.py:731
python.CaloCondTools.g
g
Definition: CaloCondTools.py:15
VP1SoMaterialMixer::Imp::matlists2mixedmats
std::map< std::set< SoMaterial * >, SoMaterial * > matlists2mixedmats
Definition: VP1SoMaterialMixer.cxx:44
VP1SoMaterialMixer::Imp::materialChanged
void materialChanged(SoMaterial *)
Definition: VP1SoMaterialMixer.cxx:160
VP1SoMaterialMixer::Imp::mat2sensors
std::map< SoMaterial *, SoNodeSensor * > mat2sensors
Definition: VP1SoMaterialMixer.cxx:46
VP1HelperClassBase
Definition: VP1HelperClassBase.h:28
VP1SoMaterialMixer::m_d
Imp * m_d
Definition: VP1SoMaterialMixer.h:48
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
VP1SoMaterialMixer::Imp::norm
static float norm(const float &x)
Definition: VP1SoMaterialMixer.cxx:23
VP1SoMaterialMixer::Imp::defmat
SoMaterial * defmat
Definition: VP1SoMaterialMixer.cxx:33
VP1SoMaterialMixer::Imp
Definition: VP1SoMaterialMixer.cxx:18
VP1SoMaterialMixer::Imp::monitorMaterial
void monitorMaterial(SoMaterial *)
Definition: VP1SoMaterialMixer.cxx:146
VP1Msg::message
static void message(const QString &, IVP1System *sys=0)
Definition: VP1Msg.cxx:30
VP1SoMaterialMixer::Imp::inputMaterialValid
static bool inputMaterialValid(SoMaterial *)
Definition: VP1SoMaterialMixer.cxx:118
VP1SoMaterialMixer::Imp::sensor2matmixerimp
static std::map< SoSensor *, VP1SoMaterialMixer::Imp * > sensor2matmixerimp
Definition: VP1SoMaterialMixer.cxx:27
VP1SoMaterialMixer::Imp::theclass
VP1SoMaterialMixer * theclass
Definition: VP1SoMaterialMixer.cxx:20
VP1Msg::verbose
static bool verbose()
Definition: VP1Msg.h:31
python.IoTestsLib.w
def w
Definition: IoTestsLib.py:200
get_generator_info.error
error
Definition: get_generator_info.py:40
error
Definition: IImpactPoint3dEstimator.h:70
VP1SoMaterialMixer
Definition: VP1SoMaterialMixer.h:19