1 | #include "oregen.h"
|
---|
2 |
|
---|
3 | #include <iterator>
|
---|
4 | #include <mars_log.h>
|
---|
5 |
|
---|
6 | namespace geoworld
|
---|
7 | {
|
---|
8 | const float DepositSynthesizer::FREQUENCY_MULTIPLIER = 1000;
|
---|
9 |
|
---|
10 | DepositSynthesizer::DepositSynthesizer(const MineralsDB * pMinDB, const DepositSynthesizerSettings & settings, const WorldUnit nWidth, const WorldUnit nHeight, const WorldUnit nDepth, const unsigned short nDEMLOD)
|
---|
11 | : _pMinDB(pMinDB), _nAbsWidth(nWidth), _nAbsHeight(nHeight), _stratum(settings.layers.count, nWidth, nHeight, nDepth, nDEMLOD, mars::Wrap), _settings(settings),
|
---|
12 | _otOre(std::max(nWidth, nHeight), 4),
|
---|
13 | _factBubbleGum(
|
---|
14 | settings.minerals.spherepack.limit,
|
---|
15 | settings.minerals.spherepack.minimum,
|
---|
16 | settings.minerals.spherepack.maxtier,
|
---|
17 | settings.minerals.spherepack.sizeflux,
|
---|
18 | settings.minerals.spherepack.kidflux,
|
---|
19 | settings.minerals.deposit.vein.detail,
|
---|
20 | settings.minerals.deposit.vein.erratic
|
---|
21 | ),
|
---|
22 | _pbsAbundance(settings.minerals.abundance.curve),
|
---|
23 | _pbsDepositSize(settings.minerals.deposit.curve),
|
---|
24 | _pbsThickness(settings.layers.count, settings.layers.thickness.curve, settings.layers.thickness.scale)
|
---|
25 | {
|
---|
26 | assert(((_nAbsWidth - 1) & _nAbsWidth) == 0 && ((_nAbsHeight - 1) & _nAbsHeight) == 0); // Must be a power of 2
|
---|
27 | }
|
---|
28 |
|
---|
29 | DepositSynthesizer::~DepositSynthesizer()
|
---|
30 | {
|
---|
31 | }
|
---|
32 |
|
---|
33 | DepositSynthesizerSettings DepositSynthesizer::loadSettings( IDepositSynthConfigReader & cfgreader )
|
---|
34 | {
|
---|
35 | DepositSynthesizerSettings settings;
|
---|
36 | cfgreader.load(settings);
|
---|
37 | return settings;
|
---|
38 | }
|
---|
39 |
|
---|
40 | Silica DepositSynthesizer::selectSilica( const float fRatio )
|
---|
41 | {
|
---|
42 | if (fRatio < 0.16f)
|
---|
43 | return Silica_NA;
|
---|
44 | else if (fRatio < 0.17f * 2.0f)
|
---|
45 | return Silica_UltraMafic;
|
---|
46 | else if (fRatio < 0.17f * 3.0f)
|
---|
47 | return Silica_Mafic;
|
---|
48 | else if (fRatio < 0.17f * 4.0f)
|
---|
49 | return Silica_Intermediate;
|
---|
50 | else if (fRatio < 0.17f * 5.0f)
|
---|
51 | return Silica_InterFelsic;
|
---|
52 | else
|
---|
53 | return Silica_Felsic;
|
---|
54 | }
|
---|
55 |
|
---|
56 | Origin DepositSynthesizer::selectOrigin( const float fRatio )
|
---|
57 | {
|
---|
58 | if (fRatio < 0.2f)
|
---|
59 | return Origin_NA;
|
---|
60 | else if (fRatio < 0.2f * 2.0f)
|
---|
61 | return Origin_Plutonic;
|
---|
62 | else if (fRatio < 0.2f * 3.0f)
|
---|
63 | return Origin_Subvolcanic;
|
---|
64 | else if (fRatio < 0.2f * 4.0f)
|
---|
65 | return Origin_Volcanic;
|
---|
66 | else
|
---|
67 | return Origin_Meteoritic;
|
---|
68 | }
|
---|
69 |
|
---|
70 | void DepositSynthesizer::generateStrata()
|
---|
71 | {
|
---|
72 | using namespace mars;
|
---|
73 | typedef std::vector< MineralsDB::ClassesSet::value_type > ClassList;
|
---|
74 |
|
---|
75 | ClassList lstSilicaClassSelection;
|
---|
76 |
|
---|
77 | for (unsigned char s = _settings.layers.silica.minimum; s <= _settings.layers.silica.maximum; ++s)
|
---|
78 | {
|
---|
79 | MineralsDB::ClassesSetFacade facade = _pMinDB->getClassesBySilica(static_cast< Silica > (s));
|
---|
80 |
|
---|
81 | lstSilicaClassSelection.insert(lstSilicaClassSelection.end(), facade.begin(), facade.end());
|
---|
82 | }
|
---|
83 |
|
---|
84 | ptr< GeoStratumMPDG > pVMPDG =
|
---|
85 | GeoStratumMPDG::createInstance(
|
---|
86 | static_cast< unsigned short > (_nAbsWidth >> _stratum.lod),
|
---|
87 | static_cast< unsigned short > (_nAbsHeight >> _stratum.lod),
|
---|
88 | mars::Wrap
|
---|
89 | );
|
---|
90 |
|
---|
91 | for (size_t c = 0; c < _stratum.size(); ++c)
|
---|
92 | {
|
---|
93 | const size_t nClassCount = _settings.layers.classes.next();
|
---|
94 | for (size_t j = 0; j < nClassCount; ++j)
|
---|
95 | pVMPDG->reg(lstSilicaClassSelection[mars::RAND(lstSilicaClassSelection.size())]);
|
---|
96 |
|
---|
97 | pVMPDG->seed(1, _settings.layers.coarseness, static_cast< signed int > (_settings.layers.thickness.base + _pbsThickness[c]));
|
---|
98 | pVMPDG->run(_settings.layers.coarseness);
|
---|
99 |
|
---|
100 | const GeoStratumMPDG::Precision
|
---|
101 | min = pVMPDG->range().minimum;
|
---|
102 |
|
---|
103 | *pVMPDG -= min.altitude - GeoStratumField::ScalarTraits::step().altitude;
|
---|
104 |
|
---|
105 | _stratum[c] << *pVMPDG;
|
---|
106 |
|
---|
107 | assert(_stratum[c].range().minimum.altitude >= 0);
|
---|
108 |
|
---|
109 | pVMPDG->reset();
|
---|
110 | pVMPDG->clearRegs();
|
---|
111 | }
|
---|
112 |
|
---|
113 | // TODO: Automate
|
---|
114 | _stratum.updateIndexMap();
|
---|
115 | }
|
---|
116 |
|
---|
117 | void DepositSynthesizer::generateMinerals(const unsigned int nPass)
|
---|
118 | {
|
---|
119 | using namespace mars;
|
---|
120 | typedef std::set< ptr< MineralDef > > MineralSet;
|
---|
121 | const mars::RangeX< WorldUnit > rngStrata = _stratum.getRange();
|
---|
122 |
|
---|
123 | const size_t
|
---|
124 | nMineralCount = static_cast< size_t > (
|
---|
125 | _settings.minerals.frequency *
|
---|
126 | static_cast< float > (_nAbsWidth) / FREQUENCY_MULTIPLIER *
|
---|
127 | static_cast< float > (_nAbsHeight) / FREQUENCY_MULTIPLIER *
|
---|
128 | static_cast< float > (rngStrata.delta) / FREQUENCY_MULTIPLIER
|
---|
129 | );
|
---|
130 |
|
---|
131 | size_t c = 0;
|
---|
132 | MineralDepositList lstAssociations, lstProtoliths;
|
---|
133 | MineralSet setSelections;
|
---|
134 |
|
---|
135 | while (c < nMineralCount)
|
---|
136 | {
|
---|
137 | OctTreeOreInstance::VECTOR ptChosenSpot (RAND(_nAbsWidth), RAND(_nAbsHeight), rngStrata.next());
|
---|
138 | const size_t nNestCount = _settings.minerals.deposit.nesting.next();
|
---|
139 |
|
---|
140 | for (size_t j = 0; j <= nNestCount; ++j, ++c) // j <= x: Nesting value is number of nested hosted minerals not number of minerals total
|
---|
141 | {
|
---|
142 | const MinClassPtr pEnvironment = _stratum.getDominantElementVN3(ptChosenSpot.x, ptChosenSpot.y, ptChosenSpot.z);
|
---|
143 |
|
---|
144 | for (
|
---|
145 | OctTreeOreInstance::const_EntityRadialIterator
|
---|
146 | i = const_cast< const OctTreeOreInstance & > (_otOre).contents(
|
---|
147 | OctTreeOreInstance::MyRadialRegion(
|
---|
148 | ptChosenSpot,
|
---|
149 | _settings.minerals.neighborhood.next()
|
---|
150 | )
|
---|
151 | );
|
---|
152 | i;
|
---|
153 | ++i
|
---|
154 | )
|
---|
155 | {
|
---|
156 | if (i->pass < nPass)
|
---|
157 | {
|
---|
158 | MineralsDB::PetrogenyMineralSetFacade facminIncubated = _pMinDB->getIncubatedMinerals(i->deposit.mineral);
|
---|
159 |
|
---|
160 | lstProtoliths.push_back(i->deposit);
|
---|
161 | for (MineralsDB::PetrogenyMineralSet::const_iterator k = facminIncubated.begin(); k != facminIncubated.end(); ++k)
|
---|
162 | setSelections.insert(k->mineral);
|
---|
163 | }
|
---|
164 | else
|
---|
165 | {
|
---|
166 | MineralsDB::PetrogenyMineralSetFacade facminAssociated = _pMinDB->getAssociatedMinerals(i->deposit.mineral);
|
---|
167 |
|
---|
168 | lstAssociations.push_back(i->deposit);
|
---|
169 | for (MineralsDB::PetrogenyMineralSet::const_iterator k = facminAssociated.begin(); k != facminAssociated.end(); ++k)
|
---|
170 | setSelections.insert(k->mineral);
|
---|
171 | }
|
---|
172 | }
|
---|
173 |
|
---|
174 | MineralsDB::PetrogenyClassSetFacade facminEnvironment = _pMinDB->getMineralsByEnvironment(pEnvironment);
|
---|
175 |
|
---|
176 | for (MineralsDB::PetrogenyClassSet::const_iterator k = facminEnvironment.begin(); k != facminEnvironment.end(); ++k)
|
---|
177 | setSelections.insert(k->mineral);
|
---|
178 |
|
---|
179 | if (!setSelections.empty())
|
---|
180 | {
|
---|
181 | const size_t nSelection = RAND(setSelections.size());
|
---|
182 | MineralSet::const_iterator iMin = setSelections.begin();
|
---|
183 | std::vector< MineralDef::GenesisList::const_iterator > lstGeneses;
|
---|
184 | MineralDeposit depHost;
|
---|
185 |
|
---|
186 | std::advance(iMin, nSelection);
|
---|
187 | (*iMin)->intersectGeneses(lstGeneses, lstAssociations, lstProtoliths, depHost, pEnvironment);
|
---|
188 | if (!lstGeneses.empty())
|
---|
189 | {
|
---|
190 | const size_t nGenSelection = RAND(lstGeneses.size());
|
---|
191 | const PetrogenyDef & petrogeny = *lstGeneses[nGenSelection];
|
---|
192 | const std::pair< BubbleGumFactory::PackPtr, DepositDistribution > pairDeposit = depositMineral(petrogeny, ptChosenSpot, *iMin, nPass);
|
---|
193 | const BubbleGumFactory::PackPtr & pSpherePack = pairDeposit.first;
|
---|
194 | const DepositDistribution & enddDepositDistrib = pairDeposit.second;
|
---|
195 | const size_t nSphereCount = pSpherePack->count();
|
---|
196 | const size_t nSelectedHostSphere = RAND(nSphereCount);
|
---|
197 |
|
---|
198 | size_t k = 0;
|
---|
199 | for (BubbleGumFactory::PackPtr::Type::const_iterator iPack = pSpherePack->iterate(); iPack; ++iPack, ++k)
|
---|
200 | {
|
---|
201 | if (k == nSelectedHostSphere)
|
---|
202 | {
|
---|
203 | ptChosenSpot = iPack->p;
|
---|
204 | depHost = MineralDeposit(*iMin, enddDepositDistrib);
|
---|
205 | break;
|
---|
206 | }
|
---|
207 | }
|
---|
208 | }
|
---|
209 | }
|
---|
210 | }
|
---|
211 | lstAssociations.clear();
|
---|
212 | lstProtoliths.clear();
|
---|
213 | setSelections.clear();
|
---|
214 | }
|
---|
215 | }
|
---|
216 |
|
---|
217 | std::pair< DepositSynthesizer::BubbleGumFactory::PackPtr, DepositDistribution >
|
---|
218 | DepositSynthesizer::depositMineral( const PetrogenyDef & petrogeny, const OctTreeOreInstance::VECTOR & ptChosenSpot, const mars::ptr< MineralDef > & pMin, const size_t nPass )
|
---|
219 | {
|
---|
220 | using namespace mars;
|
---|
221 |
|
---|
222 | const PointScale enpsAbundance = _pbsAbundance(RANDf(1.0f));
|
---|
223 | const float fDepositSize = _pbsDepositSize[petrogeny.size] * _settings.minerals.deposit.base;
|
---|
224 | const size_t nSelDistOff = RAND(petrogeny.distributions.count());
|
---|
225 | size_t c = 0;
|
---|
226 | for (size_t i = 0; c < petrogeny.distributions.size() && i < nSelDistOff; petrogeny.distributions[c] && ++i, ++c);
|
---|
227 | const DepositDistribution enddDistrib = static_cast< DepositDistribution > (c);
|
---|
228 |
|
---|
229 | BubbleGumFactory::PackPtr pSpherePack;
|
---|
230 |
|
---|
231 | switch (enddDistrib)
|
---|
232 | {
|
---|
233 | case Dist_Cluster:
|
---|
234 | pSpherePack = _factBubbleGum.createCluster(ptChosenSpot, fDepositSize);
|
---|
235 | break;
|
---|
236 | case Dist_Vein:
|
---|
237 | {
|
---|
238 | const OctTreeOreInstance::VECTOR::Precision
|
---|
239 | nScale = static_cast< OctTreeOreInstance::VECTOR::Precision > (fDepositSize),
|
---|
240 | nHalfScale = nScale / 2;
|
---|
241 |
|
---|
242 | OctTreeOreInstance::VECTOR off (RAND(nScale) - nHalfScale, RAND(nScale) - nHalfScale, RAND(nScale) - nHalfScale);
|
---|
243 |
|
---|
244 | off *= nHalfScale;
|
---|
245 | off /= MAG(off);
|
---|
246 | pSpherePack = _factBubbleGum.createVein(ptChosenSpot - off, ptChosenSpot + off, fDepositSize, _settings.minerals.deposit.vein.deviation.next());
|
---|
247 | }
|
---|
248 | break;
|
---|
249 | case Dist_Dike:
|
---|
250 | {
|
---|
251 | const OctTreeOreInstance::VECTOR::Precision
|
---|
252 | nScale = static_cast< OctTreeOreInstance::VECTOR::Precision > (fDepositSize),
|
---|
253 | nHalfScale = nScale / 2;
|
---|
254 |
|
---|
255 | OctTreeOreInstance::VECTOR off (
|
---|
256 | (RAND(nScale) - nHalfScale) / static_cast< OctTreeOreInstance::VECTOR::Precision > (1.0f / (1.0f - _settings.minerals.deposit.dike.orthogonality.next())),
|
---|
257 | RAND(nScale) - nHalfScale,
|
---|
258 | (RAND(nScale) - nHalfScale) / static_cast< OctTreeOreInstance::VECTOR::Precision > (1.0f / (1.0f - _settings.minerals.deposit.dike.orthogonality.next()))
|
---|
259 | );
|
---|
260 |
|
---|
261 | off *= nHalfScale;
|
---|
262 | off /= MAG(off);
|
---|
263 | pSpherePack = _factBubbleGum.createVein(ptChosenSpot - off, ptChosenSpot + off, fDepositSize, _settings.minerals.deposit.dike.deviation.next());
|
---|
264 | }
|
---|
265 | break;
|
---|
266 | case Dist_Laccolith:
|
---|
267 | pSpherePack = _factBubbleGum.createLaccolith(ptChosenSpot, fDepositSize, _settings.minerals.deposit.laccolith.tail.next());
|
---|
268 | break;
|
---|
269 | case Dist_Sill:
|
---|
270 | case Dist_Layer:
|
---|
271 | LOG(mars::Log::Warn) << "Distribution of type sill/layer not implemented, mineral petrogeny dropped";
|
---|
272 | break;
|
---|
273 | }
|
---|
274 |
|
---|
275 | if (pSpherePack != NULL)
|
---|
276 | pSpherePack->store(_otOre, ptr< OreInstance > (new OreInstance(pMin, nPass, enddDistrib)));
|
---|
277 |
|
---|
278 | return std::pair< BubbleGumFactory::PackPtr, DepositDistribution > (pSpherePack, enddDistrib);
|
---|
279 | }
|
---|
280 |
|
---|
281 | void DepositSynthesizer::operator>>( FileSource::MineralMap & dest ) const
|
---|
282 | {
|
---|
283 | for (OctTreeOreInstance::const_EntityAllIterator i = const_cast< const OctTreeOreInstance & > (_otOre).contents(); i; ++i)
|
---|
284 | dest.add(i->deposit.mineral, FileSource::MineralMap::QuadTreeSpherePacks::MyCylindricalRegion (i.region()));
|
---|
285 | }
|
---|
286 | }
|
---|