- regularize.rs: ρ=0 no-op, 0<ρ<1 lerp non-frontage verts toward
OBB-snapped target, ρ=1 full snap to oriented bounding rectangle.
- viz: add fig_03_cul_de_sac, fig_05_acute_corner, plot_subdivision_perf
(~125 µs/parcel at 25×25 scale), plot_parcel_area_hist (varied-block
scene so the distribution is actually distributed). fig_07 panels at
ρ ∈ {0, 0.5, 1.0} on a Y intersection (rectangles are no-ops for OBB).
- subdivide.rs cleanup pass: drop parcels on diff/union/conversion
fallback paths instead of pushing untracked claims (was admitting
overlaps). find_frontage_edge_after_clip now takes a tolerance — the
cleanup pass uses a few-mm window since its inputs are 1mm-snapped.
- tests: bump assert_no_overlapping_parcels tol to 1cm² (the snap grid
produces ~mm-scale slivers between adjacent parcels at intersection
centers; still well below min_area).
Closes M1.0 DoD: all named tests pass, all spec figures present, OBB
regularization working, perf at ~0.13 ms/parcel.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
148 lines
15 KiB
XML
148 lines
15 KiB
XML
<svg height="1080" viewBox="-65 -205 130 270" width="520" xmlns="http://www.w3.org/2000/svg">
|
|
<rect fill="#ffffff" height="270" width="130" x="-65" y="-205"/>
|
|
<g transform="translate(0, -140) scale(1, -1)">
|
|
<g id="roads">
|
|
<line stroke="#000000" stroke-linecap="round" stroke-width="0.6" x1="0" x2="-0.000000000000011021821192326178" y1="-200" y2="-60"/>
|
|
<line stroke="#000000" stroke-linecap="round" stroke-width="0.6" x1="60" x2="51.96152422706632" y1="0" y2="29.999999999999996"/>
|
|
<line stroke="#000000" stroke-linecap="round" stroke-width="0.6" x1="51.96152422706632" x2="30.000000000000007" y1="29.999999999999996" y2="51.96152422706631"/>
|
|
<line stroke="#000000" stroke-linecap="round" stroke-width="0.6" x1="30.000000000000007" x2="0.00000000000000367394039744206" y1="51.96152422706631" y2="60"/>
|
|
<line stroke="#000000" stroke-linecap="round" stroke-width="0.6" x1="0.00000000000000367394039744206" x2="-29.99999999999999" y1="60" y2="51.96152422706632"/>
|
|
<line stroke="#000000" stroke-linecap="round" stroke-width="0.6" x1="-29.99999999999999" x2="-51.96152422706632" y1="51.96152422706632" y2="29.999999999999996"/>
|
|
<line stroke="#000000" stroke-linecap="round" stroke-width="0.6" x1="-51.96152422706632" x2="-60" y1="29.999999999999996" y2="0.00000000000000734788079488412"/>
|
|
<line stroke="#000000" stroke-linecap="round" stroke-width="0.6" x1="-60" x2="-51.96152422706631" y1="0.00000000000000734788079488412" y2="-30.000000000000007"/>
|
|
<line stroke="#000000" stroke-linecap="round" stroke-width="0.6" x1="-51.96152422706631" x2="-30.00000000000003" y1="-30.000000000000007" y2="-51.961524227066306"/>
|
|
<line stroke="#000000" stroke-linecap="round" stroke-width="0.6" x1="-30.00000000000003" x2="-0.000000000000011021821192326178" y1="-51.961524227066306" y2="-60"/>
|
|
<line stroke="#000000" stroke-linecap="round" stroke-width="0.6" x1="-0.000000000000011021821192326178" x2="30.000000000000007" y1="-60" y2="-51.96152422706631"/>
|
|
<line stroke="#000000" stroke-linecap="round" stroke-width="0.6" x1="30.000000000000007" x2="51.961524227066306" y1="-51.96152422706631" y2="-30.00000000000003"/>
|
|
<line stroke="#000000" stroke-linecap="round" stroke-width="0.6" x1="51.961524227066306" x2="60" y1="-30.00000000000003" y2="0"/>
|
|
</g>
|
|
<g id="parcels">
|
|
<path d="M0,60 L-15,55.981 L-10.981,40.981 L15,55.981 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="0" x2="-15" y1="60" y2="55.981"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="-15" x2="-10.981" y1="55.981" y2="40.981"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-10.981" x2="15" y1="40.981" y2="55.981"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="15" x2="0" y1="55.981" y2="60"/>
|
|
<path d="M-0,-60 L15,-55.981 L10.981,-40.981 L-15,-55.981 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-0" x2="15" y1="-60" y2="-55.981"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="15" x2="10.981" y1="-55.981" y2="-40.981"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="10.981" x2="-15" y1="-40.981" y2="-55.981"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="-15" x2="-0" y1="-55.981" y2="-60"/>
|
|
<path d="M51.962,-30 L55.981,-15 L40.981,-10.981 L40.981,-40.981 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="51.962" x2="55.981" y1="-30" y2="-15"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="55.981" x2="40.981" y1="-15" y2="-10.981"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="40.981" x2="40.981" y1="-10.981" y2="-40.981"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="40.981" x2="51.962" y1="-40.981" y2="-30"/>
|
|
<path d="M30.43,-7.923 L60,0 L54.085,22.077 L24.515,14.154 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="30.43" x2="60" y1="-7.923" y2="0"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="60" x2="54.085" y1="0" y2="22.077"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="54.085" x2="24.515" y1="22.077" y2="14.154"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="24.515" x2="30.43" y1="14.154" y2="-7.923"/>
|
|
<path d="M27.209974,14.876093 L54.085,22.077 L51.962,30 L25.087,22.799 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="27.209975100978127" x2="54.085" y1="14.876092922727416" y2="22.077"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="54.085" x2="51.962" y1="22.077" y2="30"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="51.962" x2="25.087" y1="30" y2="22.799"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="25.087" x2="27.209975100978127" y1="22.799" y2="14.876092922727416"/>
|
|
<path d="M24.894293,12.738339 L24.515,14.154 L27.209974,14.876093 L25.087,22.799 L51.962,30 L38.665,43.297 L16.5,21.132 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="24.894292222912288" x2="24.515" y1="12.738339069275643" y2="14.154"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="24.515" x2="27.209975100978127" y1="14.154" y2="14.876092922727416"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="27.209975100978127" x2="25.087" y1="14.876092922727416" y2="22.799"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="25.087" x2="51.962" y1="22.799" y2="30"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="51.962" x2="38.665" y1="30" y2="43.297"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="38.665" x2="16.5" y1="43.297" y2="21.132"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="16.5" x2="24.894292222912288" y1="21.132" y2="12.738339069275643"/>
|
|
<path d="M15.039,19.671 L38.665,43.297 L30,51.962 L6.374,28.336 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="15.039" x2="38.665" y1="19.671" y2="43.297"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="38.665" x2="30" y1="43.297" y2="51.962"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="30" x2="6.374" y1="51.962" y2="28.336"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="6.374" x2="15.039" y1="28.336" y2="19.671"/>
|
|
<path d="M30,51.962 L15,55.981 L8.038085,30.000084 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="30" x2="15" y1="51.962" y2="55.981"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="15" x2="8.038084520711102" y1="55.981" y2="30.000084520711102"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="8.038084520711102" x2="30" y1="30.000084520711102" y2="51.962"/>
|
|
<path d="M-21.244,19.284 L-6.244,23.303 L-10.980811,40.98111 L-10.981,40.981 L-15,55.981 L-30,51.962 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="-21.244" x2="-6.244" y1="19.284" y2="23.303"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="-6.244" x2="-10.980811359920782" y1="23.303" y2="40.98110891040331"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="-10.980811359920782" x2="-10.981" y1="40.98110891040331" y2="40.981"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-10.981" x2="-15" y1="40.981" y2="55.981"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="-15" x2="-30" y1="55.981" y2="51.962"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-30" x2="-21.244" y1="51.962" y2="19.284"/>
|
|
<path d="M-19.28,17.169 L-15.672103,20.776897 L-21.244,19.284 L-30,51.962 L-42.036,39.926 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="-19.28" x2="-15.672103087150534" y1="17.169" y2="20.776896912849466"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="-15.672103087150534" x2="-21.244" y1="20.776896912849466" y2="19.284"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-21.244" x2="-30" y1="19.284" y2="51.962"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="-30" x2="-42.036" y1="51.962" y2="39.926"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-42.036" x2="-19.28" y1="39.926" y2="17.169"/>
|
|
<path d="M-27.92,5.958 L-17.994,15.884 L-19.2795,17.1695 L-19.28,17.169 L-42.036,39.926 L-51.962,30 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="-27.92" x2="-17.994" y1="5.958" y2="15.884"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="-17.994" x2="-19.279500000000002" y1="15.884" y2="17.1695"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="-19.279500000000002" x2="-19.28" y1="17.1695" y2="17.169"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-19.28" x2="-42.036" y1="17.169" y2="39.926"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="-42.036" x2="-51.962" y1="39.926" y2="30"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-51.962" x2="-27.92" y1="30" y2="5.958"/>
|
|
<path d="M-29.577,4.117 L-28.837816,6.8758163 L-51.962,30 L-56.933,11.447 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="-29.577" x2="-28.83781627274273" y1="4.117" y2="6.875816272742731"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-28.83781627274273" x2="-51.962" y1="6.875816272742731" y2="30"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="-51.962" x2="-56.933" y1="30" y2="11.447"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-56.933" x2="-29.577" y1="11.447" y2="4.117"/>
|
|
<path d="M-28.652,-8.4 L-25.585,3.047 L-56.933,11.447 L-60,0 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="-28.652" x2="-25.585" y1="-8.4" y2="3.047"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-25.585" x2="-56.933" y1="3.047" y2="11.447"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="-56.933" x2="-60" y1="11.447" y2="0"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-60" x2="-28.652" y1="0" y2="-8.4"/>
|
|
<path d="M-54.064,-22.155 L-22.563,-13.714 L-26.319391,0.30602226 L-28.652,-8.4 L-60,0 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-54.064" x2="-22.563" y1="-22.155" y2="-13.714"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="-22.563" x2="-26.319391431366597" y1="-13.714" y2="0.3060222644755677"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="-26.319391431366597" x2="-28.652" y1="0.3060222644755677" y2="-8.4"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-28.652" x2="-60" y1="-8.4" y2="0"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="-60" x2="-54.064" y1="0" y2="-22.155"/>
|
|
<path d="M-51.962,-30 L-23.542,-22.385 L-25.644,-14.54 L-54.064,-22.155 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-51.962" x2="-23.542" y1="-30" y2="-22.385"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="-23.542" x2="-25.644" y1="-22.385" y2="-14.54"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-25.644" x2="-54.064" y1="-14.54" y2="-22.155"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="-54.064" x2="-51.962" y1="-22.155" y2="-30"/>
|
|
<path d="M-30,-51.962 L-6.113,-28.075 L-12.017,-22.171 L-35.904,-46.058 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-30" x2="-6.113" y1="-51.962" y2="-28.075"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="-6.113" x2="-12.017" y1="-28.075" y2="-22.171"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-12.017" x2="-35.904" y1="-22.171" y2="-46.058"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="-35.904" x2="-30" y1="-46.058" y2="-51.962"/>
|
|
<path d="M-15,-55.981 L-8.038839,-30.00084 L-30,-51.962 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-15" x2="-8.038838936109254" y1="-55.981" y2="-30.000838936109254"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="-8.038838936109254" x2="-30" y1="-30.000838936109254" y2="-51.962"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="-30" x2="-15" y1="-51.962" y2="-55.981"/>
|
|
<path d="M15,-55.981 L30,-51.962 L22.309,-23.257 L7.309,-27.276 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="15" x2="30" y1="-55.981" y2="-51.962"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="30" x2="22.309" y1="-51.962" y2="-23.257"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="22.309" x2="7.309" y1="-23.257" y2="-27.276"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="7.309" x2="15" y1="-27.276" y2="-55.981"/>
|
|
<path d="M22.309,-23.257 L30,-51.962 L40.981,-40.981 L20.791,-20.791 L16.866385,-24.715258 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="22.309" x2="30" y1="-23.257" y2="-51.962"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="30" x2="40.981" y1="-51.962" y2="-40.981"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="40.981" x2="20.791" y1="-40.981" y2="-20.791"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="20.791" x2="16.866384481526474" y1="-20.791" y2="-24.715258117916342"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="16.866384481526474" x2="22.309" y1="-24.715258117916342" y2="-23.257"/>
|
|
<path d="M40.981,-10.98113 L40.981,-10.981 L55.981,-15 L60,0 L30.43,-7.923 L29.840496,-5.7227483 L29.272,-7.844 z" fill="#fff7c2" fill-opacity="0.3" stroke="none"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="40.981" x2="40.981" y1="-10.981129956194541" y2="-10.981"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="40.981" x2="55.981" y1="-10.981" y2="-15"/>
|
|
<line stroke="#1f5fb4" stroke-width="0.9" x1="55.981" x2="60" y1="-15" y2="0"/>
|
|
<line stroke="#6b6b6b" stroke-width="0.4" x1="60" x2="30.43" y1="0" y2="-7.923"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="30.43" x2="29.84049552403404" y1="-7.923" y2="-5.722748044649107"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="29.84049552403404" x2="29.272" y1="-5.722748044649107" y2="-7.844"/>
|
|
<line stroke="#bdbdbd" stroke-dasharray="1.6,1.2" stroke-width="0.4" x1="29.272" x2="40.981" y1="-7.844" y2="-10.981129956194541"/>
|
|
</g>
|
|
<g id="nodes">
|
|
<circle cx="-0.000000000000011021821192326178" cy="-60" fill="#000000" r="0.7"/>
|
|
<circle cx="30.000000000000007" cy="-51.96152422706631" fill="#000000" r="0.7"/>
|
|
<circle cx="51.961524227066306" cy="-30.00000000000003" fill="#000000" r="0.7"/>
|
|
<circle cx="0" cy="-200" fill="#000000" r="0.7"/>
|
|
<circle cx="60" cy="0" fill="#000000" r="0.7"/>
|
|
<circle cx="51.96152422706632" cy="29.999999999999996" fill="#000000" r="0.7"/>
|
|
<circle cx="30.000000000000007" cy="51.96152422706631" fill="#000000" r="0.7"/>
|
|
<circle cx="0.00000000000000367394039744206" cy="60" fill="#000000" r="0.7"/>
|
|
<circle cx="-29.99999999999999" cy="51.96152422706632" fill="#000000" r="0.7"/>
|
|
<circle cx="-51.96152422706632" cy="29.999999999999996" fill="#000000" r="0.7"/>
|
|
<circle cx="-60" cy="0.00000000000000734788079488412" fill="#000000" r="0.7"/>
|
|
<circle cx="-51.96152422706631" cy="-30.000000000000007" fill="#000000" r="0.7"/>
|
|
<circle cx="-30.00000000000003" cy="-51.961524227066306" fill="#000000" r="0.7"/>
|
|
</g>
|
|
</g>
|
|
</svg> |