File indexing completed on 2026-04-09 07:48:48
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 """
0022
0023 Maximum global transform deviation just less than 0.1 mm when using float64 (jumping around up to 0.2mm when using float32)
0024 when comparing global transforms from the G4DAE/GMergedMesh
0025 cache and the products of the glTF json parsed matrices.
0026
0027 TODO: perhaps more precision loss later... compare transforms at point of use inside C++
0028
0029 ::
0030
0031 In [190]: run gltf.py
0032 [2017-07-01 11:35:10,972] p18709 {/Users/blyth/opticks/ana/base.py:266} INFO - envvar OPTICKS_ANA_DEFAULTS -> defaults {'src': 'torch', 'tag': '1', 'det': 'concentric'}
0033 args: gltf.py
0034 scenes : 1
0035 nodes : 12230
0036 meshes : 249
0037 lpo [0, 0, 0, 1] : gd32( 0.00000 0.06326 ) gd64( 0.00000 0.09817 )
0038 lpo [0.001, 0.001, 0.001, 1] : gd32( 0.00000 0.06326 ) gd64( 0.00000 0.09817 )
0039 lpo [1000, 1000, 1000, 1] : gd32( 0.00000 0.06326 ) gd64( 0.00000 0.09783 )
0040 lpo [10000, 10000, 10000, 1] : gd32( 0.00000 0.18775 ) gd64( 0.00000 0.09497 )
0041 lpo [10000.0001, 10000.0001, 10000.0001, 1] : gd32( 0.00000 0.18775 ) gd64( 0.00000 0.09497 )
0042 lpo [20000, 20000, 20000, 1] : gd32( 0.00000 0.12727 ) gd64( 0.00000 0.09218 )
0043 lpo [1000, 0, 0, 1] : gd32( 0.00000 0.06326 ) gd64( 0.00000 0.09833 )
0044 lpo [0, 1000, 0, 1] : gd32( 0.00000 0.06326 ) gd64( 0.00000 0.09771 )
0045 lpo [0, 0, 1000, 1] : gd32( 0.00000 0.06326 ) gd64( 0.00000 0.09813 )
0046 lpo [-1000, -1000, -1000, 1] : gd32( 0.00000 0.12502 ) gd64( 0.00000 0.09851 )
0047 lpo [-5000, -5000, -5000, 1] : gd32( 0.00000 0.12514 ) gd64( 0.00000 0.09992 )
0048 lpo [5000, 5000, 5000, 1] : gd32( 0.00000 0.06443 ) gd64( 0.00000 0.09652 )
0049 lpo [10000, 0, 0, 1] : gd32( 0.00000 0.06398 ) gd64( 0.00000 0.09997 )
0050
0051
0052 """
0053
0054 import os, logging, numpy as np
0055 log = logging.getLogger(__name__)
0056
0057 from opticks.ana.base import opticks_main, json_load_ , idp_
0058 from opticks.analytic.glm import mdotr_
0059
0060
0061 class NN(list):
0062 def __init__(self, volpath):
0063 list.__init__(self,volpath)
0064 def __repr__(self):
0065 return "\n".join(map(repr, self))
0066
0067 def _get_transforms32(self):
0068 return map(lambda n:n.transform32, self)
0069 transforms32 = property(_get_transforms32)
0070
0071 def _get_transforms64(self):
0072 return map(lambda n:n.transform64, self)
0073 transforms64 = property(_get_transforms64)
0074
0075 gtr32 = property(lambda self:mdotr_(self.transforms32))
0076 gtr64 = property(lambda self:mdotr_(self.transforms64))
0077 gtr32r = property(lambda self:mdotr_(self.transforms32[::-1]))
0078 gtr64r = property(lambda self:mdotr_(self.transforms64[::-1]))
0079
0080
0081 class N(object):
0082 def __init__(self, gltfnode):
0083 self.gn = gltfnode
0084 self.children = gltfnode.get('children', [])
0085 self.transform32 = np.asarray( gltfnode.get('matrix'), dtype=np.float32 ).reshape(4,4)
0086 self.transform64 = np.asarray( gltfnode.get('matrix'), dtype=np.float64 ).reshape(4,4)
0087
0088 def __repr__(self):
0089 return " mesh: %d matrix:%s pvn:%s " % (self.gn['mesh'], repr(self.gn['matrix']), self.gn['extras']['pvname'])
0090
0091
0092 class GLTF(object):
0093 def __init__(self, path="$TMP/tgltf/tgltf-gdml--.gltf", t0=None):
0094 self.path = path
0095 self.gltf = json_load_(path)
0096 self.t0 = t0
0097 self.nn = {}
0098
0099 def get_node(self, idx):
0100 return self.gltf['nodes'][idx]
0101
0102 def get_n(self, idx):
0103 return self.nn[idx]
0104
0105 def traverse(self):
0106 def traverse_r(idx,ancestors):
0107
0108 volpath = ancestors[:]
0109
0110 gn = self.get_node(idx)
0111 n = N(gn)
0112 volpath.append(n)
0113
0114 self.nn[idx] = NN(volpath)
0115
0116 cc = n.children
0117
0118
0119
0120 for c in cc:
0121 traverse_r(c, volpath)
0122 pass
0123 pass
0124 traverse_r(0, [])
0125
0126
0127 def __str__(self):
0128 lkeys = filter(lambda k:type(self.gltf[k]) is list, self.gltf.keys() )
0129 return "\n".join([" %20s : %d " % (k, len(self.gltf[k])) for k in lkeys])
0130
0131
0132
0133 def gtransform_delta(self, lpos=[0,0,0,1]):
0134 return self.gtransform_delta_(lpos, np.float32), self.gtransform_delta_(lpos, np.float64)
0135
0136 def gtransform_delta_(self, lpos_, dtype=np.float64):
0137 """
0138 Check distance between a local frame position transformed with the two
0139 transforms
0140 """
0141 lpos = np.asarray(lpos_, dtype=dtype)
0142
0143 num = len(self.nn)
0144 gdelta = np.zeros(num, dtype=dtype)
0145
0146 for idx in range(num):
0147 t0 = self.t0[idx].reshape(4,4)
0148 nn = self.nn[idx]
0149
0150 t1 = nn.gtr32r if dtype is np.float32 else nn.gtr64r
0151
0152 gpos0 = np.dot( lpos, t0 )[:3]
0153 gpos1 = np.dot( lpos, t1 )[:3]
0154 d = gpos0 - gpos1
0155 gdelta[idx] = np.sqrt(np.dot(d,d))
0156 pass
0157 return gdelta
0158
0159
0160
0161
0162
0163
0164
0165 if __name__ == '__main__':
0166 args = opticks_main()
0167
0168 t0 = np.load(idp_("GMergedMesh/0/transforms.npy"))
0169
0170 g = GLTF(t0=t0)
0171 print g
0172
0173 g.traverse()
0174
0175 lpos = [
0176 [0,0,0,1],
0177 [1e-3,1e-3,1e-3,1],
0178 [1000,1000,1000,1],
0179 [10000,10000,10000,1],
0180 [10000.0001,10000.0001,10000.0001,1],
0181 [20000,20000,20000,1],
0182 [1000,0,0,1],
0183 [0,1000,0,1],
0184 [0,0,1000,1],
0185 [-1000,-1000,-1000,1],
0186 [-5000,-5000,-5000,1],
0187 [5000,5000,5000,1],
0188 [10000,0,0,1]
0189 ]
0190
0191
0192 for lpo in lpos:
0193 gd32,gd64 = g.gtransform_delta(lpo)
0194 print " lpo %40s : gd32( %10.5f %10.5f ) gd64( %10.5f %10.5f ) " % ( repr(lpo),gd32.min(),gd32.max(), gd64.min(),gd64.max() )
0195 pass
0196
0197
0198 nn = g.nn[3159]
0199
0200