Preserve homestead context and garden-centred Blender design
This commit is contained in:
64
source/samford-retreat-garage/create_site_plan.py
Normal file
64
source/samford-retreat-garage/create_site_plan.py
Normal file
@@ -0,0 +1,64 @@
|
||||
from pathlib import Path
|
||||
from html import escape
|
||||
import json
|
||||
O=Path(__file__).parent
|
||||
p=['<svg xmlns="http://www.w3.org/2000/svg" width="1400" height="1120" viewBox="0 0 1400 1120"><rect width="1400" height="1120" fill="#f1eee5"/><style>text{font-family:Arial,sans-serif;fill:#263a34}</style><text x="60" y="60" font-size="32" font-weight="600">A home for movement, connection and quiet.</text><text x="60" y="95" font-size="17">SAMFORD VALLEY / Updated concept plan · 10 September 2026 · Version 003</text>']
|
||||
def pt(x,y):return (630+13*x,470-13*y)
|
||||
def label(x,y,lines,size=12):
|
||||
X,Y=pt(x,y)
|
||||
for i,t in enumerate(lines):p.append(f'<text x="{X}" y="{Y+i*(size+3)}" text-anchor="middle" font-size="{size}">{escape(t)}</text>')
|
||||
def rect(cx,cy,w,d,fill,stroke='#526154',dash=''):
|
||||
X,Y=pt(cx-w/2,cy+d/2);p.append(f'<rect x="{X}" y="{Y}" width="{w*13}" height="{d*13}" fill="{fill}" stroke="{stroke}" stroke-width="2" {dash}/>')
|
||||
def line(points,color,width):
|
||||
pts=' '.join(f'{pt(x,y)[0]},{pt(x,y)[1]}' for x,y in points);p.append(f'<polyline points="{pts}" fill="none" stroke="{color}" stroke-width="{width}" stroke-linejoin="round"/>')
|
||||
layout=json.loads((O/'daily-life-layout.json').read_text())
|
||||
line(layout['walking_loop'],'#adc49a',14)
|
||||
line([(14,1),(13,4),(13,7),(6,7)],'#adc49a',14)
|
||||
line([(-1,24),(-7,21),(-14,18)],'#adc49a',14)
|
||||
label(9,27.4,['SHADED WALKING LOOP'],12)
|
||||
line([(36,-40),(28,-33),(22,-27),(8,-26),(5,-22),(5,-13),(1,-12),(-3,-12)],'#c9bca1',52)
|
||||
rect(-1,-12.5,12,6,'#c9bca1',stroke='#c9bca1')
|
||||
line([(-3,-10),(-2,-6),(-5.5,-4),(-6.5,-2.8)],'#d5cdbb',12)
|
||||
line([(-3,5.4),(-3,9),(-11,9)],'#b5a88c',16)
|
||||
rect(0,0,12,6,'#ddc8a9');label(1,.7,['SHARED HOME','Kitchen · dining'],10)
|
||||
rect(0,4.2,12,2.4,'#c8d0b8');label(0,4.3,['VERANDA'],11)
|
||||
rect(-7.75,-1.8,3.5,1.2,'#c7bfae');label(-7.8,1.5,['Short link'],10)
|
||||
rect(-11.8,-4.9,8,5,'#ddc8a9');label(-11.8,-4.5,['PARENTS','Bedroom + bath'],11)
|
||||
rect(-11,12,4.5,4.8,'#c9c1a5');label(-11,12.4,['QUIET','ROOM'],11)
|
||||
X,Y=pt(-11,12);p.append(f'<circle cx="{X}" cy="{Y+24}" r="5" fill="#626257"/>')
|
||||
for i,(x,y) in enumerate([(-3,17),(7,15)]):
|
||||
rect(x,y,4.5,4.8,'#e6e8de',stroke='#98a394',dash='stroke-dasharray="5 5"');label(x,y+.6,['FUTURE',f'SPACE {i+1}'],11)
|
||||
label(2,21.4,['Faint outlines only / build when needed'],12)
|
||||
X,Y=pt(-23,2);p.append(f'<ellipse cx="{X}" cy="{Y}" rx="29" ry="25" fill="#bc9d75" stroke="#526154" stroke-width="2"/>');label(-23,2,['SAUNA'],10)
|
||||
rect(-27,4.6,1.3,1.3,'#b6c4c5');label(-27,7.5,['Outdoor shower'],11)
|
||||
for x in [-23.95,-26.25]:
|
||||
X,Y=pt(x,-8);p.append(f'<circle cx="{X}" cy="{Y}" r="13" fill="#6b7f61"/>')
|
||||
label(-25,-10.5,['Rainwater tanks'],11)
|
||||
rect(-3,-19,8,7,'#bcb9ac');label(-3,-18.6,['GARAGE','8 × 7 m'],12)
|
||||
rect(-4.7,-19.1,1.9,4.35,'#788c83');rect(-.47,-21.5,2.5,.76,'#ab9673')
|
||||
label(-3,-24,['One car · workbench · bike racks'],12)
|
||||
label(20,-25,['4 m gravel access road'],13)
|
||||
rect(24.2,-7.5,4.3,5,'#c3d6c1');label(24.2,-7.4,['GREENHOUSE'],9)
|
||||
for x in [23.8,27.5]:
|
||||
for y in [-1.7,1.5,4.7]:rect(x,y,2.3,1.3,'#b29b73')
|
||||
label(25.5,7.5,['FOOD GARDEN'],12)
|
||||
rect(13.2,-17.7,7.3,5.2,'#71848b');label(13.2,-17.2,['GROUND SOLAR'],10)
|
||||
label(34,-42,['Site approach'],12)
|
||||
rect(*layout['training'],'#b9c8ad');label(-12.2,-16.8,['COVERED','TRAINING','4.8 × 5.4 m'],10)
|
||||
line([(-8.65,-17),(-8.4,-15),(-6.4,-13.4)],'#d5cdbb',12)
|
||||
label(-15.8,-23.2,['Bar · rings · weights','Bench · movable mats'],11)
|
||||
rect(*layout['outdoor_table'],'#d9c19b');rect(10,3.5,3.2,1.03,'#ab8962')
|
||||
rect(10,4.48,2.95,.43,'#bda078');rect(10,2.52,2.95,.43,'#bda078')
|
||||
rect(6.5,4.2,1,1.5,'#c8d0b8');label(10,9,['OUTDOOR TABLE','10 places + tea counter'],11)
|
||||
rect(*layout['table_tennis'],'#ced8c4');rect(11,-8.5,1.525,2.74,'#608570')
|
||||
label(11,-5.9,['TABLE TENNIS'],10);label(11,-12.8,['Folding table / level deck'],10)
|
||||
line([(7.1,-7),(7,-4),(6.4,1.3),(7.1,3.5)],'#d5cdbb',12)
|
||||
rect(*layout['future_basketball'],'#eceee4',stroke='#81947c',dash='stroke-dasharray="7 7"')
|
||||
label(13,-35,['FUTURE','BASKETBALL','10 × 10 m reserve'],11)
|
||||
label(13,-43,['Unbuilt / separate from driveway'],11)
|
||||
rect(30,10.9,1.8,.45,'#a58a66');label(32,14,['QUIET BENCH'],11)
|
||||
rect(29.8,1.5,.78,2.05,'#a58a66');label(35,2.4,['HARVEST','BENCH'],11)
|
||||
label(4,-4.3,['Breakfast · pantry · freezer'],10)
|
||||
rect(-3.8,.1,2.2,.95,'#f4f1e9')
|
||||
p.extend(['<path d="M1250 220V153m0 0l-9 18m9-18l9 18" fill="none" stroke="#263a34" stroke-width="3"/><text x="1250" y="140" text-anchor="middle" font-size="17">N</text>','<line x1="70" y1="970" x2="200" y2="970" stroke="#263a34" stroke-width="4"/><text x="70" y="999" font-size="13">10 metres</text>','<line x1="60" y1="1040" x2="1340" y2="1040" stroke="#bdc3b6"/><text x="60" y="1070" font-size="15">The Blender presentation fades one facade of each building so you can see inside. Walls remain in the model.</text>','<text x="60" y="1096" font-size="13">Concept layout only. The road approach is illustrative; no surveyed property boundary or approved access is implied.</text></svg>'])
|
||||
(O/'retreat-garage-plan.svg').write_text(''.join(p))
|
||||
Reference in New Issue
Block a user