[80a6a52] | 1 | #include "outflowchannels.h"
|
---|
| 2 |
|
---|
| 3 | #include <mars_util.h>
|
---|
| 4 | #include <mars_lookup.h>
|
---|
| 5 | #include <mars_ptr.h>
|
---|
| 6 |
|
---|
| 7 | using namespace mars;
|
---|
| 8 | using namespace geoworld::ofc;
|
---|
| 9 |
|
---|
| 10 | namespace geoworld
|
---|
| 11 | {
|
---|
| 12 | void OutflowChannelGM::init(SynthesisSession & manager, const IGeoWorldAccessor & accessor, const unsigned short nMaxWidth, const unsigned short nMaxHeight)
|
---|
| 13 | {
|
---|
| 14 | using namespace mars;
|
---|
| 15 |
|
---|
| 16 | const mars::RangeX< float > mmfDirs(_fGeneralDir - _fSourceSpread / 2.0f, _fGeneralDir + _fSourceSpread / 2.0f);
|
---|
| 17 |
|
---|
| 18 | for (unsigned int i = 0; i < _nSourcePoints; ++i)
|
---|
| 19 | {
|
---|
| 20 | const float fDir = mmfDirs.next();
|
---|
| 21 |
|
---|
| 22 | _chans.addStartPoint(
|
---|
| 23 | accessor.createCoords(
|
---|
| 24 | static_cast< GWSurfacePos::Precision > (_mmfSourceDisplacement.next() * cosf(fDir + static_cast< float > (mars::PI))),
|
---|
| 25 | static_cast< GWSurfacePos::Precision > (_mmfSourceDisplacement.next() * sinf(fDir + static_cast< float > (mars::PI)))
|
---|
| 26 | ),
|
---|
| 27 | fDir
|
---|
| 28 | );
|
---|
| 29 | }
|
---|
| 30 |
|
---|
| 31 | const float
|
---|
| 32 | nNewHalfWidth = static_cast< float > (nMaxWidth) / 2,
|
---|
| 33 | nNewHalfHeight = static_cast< float > (nMaxHeight) / 2;
|
---|
| 34 |
|
---|
| 35 | _chans.init(
|
---|
| 36 | new FluiDynQueryBridge (&accessor, _ptStart),
|
---|
| 37 | _mmnLevels.next(),
|
---|
| 38 | mars::BBox< float > (
|
---|
| 39 | -nNewHalfWidth + 1,
|
---|
| 40 | -nNewHalfHeight + 1,
|
---|
| 41 | +nNewHalfWidth - 1,
|
---|
| 42 | +nNewHalfHeight - 1
|
---|
| 43 | )
|
---|
| 44 | );
|
---|
| 45 |
|
---|
| 46 | const BBox< long > bbox = _chans.getBBox();
|
---|
| 47 |
|
---|
| 48 | if (!bbox.empty())
|
---|
| 49 | _bbox = _chans.getBBox() + _ptStart;
|
---|
| 50 | else
|
---|
| 51 | _bbox = BBox< long >();
|
---|
| 52 | }
|
---|
| 53 |
|
---|
| 54 | void OutflowChannelGM::doMorph (LockedGWSection & section) const
|
---|
| 55 | {
|
---|
| 56 | mars::BBox< long > bbox = getBBox();
|
---|
| 57 | LockedGWSection::View * pView = section.createView(bbox.left, bbox.top, bbox.right, bbox.bottom);
|
---|
| 58 |
|
---|
| 59 | _chans.run(pView->getHeightMap());
|
---|
| 60 |
|
---|
| 61 | section.releaseView(pView);
|
---|
| 62 | }
|
---|
| 63 |
|
---|
| 64 | OutflowChannelGM::~OutflowChannelGM()
|
---|
| 65 | {
|
---|
| 66 | }
|
---|
| 67 |
|
---|
| 68 | OutflowChannelGM::OutflowChannelGM(
|
---|
| 69 | const GWSurfacePos & ptStart,
|
---|
| 70 | const float fGeneralDir,
|
---|
| 71 | const unsigned int nSourcePoints,
|
---|
| 72 | const mars::RangeX< float > & mmfSourceDisplacement,
|
---|
| 73 | const float fSourceSpread,
|
---|
| 74 | const mars::RangeX< float > & mmfBendZenith,
|
---|
| 75 | const unsigned int nBendZenithSteps,
|
---|
| 76 | const unsigned int nCandidateSampleAmt,
|
---|
| 77 | const mars::RangeX< float > & mmfSplineSeg,
|
---|
| 78 | const float fGravitySlopeGrace,
|
---|
| 79 | const float fCarveWeight,
|
---|
| 80 | const float frSnapToGuide,
|
---|
| 81 | const mars::RangeX< float > & mmfFlowLineWidth,
|
---|
| 82 | const mars::RangeX< unsigned int > & mmnLevels,
|
---|
| 83 | const mars::RangeX< unsigned int > & mmnKidsPerLevel,
|
---|
| 84 | const float fwStraightness,
|
---|
| 85 | const float fwElevationInfluence,
|
---|
| 86 | const float fwDensityInfluence,
|
---|
| 87 | const float fwChaosInfluence,
|
---|
| 88 | const unsigned int nSedimentHistorySize
|
---|
| 89 | ) :
|
---|
| 90 | _mmfFlowLineWidth(mmfFlowLineWidth),
|
---|
| 91 | _mmnLevels(mmnLevels),
|
---|
| 92 | _chans(
|
---|
| 93 | mmfBendZenith, nBendZenithSteps, nCandidateSampleAmt, mmfSplineSeg,
|
---|
| 94 | fGravitySlopeGrace, fCarveWeight, frSnapToGuide, mmfFlowLineWidth, mmnKidsPerLevel,
|
---|
| 95 | fwStraightness, fwElevationInfluence, fwDensityInfluence, fwChaosInfluence,
|
---|
| 96 | nSedimentHistorySize
|
---|
| 97 | ),
|
---|
| 98 | _ptStart(ptStart),
|
---|
| 99 | _fGeneralDir(fGeneralDir),
|
---|
| 100 | _nSourcePoints(nSourcePoints),
|
---|
| 101 | _mmfSourceDisplacement(mmfSourceDisplacement),
|
---|
| 102 | _fSourceSpread(fSourceSpread)
|
---|
| 103 | {}
|
---|
| 104 |
|
---|
| 105 | OutflowChannelGM::OutflowChannelGM()
|
---|
| 106 | :
|
---|
| 107 | _fGeneralDir(0),
|
---|
| 108 | _nSourcePoints(0),
|
---|
| 109 | _fSourceSpread(0)
|
---|
| 110 | {}
|
---|
| 111 |
|
---|
| 112 | OutflowChannelGM * OutflowChannelGM::createInstance( mars::ObjectStream & ins )
|
---|
| 113 | {
|
---|
| 114 | OutflowChannelGM * pOFCGM = new OutflowChannelGM();
|
---|
| 115 |
|
---|
| 116 | ins
|
---|
| 117 | >> pOFCGM->_mmfFlowLineWidth
|
---|
| 118 | >> pOFCGM->_mmnLevels
|
---|
| 119 | >> pOFCGM->_ptStart
|
---|
| 120 | >> pOFCGM->_fGeneralDir
|
---|
| 121 | >> pOFCGM->_nSourcePoints
|
---|
| 122 | >> pOFCGM->_mmfSourceDisplacement
|
---|
| 123 | >> pOFCGM->_fSourceSpread
|
---|
| 124 | >> pOFCGM->_bbox;
|
---|
| 125 |
|
---|
| 126 | pOFCGM->_chans << ins;
|
---|
| 127 | return pOFCGM;
|
---|
| 128 | }
|
---|
| 129 |
|
---|
| 130 | mars::ObjectStream & OutflowChannelGM::operator >> ( mars::ObjectStream & outs ) const
|
---|
| 131 | {
|
---|
| 132 | outs
|
---|
| 133 | << _mmfFlowLineWidth
|
---|
| 134 | << _mmnLevels
|
---|
| 135 | << _ptStart
|
---|
| 136 | << _fGeneralDir
|
---|
| 137 | << _nSourcePoints
|
---|
| 138 | << _mmfSourceDisplacement
|
---|
| 139 | << _fSourceSpread
|
---|
| 140 | << _bbox;
|
---|
| 141 |
|
---|
| 142 | _chans >> outs;
|
---|
| 143 | return outs;
|
---|
| 144 | }
|
---|
| 145 |
|
---|
| 146 | void OutflowChannelGM::MyChannelSet::applyFlowLine( const FlowLineType & fl, OutflowChannelData * pData ) const
|
---|
| 147 | {
|
---|
| 148 | unsigned int nSplNum = 0;
|
---|
| 149 | mars::RingBuffer< HMPrec > & rbSediment = *_prbSediment;
|
---|
| 150 |
|
---|
| 151 | for (ChannelFinderType::FlowLineType::Iterator<GeoHeightMap::Precision, EaseInFn, EaseOutFn> it = fl.iterate<GeoHeightMap::Precision, EaseInFn, EaseOutFn>(_fnEaseIn, _fnEaseOut); it; ++it)
|
---|
| 152 | {
|
---|
| 153 | const VectorTag< unsigned short > ::V2 pos = *it;
|
---|
| 154 | // Reset sediment history if wrap-around to new spline
|
---|
| 155 | if (nSplNum != it.splineNum())
|
---|
| 156 | {
|
---|
| 157 | rbSediment.clear();
|
---|
| 158 | nSplNum = it.splineNum();
|
---|
| 159 | }
|
---|
| 160 |
|
---|
| 161 | // Total width
|
---|
| 162 | const float fTotalRadius = static_cast <float> (it.crad());
|
---|
| 163 |
|
---|
| 164 | // The radius as a ratio to the total width
|
---|
| 165 | const float frRadius = it.trad();
|
---|
| 166 |
|
---|
| 167 | // Perturbation value obtained from map
|
---|
| 168 | const float per = _perturb->getw(it.radius(), it.index());
|
---|
| 169 |
|
---|
| 170 | // Obtain the height at the current spot
|
---|
| 171 | const GeoHeightMap::Precision s = pData->view(pos.x, pos.y);
|
---|
| 172 |
|
---|
| 173 | // Diffused perturbed sediment index based on distance from spline spine
|
---|
| 174 | const unsigned int ips =
|
---|
| 175 | std::min(
|
---|
| 176 | static_cast< unsigned int > (_prbSediment->count - 1),
|
---|
| 177 | static_cast< unsigned int > (per * _fnBevel.rforce(frRadius) * fTotalRadius)
|
---|
| 178 | );
|
---|
| 179 |
|
---|
| 180 | // If the sediment value at the sediment index is empty/null
|
---|
| 181 | if (rbSediment[ips] == 0)
|
---|
| 182 | rbSediment[ips] = s;
|
---|
| 183 | else
|
---|
| 184 | rbSediment[ips] = (rbSediment[ips] + s) / 2;
|
---|
| 185 |
|
---|
| 186 | //const VectorTag< float > ::V3 T = it.stress();
|
---|
| 187 |
|
---|
| 188 | const GeoHeightMap::Precision
|
---|
| 189 | he = rbSediment[0],
|
---|
| 190 | h = static_cast <GeoHeightMap::Precision> (
|
---|
| 191 | (he == 0 ? s : (he + s) / 2)
|
---|
| 192 | + (_fnBevel.f(frRadius))
|
---|
| 193 | * getWidthRange().maximum
|
---|
| 194 | //* 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
|
---|
| 195 | );
|
---|
| 196 | ++rbSediment;
|
---|
| 197 |
|
---|
| 198 | pData->hmbb(pos.x, pos.y) =
|
---|
| 199 | std::min(
|
---|
| 200 | pData->view(pos.x, pos.y),
|
---|
| 201 | std::min(s, h)
|
---|
| 202 | );
|
---|
| 203 | }
|
---|
| 204 | pData->view << pData->hmbb;
|
---|
| 205 | }
|
---|
| 206 |
|
---|
| 207 | void OutflowChannelGM::MyChannelSet::init( const mars::ptr< FluiDynQueryBridge > & pQuery, const unsigned int nLevels, const mars::BBox< float > & bboxSearch )
|
---|
| 208 | {
|
---|
| 209 | using namespace mars;
|
---|
| 210 |
|
---|
| 211 | OutflowChannelGM::ChannelSetType::init(pQuery, bboxSearch, nLevels);
|
---|
| 212 |
|
---|
| 213 | const BBox< long > bbox = getBBox();
|
---|
| 214 |
|
---|
| 215 | if (!bbox.empty()) // Sometimes the finder algorithm fails to find any suitable paths, so we ditch this GeoMorph instance
|
---|
| 216 | {
|
---|
| 217 | const GWCoords pos3d = GWCoords(-bbox.left, -bbox.top, 0);
|
---|
| 218 |
|
---|
| 219 | for (MyChannelSet::GuideList::iterator i = begin(); i != end(); ++i)
|
---|
| 220 | (*i)->offsetBy(pos3d);
|
---|
| 221 |
|
---|
| 222 | _perturb =
|
---|
| 223 | PerturbMapType::createInstance(
|
---|
| 224 | static_cast< HMPrec >(getWidthRange().maximum),
|
---|
| 225 | static_cast< HMPrec >(sqrt(static_cast <float> (SQ(bbox.getWidth()) + SQ(bbox.getHeight())))),
|
---|
| 226 | mars::Wrap
|
---|
| 227 | );
|
---|
| 228 |
|
---|
| 229 | for (PerturbMapType::EdgeSeedIterator it = _perturb->edgeSeedIterator(); it; ++it)
|
---|
| 230 | {
|
---|
| 231 | it = static_cast <short> (RAND(_prbSediment->count));
|
---|
| 232 | }
|
---|
| 233 | _perturb->run(0.25f);
|
---|
| 234 | }
|
---|
| 235 | }
|
---|
| 236 |
|
---|
| 237 | void OutflowChannelGM::MyChannelSet::run( GeoHeightMap::View * pView ) const
|
---|
| 238 | {
|
---|
| 239 | OutflowChannelData data(pView);
|
---|
| 240 | OutflowChannelGM::ChannelSetType::run(&data);
|
---|
| 241 | }
|
---|
| 242 |
|
---|
| 243 | mars::ObjectStream & OutflowChannelGM::MyChannelSet::operator >> (mars::ObjectStream & outs) const
|
---|
| 244 | {
|
---|
| 245 | ChannelSetType::operator >> (outs);
|
---|
| 246 | outs << _fnBevel.getBevelDepth() << (_prbSediment == NULL ? 0 : _prbSediment->count);
|
---|
| 247 | return outs;
|
---|
| 248 | }
|
---|
| 249 | mars::ObjectStream & OutflowChannelGM::MyChannelSet::operator << (mars::ObjectStream & ins)
|
---|
| 250 | {
|
---|
| 251 | using namespace mars;
|
---|
| 252 |
|
---|
| 253 | ChannelSetType::operator << (ins);
|
---|
| 254 |
|
---|
| 255 | float fCarveWeight;
|
---|
| 256 | unsigned int nSedimentCount;
|
---|
| 257 |
|
---|
| 258 | ins >> fCarveWeight >> nSedimentCount;
|
---|
| 259 | _fnBevel = BevelFn(fCarveWeight);
|
---|
| 260 | delete _prbSediment;
|
---|
| 261 | _prbSediment = (nSedimentCount > 0 ? new RingBuffer< HMPrec >(nSedimentCount) : NULL);
|
---|
| 262 | return ins;
|
---|
| 263 | }
|
---|
| 264 |
|
---|
| 265 | OutflowChannelGM::MyChannelSet::MyChannelSet(
|
---|
| 266 | const mars::RangeX< float > & mmfBendZenith,
|
---|
| 267 | const unsigned int nBendZenithSteps,
|
---|
| 268 | const unsigned int nCandidateSampleAmt,
|
---|
| 269 | const mars::RangeX< float > & mmfSplineSeg,
|
---|
| 270 | const float fGravitySlopeGrace,
|
---|
| 271 | const float fCarveWeight,
|
---|
| 272 | const float frSnapToGuide,
|
---|
| 273 | const mars::RangeX< float > & mmfFlowLineWidth,
|
---|
| 274 | const mars::RangeX< unsigned int > & mmnKidsPerLevel,
|
---|
| 275 | const float fwStraightness,
|
---|
| 276 | const float fwElevationInfluence,
|
---|
| 277 | const float fwDensityInfluence,
|
---|
| 278 | const float fwChaosInfluence,
|
---|
| 279 | const unsigned int nSedimentHistorySize
|
---|
| 280 | )
|
---|
| 281 | : ChannelSet(
|
---|
| 282 | mmfBendZenith,
|
---|
| 283 | nBendZenithSteps,
|
---|
| 284 | nCandidateSampleAmt,
|
---|
| 285 | mmfSplineSeg,
|
---|
| 286 | fGravitySlopeGrace,
|
---|
| 287 | frSnapToGuide,
|
---|
| 288 | mmfFlowLineWidth,
|
---|
| 289 | mmnKidsPerLevel,
|
---|
| 290 | fwStraightness,
|
---|
| 291 | fwElevationInfluence,
|
---|
| 292 | fwDensityInfluence,
|
---|
| 293 | fwChaosInfluence
|
---|
| 294 | ),
|
---|
| 295 | _fnEaseOut(ofc::EASE_IN_FN),
|
---|
| 296 | _fnEaseIn(ofc::EASE_OUT_FN),
|
---|
| 297 | _fnBevel(fCarveWeight),
|
---|
| 298 | _prbSediment(new RingBuffer< HMPrec > (nSedimentHistorySize)),
|
---|
| 299 | _perturb(NULL)
|
---|
| 300 | {}
|
---|
| 301 |
|
---|
| 302 | OutflowChannelGM::MyChannelSet::MyChannelSet()
|
---|
| 303 | :
|
---|
| 304 | _fnEaseOut(ofc::EASE_IN_FN),
|
---|
| 305 | _fnEaseIn(ofc::EASE_OUT_FN),
|
---|
| 306 | _fnBevel(0),
|
---|
| 307 | _prbSediment(NULL),
|
---|
| 308 | _perturb(NULL)
|
---|
| 309 | {}
|
---|
| 310 |
|
---|
| 311 | OutflowChannelGM::MyChannelSet::~MyChannelSet()
|
---|
| 312 | {
|
---|
| 313 | delete _perturb;
|
---|
| 314 | delete _prbSediment;
|
---|
| 315 | }
|
---|
| 316 |
|
---|
| 317 | GeoMorph * OutflowChannelGMFactory::createRandomInstance( const long x, const long y ) const
|
---|
| 318 | {
|
---|
| 319 | return new OutflowChannelGM(
|
---|
| 320 | GWSurfacePos(x, y),
|
---|
| 321 | mars::RANDf(static_cast< float > (2 * mars::PI)),
|
---|
| 322 | _mmnSourcePoints.next(),
|
---|
| 323 | _mmfSourceDisplacement,
|
---|
| 324 | _mmfSourceSpread.next(),
|
---|
| 325 | _mmfBendZenith,
|
---|
| 326 | _nBendZenithSteps,
|
---|
| 327 | _nCandidateSampleAmount,
|
---|
| 328 | _mmfSplineSeg,
|
---|
| 329 | _fGravitySlopeGrace,
|
---|
| 330 | _fCarveWeight,
|
---|
| 331 | _frSnapToGuide,
|
---|
| 332 | _mmfFlowLineWidth,
|
---|
| 333 | _mmnLevels,
|
---|
| 334 | _mmnKidsPerLevel,
|
---|
| 335 | _fwStraightness,
|
---|
| 336 | _fwElevationInfluence,
|
---|
| 337 | _fwDensityInfluence,
|
---|
| 338 | _fwChaosInfluence,
|
---|
| 339 | _nSedimentHistorySize
|
---|
| 340 | );
|
---|
| 341 | }
|
---|
| 342 |
|
---|
| 343 | void OutflowChannelGMFactory::configure( IConfigGMFactory * pFactoryConfig, const IConfigGMFactory::Settings & settings )
|
---|
| 344 | {
|
---|
| 345 | geoworld::IConfigSection
|
---|
| 346 | & section = *pFactoryConfig->getSection(),
|
---|
| 347 | & sectCandidates = *section.getmap("candidates"),
|
---|
| 348 | & sectFlowlines = *section.getmap("flowlines"),
|
---|
| 349 | & sectWeights = *section.getmap("weights");
|
---|
| 350 |
|
---|
| 351 | *section["num_sources"] >> _mmnSourcePoints;
|
---|
| 352 | *section["displacement"] >> _mmfSourceDisplacement;
|
---|
| 353 | *section["spread"] >> _mmfSourceSpread;
|
---|
| 354 | *sectCandidates["bend_zenith"] >> _mmfBendZenith;
|
---|
| 355 | *sectCandidates["zenith_steps"] >> _nBendZenithSteps;
|
---|
| 356 | *sectCandidates["samples"] >> _nCandidateSampleAmount;
|
---|
| 357 | *section["segment"] >> _mmfSplineSeg;
|
---|
| 358 | *section["slope_grace"] >> _fGravitySlopeGrace;
|
---|
| 359 | *section["carve"] >> _fCarveWeight;
|
---|
| 360 | *section["guide_snap"] >> _frSnapToGuide;
|
---|
| 361 | *sectFlowlines["width"] >> _mmfFlowLineWidth;
|
---|
| 362 | *sectFlowlines["levels"] >> _mmnLevels;
|
---|
| 363 | *sectFlowlines["children"] >> _mmnKidsPerLevel;
|
---|
| 364 | *sectWeights["straightness"] >> _fwStraightness;
|
---|
| 365 | *sectWeights["elevation"] >> _fwElevationInfluence;
|
---|
| 366 | *sectWeights["density"] >> _fwDensityInfluence;
|
---|
| 367 | *sectWeights["chaos"] >> _fwChaosInfluence;
|
---|
| 368 | *section["sediment_memory"] >> _nSedimentHistorySize;
|
---|
| 369 | }
|
---|
| 370 |
|
---|
| 371 | void OutflowChannelGMFactory::save( const GeoMorph * pGM, mars::ObjectStream & outs ) const
|
---|
| 372 | {
|
---|
| 373 | const OutflowChannelGM * pOFCGM = dynamic_cast< const OutflowChannelGM * > (pGM);
|
---|
| 374 |
|
---|
| 375 | assert(pOFCGM != NULL);
|
---|
| 376 | *pOFCGM >> outs;
|
---|
| 377 | }
|
---|
| 378 |
|
---|
| 379 | const GeoMorph * OutflowChannelGMFactory::restore( mars::ObjectStream & ins ) const
|
---|
| 380 | {
|
---|
| 381 | OutflowChannelGM * pOFCGM;
|
---|
| 382 |
|
---|
| 383 | pOFCGM << ins;
|
---|
| 384 | return pOFCGM;
|
---|
| 385 | }
|
---|
| 386 | }
|
---|