Răsfoiți Sursa

Zone shapes & terrains work nicely.

DjWarmonger 11 ani în urmă
părinte
comite
d2fd71d087

+ 6 - 0
lib/mapping/CMapEditManager.cpp

@@ -98,6 +98,12 @@ void CTerrainSelection::deselectRange(const MapRect & rect)
 	});
 }
 
+void CTerrainSelection::setSelection(std::vector<int3> & vec)
+{
+	for (auto pos : vec)
+		this->select(pos);
+}
+
 void CTerrainSelection::selectAll()
 {
 	selectRange(MapRect(int3(0, 0, 0), getMap()->width, getMap()->height));

+ 1 - 0
lib/mapping/CMapEditManager.h

@@ -91,6 +91,7 @@ public:
 	void deselectRange(const MapRect & rect) override;
 	void selectAll() override;
 	void clearSelection() override;
+	void setSelection(std::vector<int3> & vec);
 };
 
 /// Selection class to select objects.

+ 3 - 0
lib/rmg/CMapGenerator.cpp

@@ -154,10 +154,13 @@ void CMapGenerator::genZones()
 
 	CZonePlacer placer(this);
 	placer.placeZones(mapGenOptions, &rand);
+	placer.assignZones(mapGenOptions);
 
 	int i = 0;
 	int part_w = w/player_per_side;
 	int part_h = h/player_per_side;
+
+
 	for(auto const it : zones)
 	{
 		CRmgTemplateZone * zone = it.second;

+ 48 - 37
lib/rmg/CRmgTemplateZone.cpp

@@ -294,46 +294,46 @@ void CRmgTemplateZone::setCenter(float3 f)
 
 bool CRmgTemplateZone::pointIsIn(int x, int y)
 {
-	int i, j;
-	bool c = false;
-	int nvert = shape.size();
-	for (i = 0, j = nvert-1; i < nvert; j = i++) {
-		if ( ((shape[i].y>y) != (shape[j].y>y)) &&
-			(x < (shape[j].x-shape[i].x) * (y-shape[i].y) / (shape[j].y-shape[i].y) + shape[i].x) )
-			c = !c;
-	}
-	return c;
+	//int i, j;
+	//bool c = false;
+	//int nvert = shape.size();
+	//for (i = 0, j = nvert-1; i < nvert; j = i++) {
+	//	if ( ((shape[i].y>y) != (shape[j].y>y)) &&
+	//		(x < (shape[j].x-shape[i].x) * (y-shape[i].y) / (shape[j].y-shape[i].y) + shape[i].x) )
+	//		c = !c;
+	//}
+	return true;
 }
 
 void CRmgTemplateZone::setShape(std::vector<int3> shape)
 {
-	int z = -1;
-	si32 minx = INT_MAX;
-	si32 maxx = -1;
-	si32 miny = INT_MAX;
-	si32 maxy = -1;
-	for(auto &point : shape)
-	{
-		if (z == -1)
-			z = point.z;
-		if (point.z != z)
-			throw rmgException("Zone shape points should lie on same z.");
-		minx = std::min(minx, point.x);
-		maxx = std::max(maxx, point.x);
-		miny = std::min(miny, point.y);
-		maxy = std::max(maxy, point.y);
-	}
+	//int z = -1;
+	//si32 minx = INT_MAX;
+	//si32 maxx = -1;
+	//si32 miny = INT_MAX;
+	//si32 maxy = -1;
+	//for(auto &point : shape)
+	//{
+	//	if (z == -1)
+	//		z = point.z;
+	//	if (point.z != z)
+	//		throw rmgException("Zone shape points should lie on same z.");
+	//	minx = std::min(minx, point.x);
+	//	maxx = std::max(maxx, point.x);
+	//	miny = std::min(miny, point.y);
+	//	maxy = std::max(maxy, point.y);
+	//}
 	this->shape = shape;
-	for(int x = minx; x <= maxx; ++x)
-	{
-		for(int y = miny; y <= maxy; ++y)
-		{
-			if (pointIsIn(x, y))
-			{
-				tileinfo[int3(x,y,z)] = CTileInfo();
-			}
-		}
-	}
+	//for(int x = minx; x <= maxx; ++x)
+	//{
+	//	for(int y = miny; y <= maxy; ++y)
+	//	{
+	//		if (pointIsIn(x, y))
+	//		{
+	//			tileinfo[int3(x,y,z)] = CTileInfo();
+	//		}
+	//	}
+	//}
 }
 
 int3 CRmgTemplateZone::getPos()
@@ -353,11 +353,16 @@ int3 CRmgTemplateZone::getPos()
 	//return int3(std::abs(cx/area/6), std::abs(cy/area/6), shape[0].z);
 	return pos;
 }
-void CRmgTemplateZone::setPos(int3 Pos)
+void CRmgTemplateZone::setPos(int3 &Pos)
 {
 	pos = Pos;
 }
 
