浏览代码

Fix crash with empty zone

Tomasz Zieliński 1 年之前
父节点
当前提交
c6a9d94630
共有 3 个文件被更改,包括 58 次插入26 次删除
  1. 40 20
      lib/rmg/CZonePlacer.cpp
  2. 16 6
      lib/rmg/PenroseTiling.cpp
  3. 2 0
      lib/rmg/PenroseTiling.h

+ 40 - 20
lib/rmg/CZonePlacer.cpp

@@ -906,27 +906,36 @@ 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
+		// Assign zones to closest Penrose vertex
+		// TODO: Count zones on a level exactly?
 
-	std::map<std::shared_ptr<Zone>, std::set<int3>> vertexMapping;
+		auto vertices = penrose.generatePenroseTiling(zones.size() / map.levels(), rand);
 
-	for (const auto & vertex : vertices)
-	{
-		distances.clear();
-		for(const auto & zone : zones)
+		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 : zones)
+			{
+				if (zone.second->isUnderground() == level)
+				{
+				// FIXME: Only take into account zones on the same level as vertex
+				// TODO: Create separate mapping for zones on different levels
+					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 +946,38 @@ void CZonePlacer::assignZones(CRandomGenerator * rand)
 					auto zone = zoneVertex.first;
 					for (const auto & vertex : zoneVertex.second)
 					{
-						if (zone->getCenter().z == pos.z)
+						if (zone->isUnderground() == level)
 							distances.emplace_back(zone, metric(pos, vertex));
 						else
 							distances.emplace_back(zone, std::numeric_limits<float>::max());
 					}
 				}
 
-				//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 : zones)
+		{
+			if(zone.second->isUnderground() == level && 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

+ 16 - 6
lib/rmg/PenroseTiling.cpp

@@ -38,6 +38,16 @@ bool Point2D::operator < (const Point2D& other) const
 	}
 }
 
+std::string Point2D::toString() const
+{
+	//Performance is important here
+	std::string result = "(" +
+			std::to_string(this->x()) + " " +
+			std::to_string(this->y()) + ")";
+
+	return result;
+}
+
 Triangle::Triangle(bool t_123, const TIndices & inds):
 	tiling(t_123),
 	indices(inds)
@@ -57,14 +67,14 @@ Triangle::~Triangle()
 
 Point2D Point2D::rotated(float radians) const
 {
-    float cosAngle = cos(radians);
-    float sinAngle = sin(radians);
+	float cosAngle = cos(radians);
+	float sinAngle = sin(radians);
 
-    // Apply rotation matrix transformation
-    float newX = x() * cosAngle - y() * sinAngle;
-    float newY = x() * sinAngle + y() * cosAngle;
+	// Apply rotation matrix transformation
+	float newX = x() * cosAngle - y() * sinAngle;
+	float newY = x() * sinAngle + y() * cosAngle;
 
-    return Point2D(newX, newY);
+	return Point2D(newX, newY);
 }
 
 void PenroseTiling::split(Triangle& p, std::vector<Point2D>& points,

+ 2 - 0
lib/rmg/PenroseTiling.h

@@ -32,6 +32,8 @@ public:
 	Point2D rotated(float radians) const;
 
 	bool operator < (const Point2D& other) const;
+
+	std::string toString() const;
 };
 
 Point2D rotatePoint(const Point2D& point, double radians, const Point2D& origin);