mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +02:00
Fixed zones getting actually randomized after construction. Tweaks to algorithm, now it's considerably better.
This commit is contained in:
@@ -80,25 +80,6 @@ void CZonePlacer::findPathsBetweenZones()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Dump debug
|
|
||||||
for (auto startZone : zones)
|
|
||||||
{
|
|
||||||
auto startId = startZone.second->getId();
|
|
||||||
|
|
||||||
for (auto endZone : zones)
|
|
||||||
{
|
|
||||||
auto endId = endZone.second->getId();
|
|
||||||
|
|
||||||
if (startId >= endId)
|
|
||||||
{
|
|
||||||
//Print only conections in one way
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
logGlobal->info((boost::format("Distance between zone %2d and %2d: %d")
|
|
||||||
% startId % endId % distancesBetweenZones[startId][endId]).str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CZonePlacer::placeOnGrid(CRandomGenerator* rand)
|
void CZonePlacer::placeOnGrid(CRandomGenerator* rand)
|
||||||
@@ -296,9 +277,9 @@ void CZonePlacer::placeOnGrid(CRandomGenerator* rand)
|
|||||||
{
|
{
|
||||||
//i.e. for grid size 5 we get range (0.5 - 4.5)
|
//i.e. for grid size 5 we get range (0.5 - 4.5)
|
||||||
auto targetX = rand->nextDouble(x + 0.5f, x + 0.5f);
|
auto targetX = rand->nextDouble(x + 0.5f, x + 0.5f);
|
||||||
vstd::clamp(targetX, 0.5, gridSize - 0.5);
|
std::clamp(targetX, 0.5, gridSize - 0.5);
|
||||||
auto targetY = rand->nextDouble(y + 0.5f, y + 0.5f);
|
auto targetY = rand->nextDouble(y + 0.5f, y + 0.5f);
|
||||||
vstd::clamp(targetY, 0.5, gridSize - 0.5);
|
std::clamp(targetY, 0.5, gridSize - 0.5);
|
||||||
|
|
||||||
zone->setCenter(float3(targetX / gridSize, targetY / gridSize, zone->getPos().z));
|
zone->setCenter(float3(targetX / gridSize, targetY / gridSize, zone->getPos().z));
|
||||||
}
|
}
|
||||||
@@ -324,13 +305,14 @@ void CZonePlacer::placeZones(CRandomGenerator * rand)
|
|||||||
placeOnGrid(rand);
|
placeOnGrid(rand);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gravity-based algorithm
|
Fruchterman-Reingold algorithm
|
||||||
|
|
||||||
let's assume we try to fit N circular zones with radius = size on a map
|
Let's assume we try to fit N circular zones with radius = size on a map
|
||||||
|
Connected zones attract, intersecting zones and map boundaries push back
|
||||||
*/
|
*/
|
||||||
|
|
||||||
gravityConstant = 2e-3f;
|
gravityConstant = 5e-4f;
|
||||||
stiffnessConstant = 6e-3f;
|
stiffnessConstant = 3e-3f;
|
||||||
|
|
||||||
TZoneVector zonesVector(zones.begin(), zones.end());
|
TZoneVector zonesVector(zones.begin(), zones.end());
|
||||||
assert (zonesVector.size());
|
assert (zonesVector.size());
|
||||||
@@ -340,8 +322,6 @@ void CZonePlacer::placeZones(CRandomGenerator * rand)
|
|||||||
//0. set zone sizes and surface / underground level
|
//0. set zone sizes and surface / underground level
|
||||||
prepareZones(zones, zonesVector, underground, rand);
|
prepareZones(zones, zonesVector, underground, rand);
|
||||||
|
|
||||||
//gravity-based algorithm. connected zones attract, intersecting zones and map boundaries push back
|
|
||||||
|
|
||||||
//remember best solution
|
//remember best solution
|
||||||
float bestTotalDistance = 1e10;
|
float bestTotalDistance = 1e10;
|
||||||
float bestTotalOverlap = 1e10;
|
float bestTotalOverlap = 1e10;
|
||||||
@@ -499,12 +479,14 @@ void CZonePlacer::prepareZones(TZoneMap &zones, TZoneVector &zonesVector, const
|
|||||||
else
|
else
|
||||||
levels[zone.first] = 0;
|
levels[zone.first] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const auto & zone : zonesVector)
|
for(const auto & zone : zonesVector)
|
||||||
{
|
{
|
||||||
int level = levels[zone.first];
|
int level = levels[zone.first];
|
||||||
totalSize[level] += (zone.second->getSize() * zone.second->getSize());
|
totalSize[level] += (zone.second->getSize() * zone.second->getSize());
|
||||||
auto randomAngle = static_cast<float>(rand->nextDouble(0, pi2));
|
float3 center = zone.second->getCenter();
|
||||||
zone.second->setCenter(float3(0.5f + std::sin(randomAngle) * radius, 0.5f + std::cos(randomAngle) * radius, level)); //place zones around circle
|
center.z = level;
|
||||||
|
zone.second->setCenter(center);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -538,6 +520,11 @@ void CZonePlacer::attractConnectedZones(TZoneMap & zones, TForceVector & forces,
|
|||||||
auto otherZone = zones[con];
|
auto otherZone = zones[con];
|
||||||
float3 otherZoneCenter = otherZone->getCenter();
|
float3 otherZoneCenter = otherZone->getCenter();
|
||||||
auto distance = static_cast<float>(pos.dist2d(otherZoneCenter));
|
auto distance = static_cast<float>(pos.dist2d(otherZoneCenter));
|
||||||
|
|
||||||
|
forceVector += (otherZoneCenter - pos) * distance * gravityConstant; //positive value
|
||||||
|
|
||||||
|
//Attract zone centers always
|
||||||
|
|
||||||
float minDistance = 0;
|
float minDistance = 0;
|
||||||
|
|
||||||
if (pos.z != otherZoneCenter.z)
|
if (pos.z != otherZoneCenter.z)
|
||||||
@@ -546,12 +533,7 @@ void CZonePlacer::attractConnectedZones(TZoneMap & zones, TForceVector & forces,
|
|||||||
minDistance = (zone.second->getSize() + otherZone->getSize()) / mapSize; //scale down to (0,1) coordinates
|
minDistance = (zone.second->getSize() + otherZone->getSize()) / mapSize; //scale down to (0,1) coordinates
|
||||||
|
|
||||||
if (distance > minDistance)
|
if (distance > minDistance)
|
||||||
{
|
|
||||||
//WARNING: compiler used to 'optimize' that line so it never actually worked
|
|
||||||
float overlapMultiplier = (pos.z == otherZoneCenter.z) ? (minDistance / distance) : 1.0f;
|
|
||||||
forceVector += ((otherZoneCenter - pos)* overlapMultiplier / getDistance(distance)) * gravityConstant; //positive value
|
|
||||||
totalDistance += (distance - minDistance);
|
totalDistance += (distance - minDistance);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
distances[zone.second] = totalDistance;
|
distances[zone.second] = totalDistance;
|
||||||
forceVector.z = 0; //operator - doesn't preserve z coordinate :/
|
forceVector.z = 0; //operator - doesn't preserve z coordinate :/
|
||||||
@@ -622,7 +604,7 @@ void CZonePlacer::separateOverlappingZones(TZoneMap &zones, TForceVector &forces
|
|||||||
void CZonePlacer::moveOneZone(TZoneMap & zones, TForceVector & totalForces, TDistanceVector & distances, TDistanceVector & overlaps) const
|
void CZonePlacer::moveOneZone(TZoneMap & zones, TForceVector & totalForces, TDistanceVector & distances, TDistanceVector & overlaps) const
|
||||||
{
|
{
|
||||||
float maxRatio = 0;
|
float maxRatio = 0;
|
||||||
const int maxDistanceMovementRatio = static_cast<int>(zones.size() * zones.size()); //experimental - the more zones, the greater total distance expected
|
const int maxDistanceMovementRatio = 1e1 * static_cast<int>(zones.size() * zones.size()); //experimental - the more zones, the greater total distance expected
|
||||||
std::shared_ptr<Zone> misplacedZone;
|
std::shared_ptr<Zone> misplacedZone;
|
||||||
|
|
||||||
float totalDistance = 0;
|
float totalDistance = 0;
|
||||||
|
Reference in New Issue
Block a user