|
|
- /*
- * Copyright (C) 2017 Christopher J. Howard
- *
- * This file is part of Antkeeper Source Code.
- *
- * Antkeeper Source Code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Antkeeper Source Code is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Antkeeper Source Code. If not, see <http://www.gnu.org/licenses/>.
- */
-
- #include "nest.hpp"
- #include <algorithm>
- #include <cmath>
-
- #undef min
- #undef max
-
- Vector3 Shaft::getHelixPosition(float depth) const
- {
- Vector3 position;
- position.x = entrance.x + std::cos(initialHelixAngle + depth / helixPitch) * helixRadius;
- position.y = entrance.y + depth;
- position.z = entrance.z + std::sin(initialHelixAngle + depth / helixPitch) * helixRadius;
-
- return position;
- }
-
- float Shaft::getHelixAngle(float depth) const
- {
- return initialHelixAngle + depth / helixPitch;
- }
-
- Nest::Nest():
- root(nullptr)
- {}
-
- Nest::~Nest()
- {
- if (root != nullptr)
- {
- free(root);
- }
- }
-
- void Nest::generate()
- {
- if (root != nullptr)
- {
- // Delete existing shafts and chambers
- free(root);
- }
-
- // Seed random number generator
- rng.seed(parameters.randomSeed);
-
- // Generate shafts and chambers
- root = dig(nullptr);
-
- // Merge intersecting chambers
-
- // Create nest map
- map();
- }
-
- Shaft* Nest::dig(Chamber* parent) const
- {
- Shaft* shaft = new Shaft();
-
- // Set child's parent
- shaft->parent = parent;
-
- if (parent != nullptr)
- {
- // Set parent's child to this shaft
- parent->child = shaft;
-
- // Increment generation
- shaft->generation = parent->parent->generation + 1;
-
- // Determine initial helix angle
- shaft->initialHelixAngle = parent->parent->getHelixAngle(parent->relativeDepth);
- }
- else
- {
- // Shaft is root shaft
- shaft->generation = 0;
- shaft->entrance = Vector3(0.0f);
-
- // Choose initial helix angle
-
- }
-
- shaft->initialHelixAngle = random(glm::radians(-180.0f), glm::radians(180.0f));
-
- if (parent == nullptr)
- {
- // Choose initial random parameters
- shaft->shaftRadius = random(parameters.minShaftRadius, parameters.maxShaftRadius);
- shaft->helixRadius = random(parameters.minShaftHelixRadius, parameters.maxShaftHelixRadius);
- shaft->helixPitch = random(parameters.minShaftHelixPitch, parameters.maxShaftHelixPitch);
- }
- else
- {
- // Copy initial random parameters from grandparent
- shaft->shaftRadius = parent->parent->shaftRadius;
- shaft->helixRadius = parent->parent->helixRadius;
- shaft->helixPitch = parent->parent->helixPitch;
- }
-
- // Choose random depth
- shaft->shaftDepth = random(parameters.minShaftDepth, parameters.maxShaftDepth);
-
- // Calculate entrance position
- if (parent != nullptr)
- {
- Vector3 helixPosition = parent->parent->getHelixPosition(parent->relativeDepth);
- float helixAngle = parent->parent->getHelixAngle(parent->relativeDepth);
-
- shaft->entrance.x = helixPosition.x + std::cos(helixAngle) * (parent->outerRadius - parent->innerRadius) - std::cos(shaft->initialHelixAngle) * shaft->helixRadius;
- shaft->entrance.y = helixPosition.y;
- shaft->entrance.z = helixPosition.z + std::sin(helixAngle) * (parent->outerRadius - parent->innerRadius) - std::sin(shaft->initialHelixAngle) * shaft->helixRadius;
- }
-
- // Determine potential child count (may be less, according to spacing between chambers)
- int maxChildCount = std::max<int>(1, random(parameters.minShaftChamberCount, parameters.maxShaftChamberCount));
-
- // Generate chambers, starting with final chamber (shaft must end with a chamber)
- for (float depth = shaft->shaftDepth; depth >= 0.0f;)
- {
- Chamber* chamber = new Chamber();
- shaft->children.push_back(chamber);
-
- chamber->parent = shaft;
- chamber->child = nullptr;
- chamber->relativeDepth = depth;
- chamber->absoluteDepth = shaft->entrance.y + chamber->relativeDepth;
- chamber->innerRadius = random(parameters.minChamberInnerRadius, parameters.maxChamberInnerRadius);
- chamber->outerRadius = random(parameters.minChamberOuterRadius, parameters.maxChamberOuterRadius);
- chamber->centralAngle = random(parameters.minChamberCentralAngle, parameters.maxChamberCentralAngle);
-
- // Check if maximum child count has been reached
- if (shaft->children.size() >= maxChildCount)
- {
- break;
- }
-
- // Decrease depth by random amount
- depth -= random(parameters.minShaftChamberPitch, parameters.maxShaftChamberPitch);
- }
-
- // Generate subshafts from chambers
- if (shaft->generation < parameters.maxShaftGeneration)
- {
- for (Chamber* chamber: shaft->children)
- {
- dig(chamber);
- }
- }
-
- return shaft;
- }
-
- void Nest::merge()
- {
-
- }
-
- void Nest::map()
- {
-
- }
-
- void Nest::free(Shaft* shaft)
- {
- for (Chamber* chamber: shaft->children)
- {
- if (chamber->child != nullptr)
- {
- free(chamber->child);
- }
-
- delete chamber;
- }
-
- delete shaft;
- }
-
- inline float Nest::random(float minValue, float maxValue) const
- {
- std::uniform_real_distribution<float> distribution(minValue, std::nextafter(maxValue, std::numeric_limits<float>::max()));
- return distribution(rng);
- }
-
- inline int Nest::random(int minValue, int maxValue) const
- {
- std::uniform_int_distribution<int> distribution(minValue, std::nextafter(maxValue, std::numeric_limits<int>::max()));
- return distribution(rng);
- }
-
- void Nest::setParameters(const NestParameters& parameters)
- {
- this->parameters = parameters;
- }
-
- const NestParameters& Nest::getParameters() const
- {
- return parameters;
- }
|