void CEnergyGrid::AddPylon(CCircuitUnit::Id unitId, CCircuitDef::Id defId, const AIFloat3& pos) { CMetalManager* metalManager = circuit->GetMetalManager(); const CMetalData::Clusters& clusters = metalManager->GetClusters(); const CMetalData::Graph& clusterGraph = metalManager->GetGraph(); // Find edges to which building belongs to float range = pylonRanges[defId]; float sqRange = range * range; CMetalData::Graph::edge_iterator edgeIt, edgeEnd; std::tie(edgeIt, edgeEnd) = boost::edges(clusterGraph); // or boost::tie for (; edgeIt != edgeEnd; ++edgeIt) { const CMetalData::EdgeDesc& edgeId = *edgeIt; int idxSource = boost::source(edgeId, clusterGraph); const AIFloat3& P0 = clusters[idxSource].geoCentr; int idxTarget = boost::target(edgeId, clusterGraph); const AIFloat3& P1 = clusters[idxTarget].geoCentr; if ((P0.SqDistance2D(pos) < sqRange) || (P1.SqDistance2D(pos) < sqRange) || (((P0 + P1) * 0.5f).SqDistance2D(pos) < P0.SqDistance2D(P1) * 0.25f)) { CEnergyLink& link = boost::get(linkIt, edgeId); link.AddPylon(unitId, pos, range); linkPylons.insert(edgeId); } } }
void CEnergyGrid::RebuildTree() { if (linkClusters.empty() && unlinkClusters.empty() && !isForceRebuild) { return; } isForceRebuild = false; CMetalManager* metalManager = circuit->GetMetalManager(); const CMetalData::Graph& clusterGraph = metalManager->GetGraph(); // Remove destroyed edges auto pred = [this](const CMetalData::EdgeDesc& desc) { spanningTree.erase(desc); return true; }; for (int index : unlinkClusters) { boost::remove_out_edge_if(index, pred, ownedClusters); } unlinkClusters.clear(); // Add new edges to Kruskal graph for (int index : linkClusters) { CMetalData::Graph::out_edge_iterator outEdgeIt, outEdgeEnd; std::tie(outEdgeIt, outEdgeEnd) = boost::out_edges(index, clusterGraph); // or boost::tie for (; outEdgeIt != outEdgeEnd; ++outEdgeIt) { const CMetalData::EdgeDesc& edgeId = *outEdgeIt; int idx0 = boost::target(edgeId, clusterGraph); if (linkedClusters[idx0]) { boost::add_edge(idx0, index, clusterGraph[edgeId], ownedClusters); CEnergyLink& link = boost::get(linkIt, edgeId); link.SetStartVertex(idx0); } } } linkClusters.clear(); float width = circuit->GetTerrainManager()->GetTerrainWidth(); float height = circuit->GetTerrainManager()->GetTerrainHeight(); float baseWeight = width * width + height * height; float invBaseWeight = 1.0f / baseWeight; // FIXME: only valid for 1 of the ally team const AIFloat3& basePos = circuit->GetSetupManager()->GetBasePos(); for (const CMetalData::EdgeDesc& edgeId : spanningTree) { CEnergyLink& link = boost::get(linkIt, edgeId); if (link.IsFinished() || link.IsBeingBuilt()) { // Mark used edges as const ownedClusters[edgeId].weight = clusterGraph[edgeId].weight * invBaseWeight; } else if (!link.IsValid()) { ownedClusters[edgeId].weight = clusterGraph[edgeId].weight * baseWeight; } else { // Adjust weight by distance to base const CMetalData::SEdge& edge = clusterGraph[edgeId]; ownedClusters[edgeId].weight = edge.weight * basePos.SqDistance2D(edge.center) * invBaseWeight; } } // Build Kruskal's minimum spanning tree spanningTree.clear(); boost::property_map<CMetalData::Graph, float CMetalData::SEdge::*>::type w_map = boost::get(&CMetalData::SEdge::weight, ownedClusters); boost::kruskal_minimum_spanning_tree(ownedClusters, std::inserter(spanningTree, spanningTree.end()), boost::weight_map(w_map)); }
void CEnergyGrid::Init() { for (auto& kv : circuit->GetCircuitDefs()) { const std::map<std::string, std::string>& customParams = kv.second->GetUnitDef()->GetCustomParams(); auto it = customParams.find("pylonrange"); if (it != customParams.end()) { pylonRanges[kv.first] = utils::string_to_float(it->second); } } // FIXME: const names const char* names[] = {"armestor", "armsolar", "armwin"}; for (const char* name : names) { CCircuitDef* cdef = circuit->GetCircuitDef(name); rangePylons[pylonRanges[cdef->GetId()]] = cdef->GetId(); } CMetalManager* metalManager = circuit->GetMetalManager(); const CMetalData::Clusters& clusters = metalManager->GetClusters(); const CMetalData::Graph& clusterGraph = metalManager->GetGraph(); linkedClusters.resize(clusters.size(), false); links.reserve(boost::num_edges(clusterGraph)); CMetalData::Graph::edge_iterator edgeIt, edgeEnd; std::tie(edgeIt, edgeEnd) = boost::edges(clusterGraph); for (; edgeIt != edgeEnd; ++edgeIt) { const CMetalData::EdgeDesc& edgeId = *edgeIt; int idx0 = boost::source(edgeId, clusterGraph); int idx1 = boost::target(edgeId, clusterGraph); links.emplace_back(idx0, clusters[idx0].geoCentr, idx1, clusters[idx1].geoCentr); } linkIt = boost::make_iterator_property_map(&links[0], boost::get(&CMetalData::SEdge::index, clusterGraph)); ownedClusters = CMetalData::Graph(boost::num_vertices(clusterGraph)); }
void CEnergyGrid::RemovePylon(CCircuitUnit::Id unitId) { CMetalManager* metalManager = circuit->GetMetalManager(); const CMetalData::Graph& clusterGraph = metalManager->GetGraph(); // Find edges to which building belongs to CMetalData::Graph::edge_iterator edgeIt, edgeEnd; std::tie(edgeIt, edgeEnd) = boost::edges(clusterGraph); // or boost::tie for (; edgeIt != edgeEnd; ++edgeIt) { const CMetalData::EdgeDesc& edgeId = *edgeIt; CEnergyLink& link = boost::get(linkIt, edgeId); if (link.RemovePylon(unitId)) { unlinkPylons.insert(edgeId); } } }
void CEnergyGrid::Init() { CMetalManager* metalManager = circuit->GetMetalManager(); const CMetalData::Clusters& clusters = metalManager->GetClusters(); const CMetalData::Graph& clusterGraph = metalManager->GetGraph(); linkedClusters.resize(clusters.size(), false); links.reserve(boost::num_edges(clusterGraph)); CMetalData::Graph::edge_iterator edgeIt, edgeEnd; std::tie(edgeIt, edgeEnd) = boost::edges(clusterGraph); for (; edgeIt != edgeEnd; ++edgeIt) { const CMetalData::EdgeDesc& edgeId = *edgeIt; int idx0 = boost::source(edgeId, clusterGraph); int idx1 = boost::target(edgeId, clusterGraph); links.emplace_back(idx0, clusters[idx0].geoCentr, idx1, clusters[idx1].geoCentr); } linkIt = boost::make_iterator_property_map(&links[0], boost::get(&CMetalData::SEdge::index, clusterGraph)); ownedClusters = CMetalData::Graph(boost::num_vertices(clusterGraph)); }