• 13.46% Rate
  • 21 Hits
  • 135 Missed
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 1x
  • 1x
  • 1x
  • 1x
  • 1x
  • 1x
  • 1x
  • 1x
  • 1x
  • 1x
  • 1x
  • 1x
  • 1x
  • 1x
  • 1x
  • 1x
  • 1x
  • 1x
  • 1x
  • 1x
  • 1x
  • -------------------------------------------------------------------------------
  • -- Earth geometry for PUMAS
  • -- Author: Valentin Niess
  • -- License: GNU LGPL-3.0
  • -------------------------------------------------------------------------------
  • local ffi = require('ffi')
  • local call = require('pumas.call')
  • local clib = require('pumas.clib')
  • local compat = require('pumas.compat')
  • local error = require('pumas.error')
  • local base = require('pumas.geometry.base')
  • local readonly = require('pumas.readonly')
  • local layer_ = require('pumas.geometry.layer')
  • local topography = require('pumas.geometry.topography')
  • local uniform = require('pumas.medium.uniform')
  • local metatype = require('pumas.metatype')
  • local earth = {}
  • -- XXX Add a geoid metatype / interface ?
  • -------------------------------------------------------------------------------
  • -- The Earth geometry metatype
  • -------------------------------------------------------------------------------
  • local EarthGeometry = {}
  • local ctype = ffi.typeof('struct pumas_geometry_earth')
  • local ctype_ptr = ffi.typeof('struct pumas_geometry_earth *')
  • local pumas_geometry_ptr = ffi.typeof('struct pumas_geometry *')
  • local function new (self)
  • local c = ffi.cast(ctype_ptr, ffi.C.calloc(1, ffi.sizeof(ctype)))
  • c.base.get = clib.pumas_geometry_earth_get
  • c.base.reset = clib.pumas_geometry_earth_reset
  • c.base.destroy = clib.pumas_geometry_earth_destroy
  • c.media = self._media
  • local layers = readonly.rawget(self.layers)
  • c.n_layers = #layers
  • call(clib.turtle_stepper_create, c.stepper)
  • if self._geoid_undulations then
  • clib.turtle_stepper_geoid_set(c.stepper[0], self._geoid_undulations._c)
  • end
  • for i = #layers, 1, -1 do
  • local data = layers[i].data
  • if i < #layers then
  • call(clib.turtle_stepper_add_layer, c.stepper[0])
  • end
  • for j = #data, 1, -1 do
  • local datum = data[j]
  • if datum._elevation then
  • call(datum._stepper_add, c.stepper[0], datum._c, datum.offset)
  • else
  • call(datum._stepper_add, c.stepper[0], datum.offset)
  • end
  • end
  • end
  • c.magnet.workspace[0] = nil
  • if self._magnet then
  • local date = self._date or '01/01/2021'
  • local matches = {}
  • for match in date:gmatch('(%d+)/*') do
  • table.insert(matches, tonumber(match))
  • end
  • local magnet
  • if self._magnet == true then
  • magnet = os.tmpname()
  • local f = io.open(magnet, 'a+')
  • f:write(require('pumas.data.igrf13'))
  • f:close()
  • else
  • magnet = self._magnet
  • end
  • local errmsg = call.protected(
  • ffi.C.gull_snapshot_create, c.magnet.snapshot, magnet,
  • matches[1], matches[2], matches[3])
  • if self._magnet == true then os.remove(magnet) end
  • if errmsg then
  • error.raise{
  • fname = 'EarthGeometry.new',
  • description = errmsg
  • }
  • end
  • c.base.magnet = clib.pumas_geometry_earth_magnet
  • else
  • c.magnet.snapshot[0] = nil
  • end
  • return ffi.cast(pumas_geometry_ptr, c)
  • end
  • function EarthGeometry:__index (k)
  • if k == 'date' then
  • return self._date
  • elseif k == 'geoid_undulations' then
  • return self._geoid_undulations
  • elseif k == 'magnet' then
  • return self._magnet
  • elseif k == '_new' then
  • return new
  • else
  • return base.BaseGeometry.__index[k]
  • end
  • end
  • function EarthGeometry:__newindex (k, v)
  • if (k == 'magnet') or (k == 'date') or (k == 'geoid_undulations') then
  • local key = '_'..k
  • if v == rawget(self, key) then return end
  • local mt, expected = metatype(v)
  • if k == 'date' then
  • if (mt ~= 'string') and (mt ~= 'nil') then
  • expected = 'a string or nil'
  • end
  • elseif k == 'magnet' then
  • if (mt ~= 'string') and (mt ~= 'nil') and (mt ~= 'boolean') then
  • expected = 'a boolean, a string or nil'
  • end
  • else
  • if (mt ~= 'string') and (mt ~= 'nil') and
  • (mt ~= 'TopographyData') then
  • expected = 'a TopographyData table, a string or nil'
  • end
  • end
  • if expected then
  • error.raise{
  • fname = k,
  • expected = expected,
  • got = metatype.a(v)
  • }
  • end
  • if k == 'geoid_undulations' then
  • local undulations
  • if metatype(v) == 'TopographyData' then
  • undulations = v
  • else
  • undulations = topography.TopographyData(v)
  • end
  • if not ffi.istype('struct turtle_map *', undulations._c) then
  • error.raise{
  • fname = k,
  • description = 'invalid TopographyData format'
  • }
  • end
  • v = undulations
  • end
  • rawset(self, key, v)
  • self:_invalidate()
  • else
  • error.raise{
  • ['type'] = 'EarthGeometry',
  • bad_member = k
  • }
  • end
  • end
  • -------------------------------------------------------------------------------
  • -- The Earth geometry constructor
  • -------------------------------------------------------------------------------
  • do
  • local raise_error = error.ErrorFunction{fname = 'EarthGeometry'}
  • local function new_ (cls, ...)
  • local nargs = select('#', ...)
  • if nargs == 0 then
  • raise_error{argnum = 'bad', expected = '1 or more', got = 0}
  • end
  • local self = base.BaseGeometry:new()
  • local layers = compat.table_new(nargs, 0)
  • local ilayer = 0
  • local magnet, date, geoid_undulations
  • local function add(args, index)
  • for i, arg in ipairs(args) do
  • if metatype(arg) == 'table' then
  • if arg.magnet then magnet = arg.magnet end
  • if arg.date then date = arg.date end
  • if arg.geoid_undulations then
  • geoid_undulations = arg.geoid_undulations
  • end
  • end
  • local medium, data = arg.medium, arg.data
  • if (not medium) and (not data) and type(arg) == 'table' then
  • add(arg, index or i)
  • else
  • do
  • local mt = metatype(medium)
  • if mt == 'string' then
  • medium = uniform.UniformMedium(medium)
  • elseif (mt ~= 'Medium') and (mt ~= 'nil') then
  • raise_error{argnum = (index or i)..' (medium)',
  • expected = 'a Medium table or nil',
  • got = metatype.a(medium)}
  • end
  • end
  • if not data then
  • raise_error{argnum = (index or i)..' (data)',
  • expected = 'a TopographyData(set) table',
  • got = metatype.a(data)}
  • end
  • local mt = metatype(data)
  • if (mt ~= 'table') and (mt ~= 'TopographyDataset') then
  • data = {data}
  • end
  • if mt == 'TopographyDataset' then
  • data = data:clone()
  • else
  • for j, datum in ipairs(data) do
  • local mt_ = metatype(datum)
  • if (mt_ == 'string') or (mt_ == 'number') then
  • data[j] = topography.TopographyData(datum)
  • elseif mt_ ~= 'TopographyData' then
  • raise_error{argnum = (index or i)..' (data)',
  • expected = 'a TopographyData table, \z
  • a number or a string',
  • got = metatype.a(data)}
  • end
  • end
  • data = topography.TopographyDataset(data)
  • end
  • for _, datum in data:ipairs() do
  • rawset(datum, '_geometry', self)
  • end
  • ilayer = ilayer + 1
  • layers[ilayer] = layer_.TopographyLayer(medium, data)
  • end
  • end
  • end
  • add{...}
  • -- XXX Provide elevation and frame methods?
  • local pumas_medium_ptr = ffi.typeof('struct pumas_medium *')
  • local pumas_medium_ptrarr = ffi.typeof('struct pumas_medium **')
  • local size = ffi.sizeof(pumas_medium_ptr)
  • local media = ffi.cast(pumas_medium_ptrarr, ffi.C.calloc(#layers, size))
  • ffi.gc(media, ffi.C.free)
  • for i, layer in ipairs(layers) do
  • if layer.medium ~= nil then
  • media[#layers - i] = ffi.cast(pumas_medium_ptr, layer.medium._c)
  • end
  • end
  • self._media = media
  • self.layers = readonly.Readonly(layers)
  • self = setmetatable(self, cls)
  • self.magnet = magnet
  • self.date = date
  • self.geoid_undulations = geoid_undulations
  • return self
  • end
  • earth.EarthGeometry = setmetatable(EarthGeometry, {__call = new_})
  • end
  • -------------------------------------------------------------------------------
  • -- Return the package
  • -------------------------------------------------------------------------------
  • return earth