|
@@ -873,6 +873,11 @@ void CZonePlacer::assignZones(CRandomGenerator * rand)
|
|
|
int levels = map.levels();
|
|
|
|
|
|
// Find current center of mass for each zone. Move zone to that center to balance zones sizes
|
|
|
+ std::vector<RmgMap::Zones> zonesOnLevel;
|
|
|
+ for(int level = 0; level < levels; level++)
|
|
|
+ {
|
|
|
+ zonesOnLevel.push_back(map.getZonesOnLevel(level));
|
|
|
+ }
|
|
|
|
|
|
int3 pos;
|
|
|
|
|
@@ -883,12 +888,9 @@ void CZonePlacer::assignZones(CRandomGenerator * rand)
|
|
|
for(pos.y = 0; pos.y < height; pos.y++)
|
|
|
{
|
|
|
distances.clear();
|
|
|
- for(const auto & zone : zones)
|
|
|
+ for(const auto & zone : zonesOnLevel[pos.z])
|
|
|
{
|
|
|
- if (zone.second->getPos().z == pos.z)
|
|
|
- distances.emplace_back(zone.second, static_cast<float>(pos.dist2dSQ(zone.second->getPos())));
|
|
|
- else
|
|
|
- distances.emplace_back(zone.second, std::numeric_limits<float>::max());
|
|
|
+ distances.emplace_back(zone.second, static_cast<float>(pos.dist2dSQ(zone.second->getPos())));
|
|
|
}
|
|
|
boost::min_element(distances, compareByDistance)->first->area().add(pos); //closest tile belongs to zone
|
|
|
}
|
|
@@ -906,27 +908,30 @@ void CZonePlacer::assignZones(CRandomGenerator * rand)
|
|
|
for(const auto & zone : zones)
|
|
|
zone.second->clearTiles(); //now populate them again
|
|
|
|
|
|
- // Assign zones to closest Penrose vertex
|
|
|
PenroseTiling penrose;
|
|
|
- auto vertices = penrose.generatePenroseTiling(zones.size() / map.levels(), rand);
|
|
|
+ for (int level = 0; level < levels; level++)
|
|
|
+ {
|
|
|
+ //Create different tiling for each level
|
|
|
|
|
|
- std::map<std::shared_ptr<Zone>, std::set<int3>> vertexMapping;
|
|
|
+ auto vertices = penrose.generatePenroseTiling(zonesOnLevel[level].size(), rand);
|
|
|
|
|
|
- for (const auto & vertex : vertices)
|
|
|
- {
|
|
|
- distances.clear();
|
|
|
- for(const auto & zone : zones)
|
|
|
+ // Assign zones to closest Penrose vertex
|
|
|
+ std::map<std::shared_ptr<Zone>, std::set<int3>> vertexMapping;
|
|
|
+
|
|
|
+ for (const auto & vertex : vertices)
|
|
|
{
|
|
|
- distances.emplace_back(zone.second, zone.second->getCenter().dist2dSQ(float3(vertex.x(), vertex.y(), 0)));
|
|
|
- }
|
|
|
- auto closestZone = boost::min_element(distances, compareByDistance)->first;
|
|
|
+ distances.clear();
|
|
|
+ for(const auto & zone : zonesOnLevel[level])
|
|
|
+ {
|
|
|
+ distances.emplace_back(zone.second, zone.second->getCenter().dist2dSQ(float3(vertex.x(), vertex.y(), level)));
|
|
|
+ }
|
|
|
+ auto closestZone = boost::min_element(distances, compareByDistance)->first;
|
|
|
|
|
|
- vertexMapping[closestZone].insert(int3(vertex.x() * width, vertex.y() * height, closestZone->getPos().z)); //Closest vertex belongs to zone
|
|
|
- }
|
|
|
+ vertexMapping[closestZone].insert(int3(vertex.x() * width, vertex.y() * height, level)); //Closest vertex belongs to zone
|
|
|
+ }
|
|
|
|
|
|
- //Assign actual tiles to each zone
|
|
|
- for (pos.z = 0; pos.z < levels; pos.z++)
|
|
|
- {
|
|
|
+ //Assign actual tiles to each zone
|
|
|
+ pos.z = level;
|
|
|
for (pos.x = 0; pos.x < width; pos.x++)
|
|
|
{
|
|
|
for (pos.y = 0; pos.y < height; pos.y++)
|
|
@@ -937,27 +942,35 @@ void CZonePlacer::assignZones(CRandomGenerator * rand)
|
|
|
auto zone = zoneVertex.first;
|
|
|
for (const auto & vertex : zoneVertex.second)
|
|
|
{
|
|
|
- if (zone->getCenter().z == pos.z)
|
|
|
- distances.emplace_back(zone, metric(pos, vertex));
|
|
|
- else
|
|
|
- distances.emplace_back(zone, std::numeric_limits<float>::max());
|
|
|
+ distances.emplace_back(zone, metric(pos, vertex));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- //Tile closes to vertex belongs to zone
|
|
|
+ //Tile closest to vertex belongs to zone
|
|
|
auto closestZone = boost::min_element(distances, simpleCompareByDistance)->first;
|
|
|
closestZone->area().add(pos);
|
|
|
map.setZoneID(pos, closestZone->getId());
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ for(const auto & zone : zonesOnLevel[level])
|
|
|
+ {
|
|
|
+ if(zone.second->area().empty())
|
|
|
+ {
|
|
|
+ // FIXME: Some vertices are duplicated, but it's not a source of problem
|
|
|
+ logGlobal->error("Zone %d at %s is empty, dumping Penrose tiling", zone.second->getId(), zone.second->getCenter().toString());
|
|
|
+ for (const auto & vertex : vertices)
|
|
|
+ {
|
|
|
+ logGlobal->warn("Penrose Vertex: %s", vertex.toString());
|
|
|
+ }
|
|
|
+ throw rmgException("Empty zone after Penrose tiling");
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
//set position (town position) to center of mass of irregular zone
|
|
|
for(const auto & zone : zones)
|
|
|
{
|
|
|
- if(zone.second->area().empty())
|
|
|
- throw rmgException("Empty zone after Penrose tiling");
|
|
|
-
|
|
|
moveZoneToCenterOfMass(zone.second);
|
|
|
|
|
|
//TODO: similiar for islands
|