/
GeekNerd
/
ServerModelingProject
Обзор
Документация
Войти
/
GeekNerd
/
ServerModelingProject
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
Assets/Scripts/OptimizationLogic/Core/ZonePartitioner.cs
191 строка
7 KB
Gorney-Alex
Init
30 май 2026, 19:05
30 май 2026, 19:05
3cdcc49
Код
Авторство
О чём код?
using System; using System.Collections.Generic; using DataClasses; using DataClasses.Algorithm; using UnityEngine; namespace OptimizationLogic.Core { public sealed class ZonePartitioner { public List<PlacementZone> Partition(RoomConfig room, IReadOnlyList<RackData> rackCatalog) { List<PlacementZone> zones = new(); if (room == null || room.PolygonVertices == null || room.PolygonVertices.Count < 3) return zones; float gridStep = room.GridStep > 0f ? room.GridStep : 0.6f; float dmin = room.MinAisleWidth > 0f ? room.MinAisleWidth : 1.0f; float maxRackWidth = 0.6f; if (rackCatalog != null) { for (int i = 0; i < rackCatalog.Count; i++) { RackData m = rackCatalog[i]; if (m == null) continue; maxRackWidth = Mathf.Max(maxRackWidth, Mathf.Max(m.Width, m.Length)); } } float zoneWidth = 2f * maxRackWidth + dmin; Rect bbox = Geometry2D.ComputeBoundingBox(room.PolygonVertices); // Choose slicing axis based on CRAC placement, not room aspect ratio. // CRACs on left/right wall -> sliceAlongX = false (horizontal strips along Y). // CRACs on top/bottom wall -> sliceAlongX = true (vertical strips along X). bool sliceAlongX = ShouldSliceAlongX(room, bbox); int zoneId = 0; if (sliceAlongX) { for (float x = bbox.xMin; x < bbox.xMax; x += zoneWidth) { Rect strip = new Rect(x, bbox.yMin, Mathf.Min(zoneWidth, bbox.xMax - x), bbox.height); PlacementZone zone = BuildZone(room, strip, zoneId++, gridStep); if (zone.CandidatePositions.Count > 0) zones.Add(zone); } } else { for (float y = bbox.yMin; y < bbox.yMax; y += zoneWidth) { Rect strip = new Rect(bbox.xMin, y, bbox.width, Mathf.Min(zoneWidth, bbox.yMax - y)); PlacementZone zone = BuildZone(room, strip, zoneId++, gridStep); if (zone.CandidatePositions.Count > 0) zones.Add(zone); } } // Debug: partition summary and per-zone details Debug.Log($"[ZonePartitioner] bbox={bbox}, sliceAlongX={sliceAlongX}, zones={zones.Count}"); for (int i = 0; i < zones.Count; i++) { PlacementZone z = zones[i]; Debug.Log($" Zone[{z.ZoneId}] bounds={z.Bounds}, coldDir={z.ColdAirDirection}, candidates={z.CandidatePositions.Count}"); } return zones; } /// <summary> /// CRACs on left/right wall -> sliceAlongX = false (strips along Y). /// CRACs on top/bottom wall -> sliceAlongX = true (strips along X). /// </summary> private static bool ShouldSliceAlongX(RoomConfig room, Rect bbox) { if (room.Cracs == null || room.Cracs.Count == 0) return bbox.width >= bbox.height; int onLeftRight = 0; int onTopBottom = 0; for (int i = 0; i < room.Cracs.Count; i++) { CracData c = room.Cracs[i]; if (c == null) continue; float distLR = Mathf.Min( Mathf.Abs(c.Center.x - bbox.xMin), Mathf.Abs(c.Center.x - bbox.xMax)); float distTB = Mathf.Min( Mathf.Abs(c.Center.y - bbox.yMin), Mathf.Abs(c.Center.y - bbox.yMax)); if (distLR < distTB) onLeftRight++; else onTopBottom++; } // CRACs on left/right -> sliceAlongX = false (slice along Y). Debug.Log($"[ZonePartitioner] ShouldSliceAlongX: onLeftRight={onLeftRight}, onTopBottom={onTopBottom}, result={onTopBottom > onLeftRight}"); return onTopBottom > onLeftRight; } private static PlacementZone BuildZone(RoomConfig room, Rect bounds, int zoneId, float gridStep) { PlacementZone zone = new PlacementZone { ZoneId = zoneId, Bounds = bounds, Capacity = 0, CandidatePositions = new List<Vector2>() }; Vector2 zoneCenter = bounds.center; zone.ColdAirDirection = ComputeColdDirection(room, zoneCenter); float startX = Mathf.Floor(bounds.xMin / gridStep) * gridStep; float startY = Mathf.Floor(bounds.yMin / gridStep) * gridStep; for (float x = startX; x <= bounds.xMax; x += gridStep) { for (float y = startY; y <= bounds.yMax; y += gridStep) { Vector2 p = new Vector2(x, y); if (!bounds.Contains(p)) continue; if (!Geometry2D.IsPointInPolygon(p, room.PolygonVertices)) continue; zone.CandidatePositions.Add(p); } } // Sort candidates: closer to nearest CRAC first (TZ requirement) if (room.Cracs != null && room.Cracs.Count > 0) { zone.CandidatePositions.Sort((a, b) => { float da = DistanceToNearestCrac(room.Cracs, a); float db = DistanceToNearestCrac(room.Cracs, b); return da.CompareTo(db); }); } zone.Capacity = zone.CandidatePositions.Count; return zone; } private static float DistanceToNearestCrac(IReadOnlyList<CracData> cracs, Vector2 point) { float best = float.PositiveInfinity; for (int i = 0; i < cracs.Count; i++) { CracData c = cracs[i]; if (c == null) continue; float d = Vector2.Distance(point, c.Center); if (d < best) best = d; } return best; } private static Vector2 ComputeColdDirection(RoomConfig room, Vector2 zoneCenter) { if (room.Cracs == null || room.Cracs.Count == 0) return Vector2.up; CracData best = null; float bestD = float.PositiveInfinity; for (int i = 0; i < room.Cracs.Count; i++) { CracData c = room.Cracs[i]; if (c == null) continue; float d = Vector2.SqrMagnitude(zoneCenter - c.Center); if (d < bestD) { bestD = d; best = c; } } if (best == null) return Vector2.up; // Flow direction from CRAC to the zone Vector2 raw = Geometry2D.SafeNormalize(zoneCenter - best.Center, Vector2.up); // Quantize to one of 4 axes to avoid ambiguous small components (e.g. -0.99, -0.16) // which can make multiple rack rotations appear "valid". if (Mathf.Abs(raw.x) >= Mathf.Abs(raw.y)) return new Vector2(Mathf.Sign(raw.x), 0f); return new Vector2(0f, Mathf.Sign(raw.y)); } } }