58 lines
4.7 KiB
Python
58 lines
4.7 KiB
Python
from pathlib import Path
|
|
import json,html
|
|
O=Path(__file__).parent;d=json.loads((O/('container-water-layout.json' if (O/'container-water-layout.json').exists() else 'garden-flow-layout.json')).read_text());p=[]
|
|
p.append('<svg xmlns="http://www.w3.org/2000/svg" width="1400" height="1180" viewBox="0 0 1400 1180"><rect width="1400" height="1180" fill="#f3f0e7"/><style>text{font-family:Arial,sans-serif;fill:#30433b}.sub{fill:#68756b}</style><text x="60" y="58" font-size="31" font-weight="600">A home held together by its garden.</text><text x="60" y="91" font-size="16" class="sub">SAMFORD VALLEY / Aligned pavilions, soft garden curves and room to grow · Concept 004</text>')
|
|
def pt(x,y):return (600+x*13,500-y*13)
|
|
def line(pts,color,w,dash=''):
|
|
q=' '.join(f'{pt(x,y)[0]:.1f},{pt(x,y)[1]:.1f}' for x,y in pts);p.append(f'<polyline points="{q}" fill="none" stroke="{color}" stroke-width="{w}" stroke-linejoin="round" stroke-linecap="round" {dash}/>')
|
|
def rect(cx,cy,w,h,fill='#d9c5a5',dash=''):
|
|
x,y=pt(cx-w/2,cy+h/2);p.append(f'<rect x="{x}" y="{y}" width="{w*13}" height="{h*13}" fill="{fill}" stroke="#657666" stroke-width="1.5" {dash}/>')
|
|
def label(x,y,lines,size=11):
|
|
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}">{html.escape(t)}</text>')
|
|
def ellipse(cx,cy,rx,ry,fill):
|
|
x,y=pt(cx,cy);p.append(f'<ellipse cx="{x}" cy="{y}" rx="{rx*13}" ry="{ry*13}" fill="{fill}"/>')
|
|
line([(0,-23),(0,28)],'#c1cbbc',1,'stroke-dasharray="4 6"')
|
|
ellipse(0,13.2,7.8,4.6,'#c7d4b5')
|
|
for path in d['paths']:
|
|
color='#c9bda6' if 'VEHICLE' in path['name'] else ('#b59b75' if path['kind']=='roofed walk' else '#d9d2bf')
|
|
line(path['points'],color,path['width']*13)
|
|
rect(2,-12.5,12,6,'#c9bda6')
|
|
for bed in d['beds']:
|
|
x,y=bed['center'];rx,ry=bed['radii'];ellipse(x,y,rx,ry,'#8fa981')
|
|
for xx in [-.5,0,.5]:ellipse(x+xx*rx,y,.12,.12,'#d5b6b5')
|
|
rect(*d['main']);rect(0,4.2,12,2.4,'#c5cfb6');label(0,4.4,['VERANDA'],11)
|
|
rect(-3.8,.1,2.2,.95,'#f5f2e9');label(1,1,['MAIN HOUSE','Kitchen · dining','Living / reading'],10)
|
|
rect(*d['parents']);label(-11.8,-4.4,['PARENTS','Bedroom + bath'],11)
|
|
rect(-7.75,-1.8,3.5,1.2,'#c8bba5')
|
|
rect(*d['meditation']);label(-11.8,12.5,['MEDITATION','ROOM'],10)
|
|
for idx,shape in enumerate(d['future']):
|
|
rect(*shape,'#e7ecdf','stroke-dasharray="5 5"');label(shape[0],shape[1]+.6,['FUTURE',f'PAVILION {idx+1}'],10)
|
|
label(0,13.5,['SHARED','GARDEN COURT'],11)
|
|
label(0,28,['ONE CENTRAL AXIS'],11)
|
|
label(-16.7,18.6,['Curved covered','timber breezeway'],11)
|
|
line([(-16.7,17),(-17,8.5),(-8.3,7.2)],'#8b9785',1)
|
|
rect(*d['outdoor_table'],'#d9c49f');rect(10,3.5,3.2,1.03,'#a48663');label(10,9,['TABLE FOR TEN','Tea + matcha'],10)
|
|
rect(*d['garage'],'#c7c2b3');rect(-1.7,-19.1,1.9,4.35,'#9da99c');label(1.5,-18.5,['GARAGE','Workshop','Bikes'],10)
|
|
rect(*d['training'],'#c1ceb1');label(-9.4,-17.9,['TRAINING','Bar + rings','Weights + mats'],10)
|
|
rect(*d['solar'],'#849a9d');label(9.4,-18.7,['GROUND SOLAR'],9)
|
|
label(0,-25,['Aligned garage, training and energy zone'],11)
|
|
x,y=d['sauna'];ellipse(x,y,2.2,2.0,'#ba9b75');label(x,y+.15,['SAUNA'],10)
|
|
rect(-27,6.8,1.3,1.3,'#b0c5c1');label(-29,10,['Outdoor shower'],10)
|
|
if 'water_container' in d:
|
|
rect(*d['water_container'][:4],'#6d8563');label(-25,-13.8,['CONTAINER WATER','2 enclosed tanks'],10)
|
|
else:
|
|
for x in [-23.95,-26.25]:ellipse(x,-8,1,1,'#6d8563')
|
|
label(-25,-10.8,['Rainwater tanks'],10)
|
|
rect(24.2,-7.5,4.3,5,'#c3d7c2');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,'#ad9573')
|
|
label(25.5,8.5,['FOOD GARDEN'],11)
|
|
rect(29.8,1.5,.78,2.05,'#a78e6b');label(33.5,1.5,['Harvest bench'],10)
|
|
rect(30,10.9,1.8,.45,'#a78e6b');label(31.5,16,['Quiet bench'],10)
|
|
label(12,-7,['FLOWER','GARDEN'],10)
|
|
rect(*d['future_basketball'],'#edf0e6','stroke-dasharray="6 6"');label(13,-35,['FUTURE','BASKETBALL','Unbuilt reserve'],11)
|
|
label(27,-29,['4 m gravel access'],11)
|
|
p.extend(['<path d="M1250 220V153m0 0l-9 18m9-18l9 18" fill="none" stroke="#30433b" stroke-width="3"/><text x="1250" y="140" text-anchor="middle" font-size="17">N</text>','<line x1="65" y1="1030" x2="195" y2="1030" stroke="#30433b" stroke-width="4"/><text x="65" y="1060" font-size="13">10 metres</text>','<line x1="60" y1="1090" x2="1340" y2="1090" stroke="#c5cebd"/><text x="60" y="1120" font-size="14">13 planted garden beds · Smooth pedestrian routes · Future pavilions remain shadows · Table-tennis deck removed</text>','<text x="60" y="1147" font-size="13" class="sub">Concept only: illustrative terrain, no surveyed boundary. Plant forms and structural connections require site-specific design development.</text></svg>'])
|
|
(O/('container-water-plan.svg' if d['version']==5 else 'garden-flow-plan.svg')).write_text(''.join(p).replace('Concept 004','Concept 005' if d['version']==5 else 'Concept 004'))
|