#include "oregen.h" #include #include namespace geoworld { const float DepositSynthesizer::FREQUENCY_MULTIPLIER = 1000; DepositSynthesizer::DepositSynthesizer(const MineralsDB * pMinDB, const DepositSynthesizerSettings & settings, const WorldUnit nWidth, const WorldUnit nHeight, const WorldUnit nDepth, const unsigned short nDEMLOD) : _pMinDB(pMinDB), _nAbsWidth(nWidth), _nAbsHeight(nHeight), _stratum(settings.layers.count, nWidth, nHeight, nDepth, nDEMLOD, mars::Wrap), _settings(settings), _otOre(std::max(nWidth, nHeight), 4), _factBubbleGum( settings.minerals.spherepack.limit, settings.minerals.spherepack.minimum, settings.minerals.spherepack.maxtier, settings.minerals.spherepack.sizeflux, settings.minerals.spherepack.kidflux, settings.minerals.deposit.vein.detail, settings.minerals.deposit.vein.erratic ), _pbsAbundance(settings.minerals.abundance.curve), _pbsDepositSize(settings.minerals.deposit.curve), _pbsThickness(settings.layers.count, settings.layers.thickness.curve, settings.layers.thickness.scale) { assert(((_nAbsWidth - 1) & _nAbsWidth) == 0 && ((_nAbsHeight - 1) & _nAbsHeight) == 0); // Must be a power of 2 } DepositSynthesizer::~DepositSynthesizer() { } DepositSynthesizerSettings DepositSynthesizer::loadSettings( IDepositSynthConfigReader & cfgreader ) { DepositSynthesizerSettings settings; cfgreader.load(settings); return settings; } Silica DepositSynthesizer::selectSilica( const float fRatio ) { if (fRatio < 0.16f) return Silica_NA; else if (fRatio < 0.17f * 2.0f) return Silica_UltraMafic; else if (fRatio < 0.17f * 3.0f) return Silica_Mafic; else if (fRatio < 0.17f * 4.0f) return Silica_Intermediate; else if (fRatio < 0.17f * 5.0f) return Silica_InterFelsic; else return Silica_Felsic; } Origin DepositSynthesizer::selectOrigin( const float fRatio ) { if (fRatio < 0.2f) return Origin_NA; else if (fRatio < 0.2f * 2.0f) return Origin_Plutonic; else if (fRatio < 0.2f * 3.0f) return Origin_Subvolcanic; else if (fRatio < 0.2f * 4.0f) return Origin_Volcanic; else return Origin_Meteoritic; } void DepositSynthesizer::generateStrata() { using namespace mars; typedef std::vector< MineralsDB::ClassesSet::value_type > ClassList; ClassList lstSilicaClassSelection; for (unsigned char s = _settings.layers.silica.minimum; s <= _settings.layers.silica.maximum; ++s) { MineralsDB::ClassesSetFacade facade = _pMinDB->getClassesBySilica(static_cast< Silica > (s)); lstSilicaClassSelection.insert(lstSilicaClassSelection.end(), facade.begin(), facade.end()); } ptr< GeoStratumMPDG > pVMPDG = GeoStratumMPDG::createInstance( static_cast< unsigned short > (_nAbsWidth >> _stratum.lod), static_cast< unsigned short > (_nAbsHeight >> _stratum.lod), mars::Wrap ); for (size_t c = 0; c < _stratum.size(); ++c) { const size_t nClassCount = _settings.layers.classes.next(); for (size_t j = 0; j < nClassCount; ++j) pVMPDG->reg(lstSilicaClassSelection[mars::RAND(lstSilicaClassSelection.size())]); pVMPDG->seed(1, _settings.layers.coarseness, static_cast< signed int > (_settings.layers.thickness.base + _pbsThickness[c])); pVMPDG->run(_settings.layers.coarseness); const GeoStratumMPDG::Precision min = pVMPDG->range().minimum; *pVMPDG -= min.altitude - GeoStratumField::ScalarTraits::step().altitude; _stratum[c] << *pVMPDG; assert(_stratum[c].range().minimum.altitude >= 0); pVMPDG->reset(); pVMPDG->clearRegs(); } // TODO: Automate _stratum.updateIndexMap(); } void DepositSynthesizer::generateMinerals(const unsigned int nPass) { using namespace mars; typedef std::set< ptr< MineralDef > > MineralSet; const mars::RangeX< WorldUnit > rngStrata = _stratum.getRange(); const size_t nMineralCount = static_cast< size_t > ( _settings.minerals.frequency * static_cast< float > (_nAbsWidth) / FREQUENCY_MULTIPLIER * static_cast< float > (_nAbsHeight) / FREQUENCY_MULTIPLIER * static_cast< float > (rngStrata.delta) / FREQUENCY_MULTIPLIER ); size_t c = 0; MineralDepositList lstAssociations, lstProtoliths; MineralSet setSelections; while (c < nMineralCount) { OctTreeOreInstance::VECTOR ptChosenSpot (RAND(_nAbsWidth), RAND(_nAbsHeight), rngStrata.next()); const size_t nNestCount = _settings.minerals.deposit.nesting.next(); for (size_t j = 0; j <= nNestCount; ++j, ++c) // j <= x: Nesting value is number of nested hosted minerals not number of minerals total { const MinClassPtr pEnvironment = _stratum.getDominantElementVN3(ptChosenSpot.x, ptChosenSpot.y, ptChosenSpot.z); for ( OctTreeOreInstance::const_EntityRadialIterator i = const_cast< const OctTreeOreInstance & > (_otOre).contents( OctTreeOreInstance::MyRadialRegion( ptChosenSpot, _settings.minerals.neighborhood.next() ) ); i; ++i ) { if (i->pass < nPass) { MineralsDB::PetrogenyMineralSetFacade facminIncubated = _pMinDB->getIncubatedMinerals(i->deposit.mineral); lstProtoliths.push_back(i->deposit); for (MineralsDB::PetrogenyMineralSet::const_iterator k = facminIncubated.begin(); k != facminIncubated.end(); ++k) setSelections.insert(k->mineral); } else { MineralsDB::PetrogenyMineralSetFacade facminAssociated = _pMinDB->getAssociatedMinerals(i->deposit.mineral); lstAssociations.push_back(i->deposit); for (MineralsDB::PetrogenyMineralSet::const_iterator k = facminAssociated.begin(); k != facminAssociated.end(); ++k) setSelections.insert(k->mineral); } } MineralsDB::PetrogenyClassSetFacade facminEnvironment = _pMinDB->getMineralsByEnvironment(pEnvironment); for (MineralsDB::PetrogenyClassSet::const_iterator k = facminEnvironment.begin(); k != facminEnvironment.end(); ++k) setSelections.insert(k->mineral); if (!setSelections.empty()) { const size_t nSelection = RAND(setSelections.size()); MineralSet::const_iterator iMin = setSelections.begin(); std::vector< MineralDef::GenesisList::const_iterator > lstGeneses; MineralDeposit depHost; std::advance(iMin, nSelection); (*iMin)->intersectGeneses(lstGeneses, lstAssociations, lstProtoliths, depHost, pEnvironment); if (!lstGeneses.empty()) { const size_t nGenSelection = RAND(lstGeneses.size()); const PetrogenyDef & petrogeny = *lstGeneses[nGenSelection]; const std::pair< BubbleGumFactory::PackPtr, DepositDistribution > pairDeposit = depositMineral(petrogeny, ptChosenSpot, *iMin, nPass); const BubbleGumFactory::PackPtr & pSpherePack = pairDeposit.first; const DepositDistribution & enddDepositDistrib = pairDeposit.second; const size_t nSphereCount = pSpherePack->count(); const size_t nSelectedHostSphere = RAND(nSphereCount); size_t k = 0; for (BubbleGumFactory::PackPtr::Type::const_iterator iPack = pSpherePack->iterate(); iPack; ++iPack, ++k) { if (k == nSelectedHostSphere) { ptChosenSpot = iPack->p; depHost = MineralDeposit(*iMin, enddDepositDistrib); break; } } } } } lstAssociations.clear(); lstProtoliths.clear(); setSelections.clear(); } } std::pair< DepositSynthesizer::BubbleGumFactory::PackPtr, DepositDistribution > DepositSynthesizer::depositMineral( const PetrogenyDef & petrogeny, const OctTreeOreInstance::VECTOR & ptChosenSpot, const mars::ptr< MineralDef > & pMin, const size_t nPass ) { using namespace mars; const PointScale enpsAbundance = _pbsAbundance(RANDf(1.0f)); const float fDepositSize = _pbsDepositSize[petrogeny.size] * _settings.minerals.deposit.base; const size_t nSelDistOff = RAND(petrogeny.distributions.count()); size_t c = 0; for (size_t i = 0; c < petrogeny.distributions.size() && i < nSelDistOff; petrogeny.distributions[c] && ++i, ++c); const DepositDistribution enddDistrib = static_cast< DepositDistribution > (c); BubbleGumFactory::PackPtr pSpherePack; switch (enddDistrib) { case Dist_Cluster: pSpherePack = _factBubbleGum.createCluster(ptChosenSpot, fDepositSize); break; case Dist_Vein: { const OctTreeOreInstance::VECTOR::Precision nScale = static_cast< OctTreeOreInstance::VECTOR::Precision > (fDepositSize), nHalfScale = nScale / 2; OctTreeOreInstance::VECTOR off (RAND(nScale) - nHalfScale, RAND(nScale) - nHalfScale, RAND(nScale) - nHalfScale); off *= nHalfScale; off /= MAG(off); pSpherePack = _factBubbleGum.createVein(ptChosenSpot - off, ptChosenSpot + off, fDepositSize, _settings.minerals.deposit.vein.deviation.next()); } break; case Dist_Dike: { const OctTreeOreInstance::VECTOR::Precision nScale = static_cast< OctTreeOreInstance::VECTOR::Precision > (fDepositSize), nHalfScale = nScale / 2; OctTreeOreInstance::VECTOR off ( (RAND(nScale) - nHalfScale) / static_cast< OctTreeOreInstance::VECTOR::Precision > (1.0f / (1.0f - _settings.minerals.deposit.dike.orthogonality.next())), RAND(nScale) - nHalfScale, (RAND(nScale) - nHalfScale) / static_cast< OctTreeOreInstance::VECTOR::Precision > (1.0f / (1.0f - _settings.minerals.deposit.dike.orthogonality.next())) ); off *= nHalfScale; off /= MAG(off); pSpherePack = _factBubbleGum.createVein(ptChosenSpot - off, ptChosenSpot + off, fDepositSize, _settings.minerals.deposit.dike.deviation.next()); } break; case Dist_Laccolith: pSpherePack = _factBubbleGum.createLaccolith(ptChosenSpot, fDepositSize, _settings.minerals.deposit.laccolith.tail.next()); break; case Dist_Sill: case Dist_Layer: LOG(mars::Log::Warn) << "Distribution of type sill/layer not implemented, mineral petrogeny dropped"; break; } if (pSpherePack != NULL) pSpherePack->store(_otOre, ptr< OreInstance > (new OreInstance(pMin, nPass, enddDistrib))); return std::pair< BubbleGumFactory::PackPtr, DepositDistribution > (pSpherePack, enddDistrib); } void DepositSynthesizer::operator>>( FileSource::MineralMap & dest ) const { for (OctTreeOreInstance::const_EntityAllIterator i = const_cast< const OctTreeOreInstance & > (_otOre).contents(); i; ++i) dest.add(i->deposit.mineral, FileSource::MineralMap::QuadTreeSpherePacks::MyCylindricalRegion (i.region())); } }