+void CRmgTemplateZone::addTile (int3 &pos)
+{
+	tileinfo[pos] = CTileInfo();
+}
+
 bool CRmgTemplateZone::fill(CMapGenerator* gen)
 {
 	std::vector<CGObjectInstance*> required_objects;
@@ -393,7 +398,13 @@ bool CRmgTemplateZone::fill(CMapGenerator* gen)
 			playerInfo.posOfMainTown = town->pos - int3(2, 0, 0);
 			playerInfo.generateHeroAtMainTown = true;
 
-			gen->editManager->getTerrainSelection().selectRange(MapRect(shape[0], shape[2].y - shape[0].y, shape[2].x - shape[0].x));
+			//paint zone with matching terrain
+			std::vector<int3> tiles;
+			for (auto tile : tileinfo)
+			{
+				tiles.push_back (tile.first);
+			}
+			gen->editManager->getTerrainSelection().setSelection(tiles);
 			gen->editManager->drawTerrain(VLC->townh->factions[townId]->nativeTerrain, &gen->rand);
 
 			//required_objects.push_back(town);

+ 2 - 1
lib/rmg/CRmgTemplateZone.h

@@ -103,8 +103,9 @@ public:
 	float3 getCenter() const;
 	void setCenter(float3 f);
 	int3 getPos();
-	void setPos(int3 pos);
+	void setPos(int3 &pos);
 
+	void addTile (int3 &pos);
 	void setShape(std::vector<int3> shape);
 	bool fill(CMapGenerator* gen);
 

+ 60 - 0
lib/rmg/CZonePlacer.cpp

@@ -115,3 +115,63 @@ void CZonePlacer::placeZones(shared_ptr<CMapGenOptions> mapGenOptions, CRandomGe
 		logGlobal->infoStream() << boost::format ("Placed zone %d at relative position %s and coordinates %s") % zone.first % zone.second->getCenter() % zone.second->getPos();
 	}
 }
+
+float CZonePlacer::metric (int3 &A, int3 &B) const
+{
+/*
+
+Matlab code
+
+	dx = abs(A(1) - B(1)); %distance must be symmetric
+	dy = abs(A(2) - B(2));
+
+	d = 0.01 * dx^3 + 0.1 * dx^2 + 1 * dx + ...
+    0.03 * dy^3 - 0.3 * dy^2 + 0.3 * dy;
+*/
+
+	float dx = abs(A.x - B.x) * scaleX;
+	float dy = abs(A.y - B.y) * scaleY;
+
+	//Horner scheme
+	return dx * (1 + dx * (0.1 + dx * 0.01)) + dy * (0.3 + dy * (-0.3 + dy * 0.03));
+}
+
+void CZonePlacer::assignZones(shared_ptr<CMapGenOptions> mapGenOptions)
+{
+	auto width = mapGenOptions->getWidth();
+	auto height = mapGenOptions->getHeight();
+
+	//scale to Medium map to ensure smooth results
+	scaleX = 72.f / width;
+	scaleY = 72.f / height;
+
+	auto zones = gen->getZones();
+
+	typedef std::pair<CRmgTemplateZone *, float> Dpair;
+	std::vector <Dpair> distances;
+	distances.reserve(zones.size());
+
+	auto compareByDistance = [](const Dpair & lhs, const Dpair & rhs) -> bool
+	{
+		return lhs.second < rhs.second;
+	};
+
+	int levels = gen->map->twoLevel ? 2 : 1;
+	for (int i=0; i<width; i++)
+	{
+		for(int j=0; j<height; j++)
+		{
+			for (int k = 0; k < levels; k++)
+			{
+				distances.clear();
+				int3 pos(i, j, k);
+				for (auto zone : zones)
+				{
+					distances.push_back (std::make_pair(zone.second, metric(pos, zone.second->getPos())));
+				}
+				boost::sort (distances, compareByDistance);
+				distances.front().first->addTile(pos); //closest tile belongs to zone
+			}
+		}
+	}
+}

+ 6 - 0
lib/rmg/CZonePlacer.h

@@ -40,11 +40,17 @@ class CZonePlacer
 public:
 	explicit CZonePlacer(CMapGenerator * gen);
 	int3 cords (float3 f) const;
+	float metric (int3 &a, int3 &b) const;
 	~CZonePlacer();
 
 	void placeZones(shared_ptr<CMapGenOptions> mapGenOptions, CRandomGenerator * rand);
+	void assignZones(shared_ptr<CMapGenOptions> mapGenOptions);
 
 private:
+	//metric coefiicients
+	float scaleX;
+	float scaleY;
+	float a1, b1, c1, a2, b2, c2;
 	//CMap * map;
 	//unique_ptr<CZoneGraph> graph;
 	CMapGenerator * gen;