15#include <unordered_map>
16#include <unordered_set>
23constexpr double kPi = 3.14159265358979323846;
47 bool operator==(
const EdgeKey& o)
const {
return a == o.a &&
b == o.b; }
51 size_t operator()(
const EdgeKey& k)
const {
return (
size_t(uint32_t(k.a)) << 32) ^ size_t(uint32_t(k.b)); }
54EdgeKey makeKey(
int a,
int b) {
55 if (
a >
b) std::swap(
a,
b);
62 explicit WeldMap(
double eps) : eps_(eps) {}
64 int add(
const Vec2&
p, std::vector<Vec2>& corners) {
65 const int qx = int(std::floor(
p.x / eps_));
66 const int qy = int(std::floor(
p.y / eps_));
67 for (
int dx = -1;
dx <= 1; ++
dx) {
68 for (
int dy = -1;
dy <= 1; ++
dy) {
70 if (it == buckets_.end())
continue;
76 const int idx = int(corners.size());
83 static uint64_t
key(
int qx,
int qy) {
return (uint64_t(uint32_t(
qx)) << 32) ^ uint64_t(uint32_t(
qy)); }
86 std::unordered_map<uint64_t, std::vector<int>> buckets_;
90std::vector<char> rollBoundaryStreetFlags(
const Polygon& land,
int mode,
double fraction, std::mt19937& rng) {
91 const size_t n = land.size();
92 std::vector<char> flags(
n, 1);
94 std::fill(flags.begin(), flags.end(), 0);
97 if (mode == 2 &&
n > 0) {
98 std::bernoulli_distribution dist(std::clamp(fraction, 0.0, 1.0));
100 for (
size_t i = 0; i <
n; ++i) {
101 flags[i] = dist(rng) ? 1 : 0;
104 if (any == 0) flags[0] = 1;
109double landScale(
const Polygon& land) {
110 if (land.empty())
return 1.0;
111 double minX = land[0].x, minY = land[0].y, maxX = land[0].x, maxY = land[0].y;
112 for (
const Vec2&
p : land) {
113 minX = std::min(minX,
p.x);
114 minY = std::min(minY,
p.y);
115 maxX = std::max(maxX,
p.x);
116 maxY = std::max(maxY,
p.y);
118 return std::max(1.0, std::max(maxX - minX, maxY - minY));
121bool cornerOnLand(
const Vec2&
p,
const Polygon& land,
double eps) {
122 const size_t n = land.size();
123 for (
size_t i = 0; i <
n; ++i) {
124 const Vec2&
a = land[i];
125 const Vec2&
b = land[size_t((i + 1) %
n)];
132bool edgeIsOnStreet(
const Vec2&
a,
const Vec2&
b,
const std::vector<std::pair<Vec2, Vec2>>& streetSegs,
double eps) {
133 for (
const auto&
s : streetSegs) {
140void rebuildGraph(UrbanGenerator::GenState& st) {
141 const double eps = 1e-6 * landScale(st.land);
144 st.rings.resize(st.parcels.size());
147 for (
size_t p = 0;
p < st.parcels.size(); ++
p) {
149 ring.ring.reserve(st.parcels[
p].size());
150 for (
const Vec2&
v : st.parcels[
p]) ring.ring.push_back(weld.add(
v, st.corners));
151 st.rings[size_t(
p)] = std::move(ring);
154 std::unordered_map<EdgeKey, int, EdgeKeyHash> edgeMap;
156 st.parcelEdges.assign(st.parcels.size(), {});
157 for (
size_t p = 0;
p < st.rings.size(); ++
p) {
158 const std::vector<int>& ring = st.rings[
p].ring;
159 const size_t m = ring.size();
160 for (
size_t i = 0; i <
m; ++i) {
161 const EdgeKey k = makeKey(ring[i], ring[
size_t((i + 1) %
m)]);
162 auto it = edgeMap.find(k);
164 if (it == edgeMap.end()) {
165 eid = int(st.edges.size());
166 st.edges.push_back({k.a, k.b,
false});
171 st.parcelEdges[size_t(
p)].push_back(eid);
175 st.edgeStreet.assign(st.edges.size(), 0);
176 for (
size_t i = 0; i < st.edges.size(); ++i) {
177 const Vec2&
a = st.corners[size_t(st.edges[i].a)];
178 const Vec2&
b = st.corners[size_t(st.edges[i].b)];
179 st.edgeStreet[size_t(i)] = edgeIsOnStreet(
a,
b, st.streetSegs, eps) ? 1 : 0;
180 st.edges[size_t(i)].isStreet = st.edgeStreet[size_t(i)] != 0;
183 st.cornerOnLandBoundary.assign(st.corners.size(), 0);
184 for (
size_t i = 0; i < st.corners.size(); ++i) {
185 if (cornerOnLand(st.corners[i], st.land, eps)) st.cornerOnLandBoundary[size_t(i)] = 1;
190 explicit UnionFind(
int n) : parent_(size_t(
n)) { std::iota(parent_.begin(), parent_.end(), 0); }
192 while (parent_[
size_t(
x)] !=
x) {
193 parent_[size_t(
x)] = parent_[size_t(parent_[
size_t(
x)])];
194 x = parent_[size_t(
x)];
198 void unite(
int a,
int b) {
199 const int ra = find(
a);
200 const int rb = find(
b);
201 if (ra != rb) parent_[size_t(ra)] = rb;
205 std::vector<int> parent_;
216double interiorAngle(
const std::vector<Vec2>& corners,
const std::vector<int>& ring,
size_t i) {
217 const size_t m = ring.size();
218 if (
m < 3)
return 0.0;
219 const Vec2& prev = corners[size_t(ring[(i +
m - 1) %
m])];
220 const Vec2& cur = corners[size_t(ring[i])];
221 const Vec2&
next = corners[size_t(ring[(i + 1) %
m])];
224 double a = std::acos(std::clamp(
dot(
u,
v), -1.0, 1.0));
225 if (
cross(
u,
v) < 0.0)
a = 2.0 * kPi -
a;
238 const double eps = 1e-6 *
scale;
239 const int n = int(st.
corners.size());
240 const int parcels = int(st.
rings.size());
242 for (
const Polygon& poly : st.parcels) landA +=
area(poly);
243 const double parcelScale = std::sqrt(std::max(1e-9, landA) /
double(std::max(1, parcels)));
244 const std::vector<Vec2> v0 = st.
corners;
245 if (
n == 0 || parcels == 0)
return;
248 std::vector<std::vector<int>> approxCorners;
249 std::vector<size_t> approxSides;
250 approxCorners.resize(
size_t(parcels));
251 approxSides.resize(
size_t(parcels));
252 for (
int p = 0;
p < parcels; ++
p) {
253 const std::vector<int>& ring = st.
rings[size_t(
p)].ring;
254 const size_t m = ring.size();
255 for (
size_t i = 0; i <
m; ++i) {
256 const int prev = ring[(i +
m - 1) %
m];
257 const int cur = ring[i];
258 const int next = ring[(i + 1) %
m];
260 approxCorners[size_t(
p)].push_back(cur);
263 approxSides[size_t(
p)] = approxCorners[size_t(
p)].size();
268 std::vector<char> fixed(
size_t(
n), 0);
269 std::vector<char> slide(
size_t(
n), 0);
271 std::vector<std::pair<double, int>>
boundary;
272 for (
int v = 0;
v <
n; ++
v) {
274 BoundaryPosition
pos;
277 for (
int e = 0; e <
pos.edgeIndex; ++e)
285 for (
size_t i = 0; i <
m; ++i) {
288 fixed[size_t(
v)] = 1;
294 slide[size_t(
v)] = 1;
296 fixed[size_t(
v)] = 1;
301 std::vector<Vec2> moves(
size_t(
n), {0, 0});
302 const double maxMove = 0.04 * parcelScale;
304 std::fill(moves.begin(), moves.end(), Vec2{0, 0});
307 for (
int p = 0;
p < parcels; ++
p) {
308 const std::vector<int>& ring = st.
rings[size_t(
p)].ring;
309 const size_t m = ring.size();
310 for (
size_t i = 0; i <
m; ++i) {
311 const int prev = ring[(i +
m - 1) %
m];
312 const int cur = ring[i];
313 const int next = ring[(i + 1) %
m];
316 moves[size_t(cur)] = moves[size_t(cur)] + L * opts.
optSide;
320 for (
const std::vector<int>& chain : st.streetChains) {
321 for (
size_t i = 1; i + 1 < chain.size(); ++i) {
322 const Vec2 L = st.
corners[size_t(chain[i - 1])] - st.
corners[size_t(chain[i])] * 2.0 +
323 st.
corners[size_t(chain[i + 1])];
324 moves[size_t(chain[i])] = moves[size_t(chain[i])] + L * opts.
optStre;
328 for (
const int jv : st.junctionVertices) {
329 std::vector<Vec2> dirs;
330 for (
const std::vector<int>& chain : st.streetChains) {
331 if (chain.size() >= 2 && chain.front() == jv)
332 dirs.push_back(st.
corners[
size_t(chain[1])] - st.
corners[
size_t(jv)]);
333 if (chain.size() >= 2 && chain.back() == jv)
334 dirs.push_back(st.
corners[
size_t(chain[chain.size() - 2])] - st.
corners[
size_t(jv)]);
336 for (
size_t a = 0;
a < dirs.size(); ++
a) {
337 for (
size_t b =
a + 1;
b < dirs.size(); ++
b) {
338 const double la =
length(dirs[
a]);
339 const double lb =
length(dirs[
b]);
340 if (la < 1e-9 || lb < 1e-9)
continue;
341 const double s =
dot(dirs[
a], dirs[
b]) / (la * lb);
344 if (
s < -0.707)
continue;
347 moves[size_t(jv)] = moves[size_t(jv)] - (pa + pb) * opts.
optJunc * 0.5;
348 for (
const auto& chain : st.streetChains) {
349 if (chain.size() < 2)
continue;
350 if (chain.front() == jv) moves[size_t(chain[1])] = moves[size_t(chain[1])] + pa * opts.
optJunc;
351 if (chain.back() == jv)
352 moves[size_t(chain[chain.size() - 2])] =
353 moves[size_t(chain[chain.size() - 2])] + pb * opts.
optJunc;
360 for (
int v = 0;
v <
n; ++
v) {
361 if (fixed[
size_t(
v)])
continue;
364 for (
int p = 0;
p < parcels; ++
p) {
365 const auto& ring = st.
rings[size_t(
p)].ring;
366 const size_t sides = approxSides[size_t(
p)];
367 if (
sides < 3)
continue;
368 for (
size_t i = 0; i < ring.size(); ++i) {
369 if (ring[i] !=
v)
continue;
370 bool isCorner =
false;
371 for (
const int c : approxCorners[size_t(
p)])
376 if (!isCorner)
continue;
378 const double theta = interiorAngle(st.
corners, ring, i);
379 const size_t m = ring.size();
385 err += std::clamp(
target - theta, -0.6, 0.6) * 0.5;
386 bisector = bisector +
b;
390 if (std::fabs(err) > 1e-6 &&
length(bisector) > 0.5) {
391 moves[size_t(
v)] = moves[size_t(
v)] +
normalize(bisector) * (err * opts.
optRegu * 0.15 * parcelScale);
395 for (
int v = 0;
v <
n; ++
v) {
396 moves[size_t(
v)] = moves[size_t(
v)] + (v0[size_t(
v)] - st.
corners[size_t(
v)]) * (opts.
optClose * 0.04);
399 std::vector<Vec2> nextPos = st.
corners;
400 for (
int v = 0;
v <
n; ++
v) {
401 if (fixed[
size_t(
v)])
continue;
402 Vec2 d = moves[size_t(
v)];
404 if (dl > maxMove)
d =
d * (maxMove / dl);
406 if (slide[
size_t(
v)]) {
407 BoundaryPosition
pos;
410 const Vec2& e1 = st.
land[size_t((
pos.edgeIndex + 1) % st.
land.size())];
411 int n0 = -1, n1 = -1;
412 for (
int u = 0;
u <
n; ++
u) {
417 if (n0 >= 0 && n1 >= 0) {
421 t = std::clamp(
t, 0.01, 0.99);
427 nextPos[size_t(
v)] = np;
431 for (
int p = 0;
p < parcels; ++
p) {
432 const std::vector<int>& ring = st.
rings[size_t(
p)].ring;
434 poly.reserve(ring.size());
435 for (
const int c : ring) poly.push_back(nextPos[size_t(
c)]);
445 std::vector<Vec2> check;
446 check.reserve(
size_t(
n));
447 for (
const Vec2&
c : nextPos) weld.add(
c, check);
448 if (
int(check.size()) !=
n)
break;
454 for (
int p = 0;
p < parcels; ++
p) {
455 const std::vector<int>& ring = st.
rings[size_t(
p)].ring;
456 for (
size_t i = 0; i < ring.size(); ++i) st.
parcels[
size_t(
p)][i] = st.
corners[size_t(ring[i])];
462bool UrbanGenerator::buildBoundaryStreets(GenState& st) {
463 st.land = opts_.
land;
464 if (st.land.size() < 3)
return false;
467 if (st.land.size() < 3)
return false;
469 st.streetSegs.clear();
470 const size_t n = st.land.size();
471 for (
size_t i = 0; i <
n; ++i) {
472 if (st.landEdgeStreet[i]) {
473 st.streetSegs.emplace_back(st.land[i], st.land[
size_t((i + 1) %
n)]);
481 if (opts_.
land.size() < 3) {
482 if (
error) *
error =
"urban: land polygon needs at least 3 vertices";
486 if (
error) *
error =
"urban: minParcelArea must be positive";
491 if (!buildBoundaryStreets(st)) {
492 if (
error) *
error =
"urban: invalid land polygon";
499 std::vector<Polygon> next;
500 splitAllParcels(st, next);
501 if (next.size() == st.
parcels.size())
break;
504 removeShortEdges(st);
506 generateStreets(st,
level + 1);
511 decomposeStreets(st);
515 const std::vector<char> streetFlags = st.
edgeStreet;
516 const std::vector<Polygon> preParcels = st.
parcels;
517 const std::vector<Vec2> preCorners = st.
corners;
522 preIrr = st.
parcels.empty() ? 0.0 : preIrr / double(st.
parcels.size());
523 optimizeLayoutGeometry(st, opts_);
525 for (
size_t e = 0; e < st.
edges.size(); ++e) st.
edges[
size_t(e)].isStreet = streetFlags[size_t(e)] != 0;
527 for (
size_t e = 0; e < st.
edges.size(); ++e) {
528 if (streetFlags[
size_t(e)]) {
532 decomposeStreets(st);
533 double postIrr = 0.0;
536 postIrr = st.
parcels.empty() ? 0.0 : postIrr / double(st.
parcels.size());
539 if (postIrr > preIrr + 1e-9) {
544 for (
size_t e = 0; e < st.
edges.size(); ++e) st.
edges[
size_t(e)].isStreet = streetFlags[size_t(e)] != 0;
545 decomposeStreets(st);
554 nextParcels.reserve(st.
parcels.size() * 2);
555 for (
const Polygon& poly : st.parcels) {
557 nextParcels.push_back(poly);
561 if (splitOneParcel(st, poly,
a,
b)) {
562 nextParcels.push_back(std::move(
a));
563 nextParcels.push_back(std::move(
b));
565 nextParcels.push_back(poly);
570bool UrbanGenerator::splitOneParcel(
const GenState& st,
const Polygon& poly,
Polygon& outA,
Polygon& outB)
const {
573 if (cands.empty())
return false;
575 const double eps = 1e-6 * landScale(st.land);
579 const auto accessRatio = [&](
const Polygon& half) {
581 if (
sides < 2)
return 0.0;
583 if (avgSide <= 1e-9)
return 0.0;
584 double streetLen = 0.0;
585 const size_t m = half.size();
586 for (
size_t i = 0; i <
m; ++i) {
587 if (edgeIsOnStreet(half[i], half[
size_t((i + 1) %
m)], st.streetSegs, eps))
588 streetLen +=
distance(half[i], half[
size_t((i + 1) %
m)]);
590 return streetLen / avgSide;
593 double bestScore = -std::numeric_limits<double>::infinity();
595 for (
const SplitCandidate& cand : cands) {
599 const double qSize = frac / std::max(1e-9, 1.0 - frac);
602 const double qRegu = 1.0 / (1.0 + ia + ib);
603 const double ra = accessRatio(
a);
604 const double rb = accessRatio(
b);
606 double qOrient = 0.0;
608 const Vec2 chord =
normalize(cand.line.back() - cand.line.front());
609 qOrient = std::fabs(
dot(chord, axis));
613 if (
score > bestScore) {
615 bestA = std::move(
a);
616 bestB = std::move(
b);
619 if (bestScore <= -std::numeric_limits<double>::infinity() / 2.0)
return false;
620 outA = std::move(bestA);
621 outB = std::move(bestB);
625void UrbanGenerator::removeShortEdges(UrbanGenerator::GenState& st) {
626 const double eps = 1e-6 * landScale(st.land);
627 for (
int pass = 0; pass < 24; ++pass) {
629 const size_t ecount = st.edges.size();
630 for (
size_t e = 0; e < ecount && !
removed; ++e) {
631 int p1 = -1, p2 = -1;
632 for (
size_t p = 0;
p < st.parcelEdges.size(); ++
p) {
633 for (
const int pe : st.parcelEdges[size_t(
p)]) {
642 if (p1 < 0 || p2 < 0)
continue;
643 const Vec2&
a = st.corners[size_t(st.edges[e].a)];
644 const Vec2&
b = st.corners[size_t(st.edges[e].b)];
646 const auto avgSide = [&](
int p) {
648 return approx.empty() ? 0.0 :
perimeter(approx) / double(approx.size());
650 if (len >= opts_.
shortEdgeFactor * std::min(avgSide(p1), avgSide(p2)))
continue;
655 for (
const Polygon& poly : st.parcels) {
657 for (Vec2&
v : sim) {
667 for (
Polygon& poly : st.parcels) {
668 for (Vec2&
v : poly) {
681void UrbanGenerator::generateStreets(UrbanGenerator::GenState& st,
int level) {
682 const int n = int(st.parcels.size());
683 auto reachableOf = [&](
int p) {
684 for (
const int e : st.parcelEdges[size_t(
p)])
685 if (st.edgeStreet[size_t(e)]) return true;
688 std::vector<char> reachable(
size_t(
n), 0);
689 for (
int p = 0;
p <
n; ++
p) reachable[
size_t(
p)] = reachableOf(
p) ? 1 : 0;
693 std::vector<std::vector<int>> edgeParcels(st.edges.size());
694 for (
int p = 0;
p <
n; ++
p) {
695 if (reachable[
size_t(
p)])
continue;
696 for (
const int e : st.parcelEdges[size_t(
p)]) edgeParcels[size_t(e)].push_back(
p);
698 for (
size_t e = 0; e < edgeParcels.size(); ++e)
699 for (
size_t k = 1; k < edgeParcels[e].size(); ++k) uf.unite(edgeParcels[e][0], edgeParcels[e][k]);
700 std::vector<std::vector<int>>
groups;
701 std::vector<int> groupOf(
size_t(
n), -1);
702 for (
int p = 0;
p <
n; ++
p) {
703 if (reachable[
size_t(
p)])
continue;
704 const int root = uf.find(
p);
705 if (groupOf[
size_t(
root)] < 0) {
709 groups[size_t(groupOf[
size_t(
root)])].push_back(
p);
711 bool changed =
false;
716 std::vector<char> groupEdge(st.edges.size(), 0);
718 for (const int e : st.parcelEdges[size_t(
p)]) groupEdge[size_t(e)] = 1;
720 std::vector<std::vector<int>> vertexEdges(st.corners.size());
721 std::vector<char>
border(st.corners.size(), 0);
722 for (
size_t e = 0; e < st.edges.size(); ++e) {
723 vertexEdges[size_t(st.edges[e].a)].push_back(
int(e));
724 vertexEdges[size_t(st.edges[e].b)].push_back(
int(e));
726 for (
size_t v = 0;
v < st.corners.size(); ++
v) {
727 if (st.cornerOnLandBoundary[
size_t(
v)]) {
731 for (
const int e : vertexEdges[size_t(
v)]) {
732 if (!groupEdge[
size_t(e)]) {
739 std::vector<int> accessEdges;
740 std::vector<int> accessVertices;
741 std::vector<char> uncovered(
size_t(
n), 0);
742 for (
const int p :
group) uncovered[size_t(
p)] = 1;
743 const int maxLen = 10;
744 for (
int accessRound = 0; accessRound < 6; ++accessRound) {
745 bool anyUncovered =
false;
747 if (uncovered[size_t(
p)]) {
751 if (!anyUncovered)
break;
755 std::vector<char> visited(st.corners.size(), 0);
756 std::vector<int>
path;
757 std::vector<int> pathEdges;
758 std::vector<char> pathCovers(
size_t(
n), 0);
761 std::function<void(
int,
int,
double,
int)> dfs = [&](
int v,
int depth,
double len,
int turns) {
763 const double score = double(coveredNow) * 1e9 - double(
turns) * 1e6 - len;
764 const double bestScore = double(
best.covered) * 1e9 - double(
best.turns) * 1e6 -
best.length;
765 if (
score > bestScore) {
767 cand.vertices =
path;
768 cand.edges = pathEdges;
771 cand.covered = coveredNow;
772 best = std::move(cand);
775 if (
depth >= maxLen)
return;
777 std::vector<int>
order = vertexEdges[size_t(
v)];
778 std::stable_sort(
order.begin(),
order.end(), [&](
int a,
int b) {
779 auto turnCost = [&](int eid) {
780 if (pathEdges.empty()) return 0.0;
781 const int pe = pathEdges.back();
782 const int w = st.edges[size_t(pe)].a == v ? st.edges[size_t(pe)].b : st.edges[size_t(pe)].a;
784 st.edges[size_t(eid)].a == v ? st.edges[size_t(eid)].b : st.edges[size_t(eid)].a;
785 return includedAngleDeg(st.corners[size_t(w)] - st.corners[size_t(v)],
786 st.corners[size_t(nv)] - st.corners[size_t(v)]);
788 const double ca = turnCost(
a);
789 const double cb = turnCost(
b);
790 if (ca != cb)
return ca > cb;
791 return distance(st.corners[
size_t(st.edges[
size_t(
a)].a)],
792 st.corners[
size_t(st.edges[
size_t(
a)].b)]) <
793 distance(st.corners[
size_t(st.edges[
size_t(
b)].a)],
794 st.corners[
size_t(st.edges[
size_t(
b)].b)]);
796 for (
const int eid :
order) {
797 if (!groupEdge[
size_t(eid)])
continue;
798 if (std::find(pathEdges.begin(), pathEdges.end(), eid) != pathEdges.end())
continue;
799 const int nv = st.edges[size_t(eid)].a ==
v ? st.edges[size_t(eid)].b : st.edges[size_t(eid)].a;
800 if (visited[
size_t(nv)])
continue;
801 const Vec2& pa = st.corners[size_t(
v)];
802 const Vec2& pb = st.corners[size_t(nv)];
803 double newLen = len +
distance(pa, pb);
804 int newTurns =
turns;
805 if (!pathEdges.empty()) {
806 const int pe = pathEdges.back();
807 const int w = st.edges[size_t(pe)].a ==
v ? st.edges[size_t(pe)].b : st.edges[size_t(pe)].a;
810 if (newTurns > 1)
continue;
811 visited[size_t(nv)] = 1;
813 pathEdges.push_back(eid);
814 for (
const int p :
group) {
815 if (uncovered[
size_t(
p)] && !pathCovers[
size_t(
p)] &&
816 std::find(st.parcelEdges[
size_t(
p)].begin(), st.parcelEdges[
size_t(
p)].end(), eid) !=
817 st.parcelEdges[
size_t(
p)].end()) {
818 pathCovers[size_t(
p)] = 1;
822 dfs(nv,
depth + 1, newLen, newTurns);
824 std::fill(pathCovers.begin(), pathCovers.end(), 0);
825 for (
const int pe : pathEdges) {
826 for (
const int p :
group) {
827 if (uncovered[
size_t(
p)] && !pathCovers[
size_t(
p)] &&
828 std::find(st.parcelEdges[
size_t(
p)].begin(), st.parcelEdges[
size_t(
p)].end(), pe) !=
829 st.parcelEdges[
size_t(
p)].end()) {
830 pathCovers[size_t(
p)] = 1;
836 pathEdges.pop_back();
837 visited[size_t(nv)] = 0;
841 for (
size_t v = 0;
v < st.corners.size(); ++
v) {
842 if (!
border[
size_t(
v)])
continue;
843 visited[size_t(
v)] = 1;
844 path.push_back(
int(
v));
845 dfs(
int(
v), 0, 0.0, 0);
847 visited[size_t(
v)] = 0;
849 if (
best.edges.empty())
break;
851 for (
const int e :
best.
edges) accessEdges.push_back(e);
855 for (
int p = 0;
p <
n; ++
p) {
856 if (uncovered[
size_t(
p)] &&
857 std::find(st.parcelEdges[
size_t(
p)].begin(), st.parcelEdges[
size_t(
p)].end(), pe) !=
858 st.parcelEdges[
size_t(
p)].end()) {
859 uncovered[size_t(
p)] = 0;
865 for (
const int e : accessEdges) {
866 if (!st.edgeStreet[
size_t(e)]) {
867 st.edgeStreet[size_t(e)] = 1;
868 st.edges[size_t(e)].isStreet =
true;
869 st.streetSegs.emplace_back(st.corners[
size_t(st.edges[e].a)], st.corners[
size_t(st.edges[e].b)]);
872 if (!accessVertices.empty()) connectAccessToNetwork(st, accessVertices);
876 for (
int p = 0;
p <
n; ++
p) reachable[
size_t(
p)] = reachableOf(
p) ? 1 : 0;
878 reconnectStreetEnds(st,
level);
881void UrbanGenerator::connectAccessToNetwork(UrbanGenerator::GenState& st,
const std::vector<int>& accessVertices,
882 const std::vector<char>* excludeTargets) {
883 if (accessVertices.empty())
return;
884 std::vector<char> isAccess(st.corners.size(), 0);
885 for (
const int v : accessVertices) isAccess[size_t(
v)] = 1;
886 std::vector<char>
target(st.corners.size(), 0);
888 for (
size_t e = 0; e < st.edges.size(); ++e) {
889 if (!st.edgeStreet[e])
continue;
890 for (
const int v : {st.edges[e].a, st.edges[e].b}) {
891 if (!isAccess[
size_t(
v)] && !
target[size_t(
v)] && (!excludeTargets || !(*excludeTargets)[size_t(
v)])) {
897 if (targetCount == 0)
return;
905 bool operator()(
const State&
a,
const State&
b)
const {
return a.cost >
b.cost; }
907 std::priority_queue<State, std::vector<State>, Cmp> pq;
908 std::unordered_map<uint64_t, double>
best;
909 std::unordered_map<uint64_t, uint64_t>
parent;
910 auto stateId = [&](
int v,
int pe) {
return (uint64_t(uint32_t(
v)) << 32) ^ uint64_t(uint32_t(pe + 1)); };
911 std::unordered_set<uint64_t> startStates;
913 std::vector<std::vector<int>> vertexEdges(st.corners.size());
914 for (
size_t e = 0; e < st.edges.size(); ++e) {
915 vertexEdges[size_t(st.edges[e].a)].push_back(
int(e));
916 vertexEdges[size_t(st.edges[e].b)].push_back(
int(e));
918 for (
const int v : accessVertices) {
919 for (
const int e : vertexEdges[size_t(
v)]) {
920 const uint64_t
id = stateId(
v, e);
922 startStates.insert(
id);
923 pq.push({
v, e, 0.0});
927 State goal{-1, -1, std::numeric_limits<double>::infinity()};
928 while (!pq.empty()) {
931 const uint64_t sid = stateId(
s.v,
s.pe);
932 auto it =
best.find(sid);
933 if (it ==
best.end() ||
s.cost > it->second + 1e-12)
continue;
934 if (
target[
size_t(
s.v)] && startStates.count(stateId(
s.v,
s.pe)) == 0) {
938 for (
const int e : vertexEdges[size_t(
s.
v)]) {
939 if (e ==
s.pe)
continue;
940 const int nv = st.edges[size_t(e)].a ==
s.v ? st.edges[size_t(e)].b : st.edges[size_t(e)].a;
941 const Vec2&
u = st.corners[size_t(
s.v)];
942 const int w = st.edges[size_t(
s.pe)].a ==
s.v ? st.edges[size_t(
s.pe)].b : st.edges[size_t(
s.pe)].a;
943 const Vec2&
v = st.corners[size_t(nv)];
945 const double turnCost =
angle <= 135.0 ? opts_.dijkstraJunctionWeight : 0.0;
946 const double nc =
s.cost +
distance(
u,
v) + turnCost;
947 const uint64_t nid = stateId(nv, e);
948 auto nit =
best.find(nid);
949 if (nit ==
best.end() || nc < nit->
second - 1e-12) {
952 pq.push({nv, e, nc});
956 if (goal.v < 0)
return;
958 std::vector<int> edgesOut;
963 edgesOut.push_back(pe);
964 const uint64_t
id = stateId(
v, pe);
965 if (startStates.count(
id) != 0)
break;
966 auto pit =
parent.find(
id);
967 if (pit ==
parent.end())
break;
968 const uint64_t nid = pit->second;
970 pe = int(uint32_t(nid)) - 1;
972 std::reverse(edgesOut.begin(), edgesOut.end());
974 for (
const int e : edgesOut) {
975 if (!st.edgeStreet[
size_t(e)]) {
976 st.edgeStreet[size_t(e)] = 1;
977 st.edges[size_t(e)].isStreet =
true;
978 st.streetSegs.emplace_back(st.corners[
size_t(st.edges[e].a)], st.corners[
size_t(st.edges[e].b)]);
983void UrbanGenerator::reconnectStreetEnds(UrbanGenerator::GenState& st,
int level) {
984 if (opts_.streetPattern == 3)
return;
985 if (opts_.streetPattern == 2 &&
level >= opts_.culDeSacAfterLevel)
return;
987 std::vector<int> ends;
988 std::vector<int> streetDegree(st.corners.size(), 0);
989 for (
size_t e = 0; e < st.edges.size(); ++e) {
990 if (!st.edgeStreet[e])
continue;
991 ++streetDegree[size_t(st.edges[e].a)];
992 ++streetDegree[size_t(st.edges[e].b)];
994 for (
size_t v = 0;
v < st.corners.size(); ++
v)
995 if (streetDegree[
size_t(
v)] == 1) ends.push_back(
int(
v));
996 if (ends.empty())
break;
997 bool connectedAny =
false;
998 for (
const int v : ends) {
999 std::vector<char> exclude(st.corners.size(), 0);
1000 exclude[size_t(
v)] = 1;
1001 for (
size_t e = 0; e < st.edges.size(); ++e) {
1002 if (!st.edgeStreet[e])
continue;
1003 if (st.edges[e].a ==
v) exclude[size_t(st.edges[e].b)] = 1;
1004 if (st.edges[e].b ==
v) exclude[size_t(st.edges[e].a)] = 1;
1006 const size_t before = st.streetSegs.size();
1007 connectAccessToNetwork(st, {
v}, &exclude);
1008 if (st.streetSegs.size() != before) connectedAny =
true;
1010 if (!connectedAny)
break;
1014void UrbanGenerator::decomposeStreets(UrbanGenerator::GenState& st) {
1015 std::vector<std::vector<int>> adj(st.corners.size());
1016 std::vector<char> used(st.edges.size(), 0);
1017 for (
size_t e = 0; e < st.edges.size(); ++e) {
1018 if (!st.edgeStreet[e])
continue;
1019 adj[size_t(st.edges[e].a)].push_back(
int(e));
1020 adj[size_t(st.edges[e].b)].push_back(
int(e));
1022 auto isJunctionOrEnd = [&](
int v) {
1023 if (adj[
size_t(
v)].size() != 2)
return true;
1024 const int e1 = adj[size_t(
v)][0];
1025 const int e2 = adj[size_t(
v)][1];
1026 const int w1 = st.edges[size_t(e1)].a ==
v ? st.edges[size_t(e1)].b : st.edges[size_t(e1)].a;
1027 const int w2 = st.edges[size_t(e2)].a ==
v ? st.edges[size_t(e2)].b : st.edges[size_t(e2)].a;
1029 st.corners[
size_t(w2)] - st.corners[
size_t(
v)]) <= 135.0;
1032 layout_.streets.clear();
1033 st.streetChains.clear();
1034 st.junctionVertices.clear();
1037 for (
size_t v = 0;
v < st.corners.size(); ++
v) {
1038 if (adj[
size_t(
v)].empty())
continue;
1039 if (adj[
size_t(
v)].
size() == 1)
1041 else if (isJunctionOrEnd(
int(
v)))
1045 auto walk = [&](
int startV,
int firstE,
bool allowLoop) {
1047 std::vector<int> chain;
1048 chain.push_back(startV);
1052 while (guard++ < 100000) {
1053 used[size_t(e)] = 1;
1054 const int nv = st.edges[size_t(e)].a ==
v ? st.edges[size_t(e)].b : st.edges[size_t(e)].a;
1055 chain.push_back(nv);
1057 if (isJunctionOrEnd(
v))
break;
1058 const int nextE = adj[size_t(
v)][0] == e ? adj[size_t(
v)][1] : adj[size_t(
v)][0];
1059 if (used[
size_t(nextE)])
break;
1062 if (chain.size() >= 2) {
1063 st.streetChains.push_back(chain);
1064 const int f = chain.front();
1065 const int b = chain.back();
1066 if (isJunctionOrEnd(
f) && adj[
size_t(
f)].
size() != 1 &&
1067 std::find(st.junctionVertices.begin(), st.junctionVertices.end(),
f) == st.junctionVertices.end())
1068 st.junctionVertices.push_back(
f);
1069 if (isJunctionOrEnd(
b) && adj[
size_t(
b)].
size() != 1 &&
1070 std::find(st.junctionVertices.begin(), st.junctionVertices.end(),
b) == st.junctionVertices.end())
1071 st.junctionVertices.push_back(
b);
1075 for (
size_t v = 0;
v < st.corners.size(); ++
v) {
1076 if (isJunctionOrEnd(
int(
v))) {
1077 for (
const int e : adj[size_t(
v)])
1078 if (!used[size_t(e)]) walk(int(
v), e, false);
1081 for (
size_t e = 0; e < st.edges.size(); ++e) {
1082 if (st.edgeStreet[e] && !used[e]) walk(st.edges[e].a,
int(e),
true);
1084 layout_.streetJunctions = junctions;
1085 layout_.streetEnds = ends;
1087 for (
const std::vector<int>& chain : st.streetChains) {
1089 s.width = opts_.streetWidth;
1090 for (
const int c : chain)
s.pts.push_back(st.corners[size_t(
c)]);
1091 layout_.streets.push_back(std::move(
s));
1095void UrbanGenerator::finalizeStats(UrbanGenerator::GenState& st) {
1096 layout_.corners = st.corners;
1097 layout_.parcels = st.rings;
1098 layout_.edges = st.edges;
1099 layout_.streetSegments.clear();
1100 for (
size_t e = 0; e < st.edges.size(); ++e)
1101 if (st.edgeStreet[e]) layout_.streetSegments.emplace_back(st.edges[e].a, st.edges[e].b);
1102 layout_.totalStreetLength = 0.0;
1103 for (
const Street&
s : layout_.streets) layout_.totalStreetLength +=
polylineLength(
s.pts);
1106 double mn = std::numeric_limits<double>::infinity();
1108 for (
const Polygon& poly : st.parcels) {
1111 mn = std::min(mn, irr);
1112 mx = std::max(mx, irr);
1114 layout_.avgIrregularity = st.parcels.empty() ? 0.0 : sum / double(st.parcels.size());
1115 layout_.minIrregularity = st.parcels.empty() ? 0.0 : mn;
1116 layout_.maxIrregularity = st.parcels.empty() ? 0.0 : mx;
building::EdgeCurveGroup group
eve::resource::CostSpec cost
std::array< float, 3 > scale
std::vector< Point > vertices
std::map< Cell, int > best
CommandLogBoundary boundary
Anchor rule, see above.
bool generate(std::string *error=nullptr)
Run the pipeline. On failure error receives a human-readable reason.
UrbanGenerator(UrbanOptions opts)
Urban generator.
constexpr HexDirection next(HexDirection d) noexcept
The next direction clockwise (NW wraps to NE).
Polygon approximatePolygon(const Polygon &ring)
Simplify a ring to its approximate polygon: consecutive edges with included angle > 135° are merged i...
Vec2 perpendicular(const Vec2 &a)
Perpendicular.
bool validSplit(const Polygon &poly, const Polyline &split, double minHalfArea, Polygon *outA, Polygon *outB, double *fracA)
Validity of a candidate split: both halves simple, positive area, inside the original.
double includedAngleDeg(const Vec2 &u, const Vec2 &v)
Included angle in degrees at the shared vertex between edge u (prev->shared) and v (shared->next),...
double distanceToSegment(const Vec2 &p, const Vec2 &a, const Vec2 &b)
Raster helper: does the pixel-center fall within eps of segment a-b?
Vec2 normalize(const Vec2 &a)
Normalize.
double dot(const Vec2 &a, const Vec2 &b)
Dot.
std::vector< Vec2 > Polygon
Closed polygon ring, stored CCW, without repeating the first point.
double cross(const Vec2 &a, const Vec2 &b)
Cross.
double perimeter(const Polygon &poly)
Perimeter length of a closed ring.
bool polygonIsSimple(const Polygon &poly)
Simple polygon test: no self intersections among non-adjacent ring edges.
double signedArea(const Polygon &poly)
Return the raw (possibly negative) signed area of a polygon ring.
double shapeIrregularity(const Polygon &approxRing, double gammaAngle, double gammaSide)
Shape irregularity metric of Eq. (1) over the approximate polygon: I = γ1·(1/N)·Σ(θi−θ̄)² + γ2·(1/(N·...
void cleanupRing(Polygon &poly, double eps)
Remove consecutive duplicate points (within eps) and points that create zero spikes.
double polylineLength(const Polyline &pl)
Total length of an open polyline.
std::vector< SplitCandidate > generateSplitCandidates(const Polygon &poly, int maxCandidates, double minHalfArea)
Generate candidate streamlines for binary partitioning of poly.
Vec2 closestPointOnBoundary(const Polygon &poly, const Vec2 &p, BoundaryPosition *pos)
Closest point on the polygon boundary; writes edge index + t in [0,1].
bool ensureCCW(Polygon &poly)
Ensure the ring is CCW (positive signed area); returns whether it was flipped.
bool isCollinear(const Vec2 &prev, const Vec2 &shared, const Vec2 &next)
True when two consecutive edges are considered collinear (included angle > 135°).
int axis(int64_t a, size_t rank)
Axis.
State
Lifecycle state of a generic transaction plan.
std::vector< std::pair< Vec2, Vec2 > > streetSegs
std::vector< Polygon > parcels
std::vector< char > landEdgeStreet
std::vector< char > edgeStreet
std::vector< Parcel > rings
std::vector< int > junctionVertices
std::vector< char > cornerOnLandBoundary
std::vector< Vec2 > corners
std::vector< GraphEdge > edges
std::vector< std::vector< int > > streetChains
std::vector< std::vector< int > > parcelEdges
All user-facing controls for the urban generator. Defaults follow the paper (λ=0.3/0....
double boundaryStreetFraction