#include "outflowchannels.h" #include #include #include using namespace mars; using namespace geoworld::ofc; namespace geoworld { void OutflowChannelGM::init(SynthesisSession & manager, const IGeoWorldAccessor & accessor, const unsigned short nMaxWidth, const unsigned short nMaxHeight) { using namespace mars; const mars::RangeX< float > mmfDirs(_fGeneralDir - _fSourceSpread / 2.0f, _fGeneralDir + _fSourceSpread / 2.0f); for (unsigned int i = 0; i < _nSourcePoints; ++i) { const float fDir = mmfDirs.next(); _chans.addStartPoint( accessor.createCoords( static_cast< GWSurfacePos::Precision > (_mmfSourceDisplacement.next() * cosf(fDir + static_cast< float > (mars::PI))), static_cast< GWSurfacePos::Precision > (_mmfSourceDisplacement.next() * sinf(fDir + static_cast< float > (mars::PI))) ), fDir ); } const float nNewHalfWidth = static_cast< float > (nMaxWidth) / 2, nNewHalfHeight = static_cast< float > (nMaxHeight) / 2; _chans.init( new FluiDynQueryBridge (&accessor, _ptStart), _mmnLevels.next(), mars::BBox< float > ( -nNewHalfWidth + 1, -nNewHalfHeight + 1, +nNewHalfWidth - 1, +nNewHalfHeight - 1 ) ); const BBox< long > bbox = _chans.getBBox(); if (!bbox.empty()) _bbox = _chans.getBBox() + _ptStart; else _bbox = BBox< long >(); } void OutflowChannelGM::doMorph (LockedGWSection & section) const { mars::BBox< long > bbox = getBBox(); LockedGWSection::View * pView = section.createView(bbox.left, bbox.top, bbox.right, bbox.bottom); _chans.run(pView->getHeightMap()); section.releaseView(pView); } OutflowChannelGM::~OutflowChannelGM() { } OutflowChannelGM::OutflowChannelGM( const GWSurfacePos & ptStart, const float fGeneralDir, const unsigned int nSourcePoints, const mars::RangeX< float > & mmfSourceDisplacement, const float fSourceSpread, const mars::RangeX< float > & mmfBendZenith, const unsigned int nBendZenithSteps, const unsigned int nCandidateSampleAmt, const mars::RangeX< float > & mmfSplineSeg, const float fGravitySlopeGrace, const float fCarveWeight, const float frSnapToGuide, const mars::RangeX< float > & mmfFlowLineWidth, const mars::RangeX< unsigned int > & mmnLevels, const mars::RangeX< unsigned int > & mmnKidsPerLevel, const float fwStraightness, const float fwElevationInfluence, const float fwDensityInfluence, const float fwChaosInfluence, const unsigned int nSedimentHistorySize ) : _mmfFlowLineWidth(mmfFlowLineWidth), _mmnLevels(mmnLevels), _chans( mmfBendZenith, nBendZenithSteps, nCandidateSampleAmt, mmfSplineSeg, fGravitySlopeGrace, fCarveWeight, frSnapToGuide, mmfFlowLineWidth, mmnKidsPerLevel, fwStraightness, fwElevationInfluence, fwDensityInfluence, fwChaosInfluence, nSedimentHistorySize ), _ptStart(ptStart), _fGeneralDir(fGeneralDir), _nSourcePoints(nSourcePoints), _mmfSourceDisplacement(mmfSourceDisplacement), _fSourceSpread(fSourceSpread) {} OutflowChannelGM::OutflowChannelGM() : _fGeneralDir(0), _nSourcePoints(0), _fSourceSpread(0) {} OutflowChannelGM * OutflowChannelGM::createInstance( mars::ObjectStream & ins ) { OutflowChannelGM * pOFCGM = new OutflowChannelGM(); ins >> pOFCGM->_mmfFlowLineWidth >> pOFCGM->_mmnLevels >> pOFCGM->_ptStart >> pOFCGM->_fGeneralDir >> pOFCGM->_nSourcePoints >> pOFCGM->_mmfSourceDisplacement >> pOFCGM->_fSourceSpread >> pOFCGM->_bbox; pOFCGM->_chans << ins; return pOFCGM; } mars::ObjectStream & OutflowChannelGM::operator >> ( mars::ObjectStream & outs ) const { outs << _mmfFlowLineWidth << _mmnLevels << _ptStart << _fGeneralDir << _nSourcePoints << _mmfSourceDisplacement << _fSourceSpread << _bbox; _chans >> outs; return outs; } void OutflowChannelGM::MyChannelSet::applyFlowLine( const FlowLineType & fl, OutflowChannelData * pData ) const { unsigned int nSplNum = 0; mars::RingBuffer< HMPrec > & rbSediment = *_prbSediment; for (ChannelFinderType::FlowLineType::Iterator it = fl.iterate(_fnEaseIn, _fnEaseOut); it; ++it) { const VectorTag< unsigned short > ::V2 pos = *it; // Reset sediment history if wrap-around to new spline if (nSplNum != it.splineNum()) { rbSediment.clear(); nSplNum = it.splineNum(); } // Total width const float fTotalRadius = static_cast (it.crad()); // The radius as a ratio to the total width const float frRadius = it.trad(); // Perturbation value obtained from map const float per = _perturb->getw(it.radius(), it.index()); // Obtain the height at the current spot const GeoHeightMap::Precision s = pData->view(pos.x, pos.y); // Diffused perturbed sediment index based on distance from spline spine const unsigned int ips = std::min( static_cast< unsigned int > (_prbSediment->count - 1), static_cast< unsigned int > (per * _fnBevel.rforce(frRadius) * fTotalRadius) ); // If the sediment value at the sediment index is empty/null if (rbSediment[ips] == 0) rbSediment[ips] = s; else rbSediment[ips] = (rbSediment[ips] + s) / 2; //const VectorTag< float > ::V3 T = it.stress(); const GeoHeightMap::Precision he = rbSediment[0], h = static_cast ( (he == 0 ? s : (he + s) / 2) + (_fnBevel.f(frRadius)) * getWidthRange().maximum //* std::max(0.0f, T.z / 4.0f) // HACK: Scale down the stress tensor, its scale is unvalidated // HACK: Add the stress tensor to the bevel ratio, scale unvalidated ); ++rbSediment; pData->hmbb(pos.x, pos.y) = std::min( pData->view(pos.x, pos.y), std::min(s, h) ); } pData->view << pData->hmbb; } void OutflowChannelGM::MyChannelSet::init( const mars::ptr< FluiDynQueryBridge > & pQuery, const unsigned int nLevels, const mars::BBox< float > & bboxSearch ) { using namespace mars; OutflowChannelGM::ChannelSetType::init(pQuery, bboxSearch, nLevels); const BBox< long > bbox = getBBox(); if (!bbox.empty()) // Sometimes the finder algorithm fails to find any suitable paths, so we ditch this GeoMorph instance { const GWCoords pos3d = GWCoords(-bbox.left, -bbox.top, 0); for (MyChannelSet::GuideList::iterator i = begin(); i != end(); ++i) (*i)->offsetBy(pos3d); _perturb = PerturbMapType::createInstance( static_cast< HMPrec >(getWidthRange().maximum), static_cast< HMPrec >(sqrt(static_cast (SQ(bbox.getWidth()) + SQ(bbox.getHeight())))), mars::Wrap ); for (PerturbMapType::EdgeSeedIterator it = _perturb->edgeSeedIterator(); it; ++it) { it = static_cast (RAND(_prbSediment->count)); } _perturb->run(0.25f); } } void OutflowChannelGM::MyChannelSet::run( GeoHeightMap::View * pView ) const { OutflowChannelData data(pView); OutflowChannelGM::ChannelSetType::run(&data); } mars::ObjectStream & OutflowChannelGM::MyChannelSet::operator >> (mars::ObjectStream & outs) const { ChannelSetType::operator >> (outs); outs << _fnBevel.getBevelDepth() << (_prbSediment == NULL ? 0 : _prbSediment->count); return outs; } mars::ObjectStream & OutflowChannelGM::MyChannelSet::operator << (mars::ObjectStream & ins) { using namespace mars; ChannelSetType::operator << (ins); float fCarveWeight; unsigned int nSedimentCount; ins >> fCarveWeight >> nSedimentCount; _fnBevel = BevelFn(fCarveWeight); delete _prbSediment; _prbSediment = (nSedimentCount > 0 ? new RingBuffer< HMPrec >(nSedimentCount) : NULL); return ins; } OutflowChannelGM::MyChannelSet::MyChannelSet( const mars::RangeX< float > & mmfBendZenith, const unsigned int nBendZenithSteps, const unsigned int nCandidateSampleAmt, const mars::RangeX< float > & mmfSplineSeg, const float fGravitySlopeGrace, const float fCarveWeight, const float frSnapToGuide, const mars::RangeX< float > & mmfFlowLineWidth, const mars::RangeX< unsigned int > & mmnKidsPerLevel, const float fwStraightness, const float fwElevationInfluence, const float fwDensityInfluence, const float fwChaosInfluence, const unsigned int nSedimentHistorySize ) : ChannelSet( mmfBendZenith, nBendZenithSteps, nCandidateSampleAmt, mmfSplineSeg, fGravitySlopeGrace, frSnapToGuide, mmfFlowLineWidth, mmnKidsPerLevel, fwStraightness, fwElevationInfluence, fwDensityInfluence, fwChaosInfluence ), _fnEaseOut(ofc::EASE_IN_FN), _fnEaseIn(ofc::EASE_OUT_FN), _fnBevel(fCarveWeight), _prbSediment(new RingBuffer< HMPrec > (nSedimentHistorySize)), _perturb(NULL) {} OutflowChannelGM::MyChannelSet::MyChannelSet() : _fnEaseOut(ofc::EASE_IN_FN), _fnEaseIn(ofc::EASE_OUT_FN), _fnBevel(0), _prbSediment(NULL), _perturb(NULL) {} OutflowChannelGM::MyChannelSet::~MyChannelSet() { delete _perturb; delete _prbSediment; } GeoMorph * OutflowChannelGMFactory::createRandomInstance( const long x, const long y ) const { return new OutflowChannelGM( GWSurfacePos(x, y), mars::RANDf(static_cast< float > (2 * mars::PI)), _mmnSourcePoints.next(), _mmfSourceDisplacement, _mmfSourceSpread.next(), _mmfBendZenith, _nBendZenithSteps, _nCandidateSampleAmount, _mmfSplineSeg, _fGravitySlopeGrace, _fCarveWeight, _frSnapToGuide, _mmfFlowLineWidth, _mmnLevels, _mmnKidsPerLevel, _fwStraightness, _fwElevationInfluence, _fwDensityInfluence, _fwChaosInfluence, _nSedimentHistorySize ); } void OutflowChannelGMFactory::configure( IConfigGMFactory * pFactoryConfig, const IConfigGMFactory::Settings & settings ) { geoworld::IConfigSection & section = *pFactoryConfig->getSection(), & sectCandidates = *section.getmap("candidates"), & sectFlowlines = *section.getmap("flowlines"), & sectWeights = *section.getmap("weights"); *section["num_sources"] >> _mmnSourcePoints; *section["displacement"] >> _mmfSourceDisplacement; *section["spread"] >> _mmfSourceSpread; *sectCandidates["bend_zenith"] >> _mmfBendZenith; *sectCandidates["zenith_steps"] >> _nBendZenithSteps; *sectCandidates["samples"] >> _nCandidateSampleAmount; *section["segment"] >> _mmfSplineSeg; *section["slope_grace"] >> _fGravitySlopeGrace; *section["carve"] >> _fCarveWeight; *section["guide_snap"] >> _frSnapToGuide; *sectFlowlines["width"] >> _mmfFlowLineWidth; *sectFlowlines["levels"] >> _mmnLevels; *sectFlowlines["children"] >> _mmnKidsPerLevel; *sectWeights["straightness"] >> _fwStraightness; *sectWeights["elevation"] >> _fwElevationInfluence; *sectWeights["density"] >> _fwDensityInfluence; *sectWeights["chaos"] >> _fwChaosInfluence; *section["sediment_memory"] >> _nSedimentHistorySize; } void OutflowChannelGMFactory::save( const GeoMorph * pGM, mars::ObjectStream & outs ) const { const OutflowChannelGM * pOFCGM = dynamic_cast< const OutflowChannelGM * > (pGM); assert(pOFCGM != NULL); *pOFCGM >> outs; } const GeoMorph * OutflowChannelGMFactory::restore( mars::ObjectStream & ins ) const { OutflowChannelGM * pOFCGM; pOFCGM << ins; return pOFCGM; } }