lovarch-cli 0.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lovarch_cli/__init__.py +16 -0
- lovarch_cli/__main__.py +10 -0
- lovarch_cli/ai/__init__.py +21 -0
- lovarch_cli/ai/gateway.py +240 -0
- lovarch_cli/api.py +111 -0
- lovarch_cli/auth/__init__.py +32 -0
- lovarch_cli/auth/keyring_store.py +214 -0
- lovarch_cli/auth/local_server.py +165 -0
- lovarch_cli/auth/pkce.py +57 -0
- lovarch_cli/auth/session.py +189 -0
- lovarch_cli/cli.py +262 -0
- lovarch_cli/clients/__init__.py +33 -0
- lovarch_cli/clients/factory.py +54 -0
- lovarch_cli/clients/local_client.py +432 -0
- lovarch_cli/clients/lovarch_storage.py +174 -0
- lovarch_cli/clients/lovarch_supabase.py +295 -0
- lovarch_cli/clients/persistence.py +166 -0
- lovarch_cli/clients/storage.py +66 -0
- lovarch_cli/commands/__init__.py +10 -0
- lovarch_cli/commands/account.py +172 -0
- lovarch_cli/commands/audit.py +394 -0
- lovarch_cli/commands/config_cmd.py +80 -0
- lovarch_cli/commands/consolidate.py +217 -0
- lovarch_cli/commands/context_cmd.py +73 -0
- lovarch_cli/commands/dev.py +287 -0
- lovarch_cli/commands/do_cmd.py +120 -0
- lovarch_cli/commands/init.py +218 -0
- lovarch_cli/commands/jobs_cmd.py +95 -0
- lovarch_cli/commands/login.py +202 -0
- lovarch_cli/commands/mcp_cmd.py +26 -0
- lovarch_cli/commands/run.py +375 -0
- lovarch_cli/commands/signup.py +185 -0
- lovarch_cli/commands/status.py +243 -0
- lovarch_cli/commands/upgrade.py +108 -0
- lovarch_cli/commands/verifica_cmd.py +174 -0
- lovarch_cli/config.py +101 -0
- lovarch_cli/config_store.py +111 -0
- lovarch_cli/credits/__init__.py +35 -0
- lovarch_cli/credits/base.py +84 -0
- lovarch_cli/credits/factory.py +36 -0
- lovarch_cli/credits/local.py +34 -0
- lovarch_cli/credits/lovarch.py +56 -0
- lovarch_cli/i18n/__init__.py +27 -0
- lovarch_cli/i18n/loader.py +121 -0
- lovarch_cli/i18n/translations/en.json +168 -0
- lovarch_cli/i18n/translations/es.json +168 -0
- lovarch_cli/i18n/translations/it.json +168 -0
- lovarch_cli/i18n/translations/pt.json +168 -0
- lovarch_cli/mcp/__init__.py +9 -0
- lovarch_cli/mcp/server.py +199 -0
- lovarch_cli/mcp/tools.py +372 -0
- lovarch_cli/sample_downloader.py +255 -0
- lovarch_cli/squad/README.md +206 -0
- lovarch_cli/squad/agents/auditor-input.md +353 -0
- lovarch_cli/squad/agents/bim-engineer.md +404 -0
- lovarch_cli/squad/agents/briefing-architect.md +249 -0
- lovarch_cli/squad/agents/cad-engineer.md +278 -0
- lovarch_cli/squad/agents/capitolato-writer.md +256 -0
- lovarch_cli/squad/agents/computo-engineer.md +258 -0
- lovarch_cli/squad/agents/concept-designer.md +399 -0
- lovarch_cli/squad/agents/contratto-architect.md +243 -0
- lovarch_cli/squad/agents/deliverable-builder.md +253 -0
- lovarch_cli/squad/agents/energy-prelim.md +388 -0
- lovarch_cli/squad/agents/pratiche-it.md +251 -0
- lovarch_cli/squad/agents/progetto-chief.md +768 -0
- lovarch_cli/squad/agents/quality-dati.md +409 -0
- lovarch_cli/squad/agents/quality-misure.md +418 -0
- lovarch_cli/squad/agents/quality-normativa.md +417 -0
- lovarch_cli/squad/agents/quality-output.md +436 -0
- lovarch_cli/squad/agents/regolatorio-it.md +278 -0
- lovarch_cli/squad/checklists/handoff-quality-gate.md +232 -0
- lovarch_cli/squad/checklists/quality-dati-checklist.md +134 -0
- lovarch_cli/squad/checklists/quality-misure-checklist.md +139 -0
- lovarch_cli/squad/checklists/quality-normativa-checklist.md +121 -0
- lovarch_cli/squad/checklists/quality-output-checklist.md +116 -0
- lovarch_cli/squad/config.yaml +408 -0
- lovarch_cli/squad/data/CHANGELOG.md +272 -0
- lovarch_cli/squad/data/agents-prd.md +428 -0
- lovarch_cli/squad/data/architettura-progetto-rules.md +328 -0
- lovarch_cli/squad/data/handoff-card-template.md +231 -0
- lovarch_cli/squad/data/mocks/catasto-visura.json +72 -0
- lovarch_cli/squad/data/mocks/firma-envelope.json +43 -0
- lovarch_cli/squad/data/prezzario-lombardia-sample.json +312 -0
- lovarch_cli/squad/scripts/api_clients.py +206 -0
- lovarch_cli/squad/scripts/architect_profile.py +276 -0
- lovarch_cli/squad/scripts/deliverable_generators.py +844 -0
- lovarch_cli/squad/scripts/generate_attico_brera_dwg.py +369 -0
- lovarch_cli/squad/scripts/generate_chianti_dxf.py +368 -0
- lovarch_cli/squad/scripts/generate_chianti_images.py +223 -0
- lovarch_cli/squad/scripts/generate_real_sample_images.py +189 -0
- lovarch_cli/squad/scripts/generate_sample_assets.py +382 -0
- lovarch_cli/squad/scripts/lovarch_client.py +1046 -0
- lovarch_cli/squad/scripts/pipeline_runner.py +2095 -0
- lovarch_cli/squad/scripts/render_dxf_to_png.py +57 -0
- lovarch_cli/squad/scripts/run_palestra_demo.sh +277 -0
- lovarch_cli/squad/scripts/simulate_squad_execution.py +515 -0
- lovarch_cli/squad/scripts/validate-squad.py +383 -0
- lovarch_cli/squad/tasks/audit-input.md +146 -0
- lovarch_cli/squad/tasks/compute-metric.md +105 -0
- lovarch_cli/squad/tasks/consolidate-dossier.md +187 -0
- lovarch_cli/squad/tasks/generate-cad-plan.md +120 -0
- lovarch_cli/squad/tasks/generate-ifc-model.md +108 -0
- lovarch_cli/squad/tasks/write-capitolato.md +100 -0
- lovarch_cli/squad/templates/asseverazione-tecnica.md +126 -0
- lovarch_cli/squad/templates/capitolato-uni-11337.md +235 -0
- lovarch_cli/squad/templates/cila-comune-milano.md +177 -0
- lovarch_cli/squad/templates/contratto-cnappc.md +220 -0
- lovarch_cli/squad/workflows/dal-brief-al-cantiere.yaml +218 -0
- lovarch_cli/squad_loader.py +114 -0
- lovarch_cli/verify/__init__.py +15 -0
- lovarch_cli/verify/contratto.py +110 -0
- lovarch_cli/verify/dossier.py +97 -0
- lovarch_cli/verify/misure.py +83 -0
- lovarch_cli/verify/normativa.py +178 -0
- lovarch_cli/version.py +13 -0
- lovarch_cli/workflows/__init__.py +9 -0
- lovarch_cli/workflows/platform.py +212 -0
- lovarch_cli-0.2.1.dist-info/METADATA +232 -0
- lovarch_cli-0.2.1.dist-info/RECORD +122 -0
- lovarch_cli-0.2.1.dist-info/WHEEL +4 -0
- lovarch_cli-0.2.1.dist-info/entry_points.txt +3 -0
- lovarch_cli-0.2.1.dist-info/licenses/LICENSE +38 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Generate sample DWG for Attico Brera demo.
|
|
3
|
+
|
|
4
|
+
Creates a realistic 120 m² floor plan in DXF format with:
|
|
5
|
+
- Layer ISO standard (CAD-A-WALL, CAD-A-DIM, CAD-A-DOOR, CAD-A-WIND, CAD-A-TEXT)
|
|
6
|
+
- Walls (perimeter + internal)
|
|
7
|
+
- Doors and windows as blocks
|
|
8
|
+
- Dimensions
|
|
9
|
+
- Room labels
|
|
10
|
+
- A1 sheet with cartiglio CNAPPC
|
|
11
|
+
|
|
12
|
+
Output: stato-attuale.dxf
|
|
13
|
+
|
|
14
|
+
Usage:
|
|
15
|
+
python3 generate_attico_brera_dwg.py [output_path]
|
|
16
|
+
|
|
17
|
+
Default output: ./stato-attuale.dxf
|
|
18
|
+
"""
|
|
19
|
+
import sys
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
import ezdxf
|
|
24
|
+
from ezdxf.enums import TextEntityAlignment
|
|
25
|
+
except ImportError:
|
|
26
|
+
sys.stderr.write(
|
|
27
|
+
"ERROR: ezdxf not installed. Run: pip install ezdxf\n"
|
|
28
|
+
)
|
|
29
|
+
sys.exit(1)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# Layer specifications (UNI ISO standard)
|
|
33
|
+
LAYERS = [
|
|
34
|
+
("CAD-A-WALL", 7, "Continuous"), # 7 = white
|
|
35
|
+
("CAD-A-WALL-EXT", 1, "Continuous"), # 1 = red (perimeter)
|
|
36
|
+
("CAD-A-DOOR", 4, "Continuous"), # 4 = cyan
|
|
37
|
+
("CAD-A-WIND", 5, "Continuous"), # 5 = blue
|
|
38
|
+
("CAD-A-DIM", 3, "Continuous"), # 3 = green
|
|
39
|
+
("CAD-A-TEXT", 2, "Continuous"), # 2 = yellow
|
|
40
|
+
("CAD-A-SYMB", 6, "Continuous"), # 6 = magenta
|
|
41
|
+
("CAD-A-FURN", 8, "Continuous"), # 8 = grey
|
|
42
|
+
("CAD-A-CART", 7, "Continuous"), # cartiglio
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def setup_layers(doc):
|
|
47
|
+
"""Create all required layers."""
|
|
48
|
+
for name, color, linetype in LAYERS:
|
|
49
|
+
if name not in doc.layers:
|
|
50
|
+
doc.layers.add(name=name, color=color, linetype=linetype)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def setup_dim_style(doc):
|
|
54
|
+
"""Create UNI dimension style with mm precision."""
|
|
55
|
+
if "UNI_DIM" not in doc.dimstyles:
|
|
56
|
+
dim_style = doc.dimstyles.new("UNI_DIM")
|
|
57
|
+
dim_style.dxf.dimtxt = 25 # text height (mm in plot 1:50 = 2.5mm real)
|
|
58
|
+
dim_style.dxf.dimasz = 25 # arrow size
|
|
59
|
+
dim_style.dxf.dimexe = 12 # extension line beyond dim
|
|
60
|
+
dim_style.dxf.dimexo = 12 # extension line offset
|
|
61
|
+
dim_style.dxf.dimdec = 0 # 0 decimals (cm)
|
|
62
|
+
dim_style.dxf.dimlfac = 0.1 # scale factor: mm → cm display
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def add_wall(msp, p1, p2, *, layer="CAD-A-WALL", thickness=80):
|
|
66
|
+
"""
|
|
67
|
+
Add a wall as 2 parallel lines (thickness mm).
|
|
68
|
+
p1, p2 are wall axis (in mm).
|
|
69
|
+
Wall thickness perpendicular to axis.
|
|
70
|
+
"""
|
|
71
|
+
import math
|
|
72
|
+
dx = p2[0] - p1[0]
|
|
73
|
+
dy = p2[1] - p1[1]
|
|
74
|
+
length = math.sqrt(dx * dx + dy * dy)
|
|
75
|
+
if length == 0:
|
|
76
|
+
return
|
|
77
|
+
# perpendicular unit vector
|
|
78
|
+
nx = -dy / length
|
|
79
|
+
ny = dx / length
|
|
80
|
+
half = thickness / 2
|
|
81
|
+
|
|
82
|
+
p1a = (p1[0] + nx * half, p1[1] + ny * half)
|
|
83
|
+
p1b = (p1[0] - nx * half, p1[1] - ny * half)
|
|
84
|
+
p2a = (p2[0] + nx * half, p2[1] + ny * half)
|
|
85
|
+
p2b = (p2[0] - nx * half, p2[1] - ny * half)
|
|
86
|
+
|
|
87
|
+
# 4 lines forming a closed thick wall
|
|
88
|
+
msp.add_line(p1a, p2a, dxfattribs={"layer": layer})
|
|
89
|
+
msp.add_line(p1b, p2b, dxfattribs={"layer": layer})
|
|
90
|
+
msp.add_line(p1a, p1b, dxfattribs={"layer": layer})
|
|
91
|
+
msp.add_line(p2a, p2b, dxfattribs={"layer": layer})
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def add_door(msp, center, width=900, swing="right"):
|
|
95
|
+
"""Add a simple door symbol."""
|
|
96
|
+
half = width / 2
|
|
97
|
+
msp.add_line(
|
|
98
|
+
(center[0] - half, center[1]),
|
|
99
|
+
(center[0] + half, center[1]),
|
|
100
|
+
dxfattribs={"layer": "CAD-A-DOOR"},
|
|
101
|
+
)
|
|
102
|
+
# arc representing swing
|
|
103
|
+
msp.add_arc(
|
|
104
|
+
center=(center[0] - half, center[1]),
|
|
105
|
+
radius=width,
|
|
106
|
+
start_angle=0,
|
|
107
|
+
end_angle=90,
|
|
108
|
+
dxfattribs={"layer": "CAD-A-DOOR"},
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def add_window(msp, p1, p2):
|
|
113
|
+
"""Add a window symbol (double line)."""
|
|
114
|
+
import math
|
|
115
|
+
dx = p2[0] - p1[0]
|
|
116
|
+
dy = p2[1] - p1[1]
|
|
117
|
+
length = math.sqrt(dx * dx + dy * dy)
|
|
118
|
+
if length == 0:
|
|
119
|
+
return
|
|
120
|
+
nx = -dy / length
|
|
121
|
+
ny = dx / length
|
|
122
|
+
offset = 30 # mm
|
|
123
|
+
|
|
124
|
+
p1a = (p1[0] + nx * offset, p1[1] + ny * offset)
|
|
125
|
+
p1b = (p1[0] - nx * offset, p1[1] - ny * offset)
|
|
126
|
+
p2a = (p2[0] + nx * offset, p2[1] + ny * offset)
|
|
127
|
+
p2b = (p2[0] - nx * offset, p2[1] - ny * offset)
|
|
128
|
+
|
|
129
|
+
msp.add_line(p1a, p2a, dxfattribs={"layer": "CAD-A-WIND"})
|
|
130
|
+
msp.add_line(p1b, p2b, dxfattribs={"layer": "CAD-A-WIND"})
|
|
131
|
+
msp.add_line(p1a, p1b, dxfattribs={"layer": "CAD-A-WIND"})
|
|
132
|
+
msp.add_line(p2a, p2b, dxfattribs={"layer": "CAD-A-WIND"})
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def add_room_label(msp, center, name, area):
|
|
136
|
+
"""Add room label with name and area."""
|
|
137
|
+
msp.add_text(
|
|
138
|
+
name,
|
|
139
|
+
dxfattribs={"layer": "CAD-A-TEXT", "height": 200},
|
|
140
|
+
).set_placement(center, align=TextEntityAlignment.MIDDLE_CENTER)
|
|
141
|
+
msp.add_text(
|
|
142
|
+
f"{area:.1f} m²",
|
|
143
|
+
dxfattribs={"layer": "CAD-A-TEXT", "height": 150},
|
|
144
|
+
).set_placement(
|
|
145
|
+
(center[0], center[1] - 250),
|
|
146
|
+
align=TextEntityAlignment.MIDDLE_CENTER,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def add_dimension_h(msp, p1, p2, offset_y, text_override=None):
|
|
151
|
+
"""Add horizontal linear dimension."""
|
|
152
|
+
dim = msp.add_linear_dim(
|
|
153
|
+
base=(p1[0], p1[1] + offset_y),
|
|
154
|
+
p1=p1,
|
|
155
|
+
p2=p2,
|
|
156
|
+
dimstyle="UNI_DIM",
|
|
157
|
+
text=text_override,
|
|
158
|
+
)
|
|
159
|
+
dim.render()
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def add_cartiglio(msp, origin):
|
|
163
|
+
"""Add CNAPPC-style cartiglio (title block) at given origin."""
|
|
164
|
+
# Outer frame: 180 × 50 mm in plot scale
|
|
165
|
+
w, h = 18000, 5000 # in mm at scale 1:1
|
|
166
|
+
x0, y0 = origin
|
|
167
|
+
|
|
168
|
+
# Frame
|
|
169
|
+
msp.add_lwpolyline(
|
|
170
|
+
[
|
|
171
|
+
(x0, y0),
|
|
172
|
+
(x0 + w, y0),
|
|
173
|
+
(x0 + w, y0 + h),
|
|
174
|
+
(x0, y0 + h),
|
|
175
|
+
(x0, y0),
|
|
176
|
+
],
|
|
177
|
+
dxfattribs={"layer": "CAD-A-CART"},
|
|
178
|
+
close=True,
|
|
179
|
+
)
|
|
180
|
+
# Internal divisions
|
|
181
|
+
msp.add_line((x0 + 6000, y0), (x0 + 6000, y0 + h), dxfattribs={"layer": "CAD-A-CART"})
|
|
182
|
+
msp.add_line((x0 + 12000, y0), (x0 + 12000, y0 + h), dxfattribs={"layer": "CAD-A-CART"})
|
|
183
|
+
msp.add_line((x0, y0 + 2500), (x0 + 18000, y0 + 2500), dxfattribs={"layer": "CAD-A-CART"})
|
|
184
|
+
|
|
185
|
+
# Texts
|
|
186
|
+
fields = [
|
|
187
|
+
("Progetto:", x0 + 200, y0 + 4500, 200),
|
|
188
|
+
("Attico Brera · Ristrutturazione interna", x0 + 200, y0 + 4200, 250),
|
|
189
|
+
("Cliente: Marco Rossini & Giulia Bianchi", x0 + 200, y0 + 3700, 200),
|
|
190
|
+
("Indirizzo: Via Fiori Chiari 17, Milano", x0 + 200, y0 + 3400, 200),
|
|
191
|
+
("Architetto:", x0 + 6200, y0 + 4500, 200),
|
|
192
|
+
("Pablo Ruan · Ord. Arch. Milano", x0 + 6200, y0 + 4200, 200),
|
|
193
|
+
("Tavola:", x0 + 12200, y0 + 4500, 200),
|
|
194
|
+
("01 · Pianta Stato Attuale", x0 + 12200, y0 + 4200, 250),
|
|
195
|
+
("Scala 1:50 · Data 25/04/2026 · Rev. 0", x0 + 12200, y0 + 3700, 200),
|
|
196
|
+
("Formato A1 (UNI ISO 5457)", x0 + 200, y0 + 1500, 200),
|
|
197
|
+
("Fase: progetto definitivo", x0 + 6200, y0 + 1500, 200),
|
|
198
|
+
("File: stato-attuale.dxf", x0 + 12200, y0 + 1500, 200),
|
|
199
|
+
]
|
|
200
|
+
for txt, x, y, h_text in fields:
|
|
201
|
+
msp.add_text(
|
|
202
|
+
txt,
|
|
203
|
+
dxfattribs={"layer": "CAD-A-CART", "height": h_text},
|
|
204
|
+
).set_placement((x, y), align=TextEntityAlignment.LEFT)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def build_attico_brera(output_path: Path) -> dict:
|
|
208
|
+
"""
|
|
209
|
+
Build the Attico Brera 120 m² DWG.
|
|
210
|
+
|
|
211
|
+
Layout (origin at bottom-left, +X right, +Y up, mm):
|
|
212
|
+
- Total: 12000 × 10000 mm = 120 m²
|
|
213
|
+
- Walls 12cm (perimeter) and 8cm (internal partitions)
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
dict with summary (rooms, areas, etc.)
|
|
217
|
+
"""
|
|
218
|
+
doc = ezdxf.new(dxfversion="R2018", setup=True)
|
|
219
|
+
setup_layers(doc)
|
|
220
|
+
setup_dim_style(doc)
|
|
221
|
+
msp = doc.modelspace()
|
|
222
|
+
|
|
223
|
+
# ----------------------------------------------------------------------
|
|
224
|
+
# Perimeter walls (12 cm thick) · outer rectangle 12000 × 10000 mm
|
|
225
|
+
# ----------------------------------------------------------------------
|
|
226
|
+
P = 120 # perimeter wall thickness (mm)
|
|
227
|
+
add_wall(msp, (0, 0), (12000, 0), layer="CAD-A-WALL-EXT", thickness=P)
|
|
228
|
+
add_wall(msp, (12000, 0), (12000, 10000), layer="CAD-A-WALL-EXT", thickness=P)
|
|
229
|
+
add_wall(msp, (12000, 10000), (0, 10000), layer="CAD-A-WALL-EXT", thickness=P)
|
|
230
|
+
add_wall(msp, (0, 10000), (0, 0), layer="CAD-A-WALL-EXT", thickness=P)
|
|
231
|
+
|
|
232
|
+
# ----------------------------------------------------------------------
|
|
233
|
+
# Internal partitions (8 cm)
|
|
234
|
+
# Layout (state attuale, before redesign):
|
|
235
|
+
# - Ingresso (left bottom): 0-2500, 0-3000
|
|
236
|
+
# - Cucina (left top): 0-3500, 6000-10000
|
|
237
|
+
# - Soggiorno (center): 2500-7500, 0-6000
|
|
238
|
+
# - Camera 1: 7500-12000, 0-4000
|
|
239
|
+
# - Camera 2: 0-4000, 3000-6000
|
|
240
|
+
# - Camera 3: 7500-12000, 4000-7000
|
|
241
|
+
# - Bagno: 7500-10000, 7000-10000
|
|
242
|
+
# - Ripostiglio: 10000-12000, 7000-10000
|
|
243
|
+
# ----------------------------------------------------------------------
|
|
244
|
+
T = 80 # internal wall thickness
|
|
245
|
+
|
|
246
|
+
# Ingresso / Soggiorno divider
|
|
247
|
+
add_wall(msp, (2500, 0), (2500, 3000), thickness=T)
|
|
248
|
+
# Ingresso / Camera 2 divider
|
|
249
|
+
add_wall(msp, (0, 3000), (4000, 3000), thickness=T)
|
|
250
|
+
# Camera 2 / Cucina divider
|
|
251
|
+
add_wall(msp, (0, 6000), (3500, 6000), thickness=T)
|
|
252
|
+
add_wall(msp, (3500, 6000), (3500, 10000), thickness=T)
|
|
253
|
+
# Camera 2 / Soggiorno
|
|
254
|
+
add_wall(msp, (4000, 3000), (4000, 6000), thickness=T)
|
|
255
|
+
# Soggiorno / Camera 1 divider
|
|
256
|
+
add_wall(msp, (7500, 0), (7500, 4000), thickness=T)
|
|
257
|
+
add_wall(msp, (7500, 4000), (12000, 4000), thickness=T)
|
|
258
|
+
# Camera 3 sopra
|
|
259
|
+
add_wall(msp, (7500, 7000), (12000, 7000), thickness=T)
|
|
260
|
+
add_wall(msp, (7500, 4000), (7500, 7000), thickness=T)
|
|
261
|
+
# Bagno / Ripostiglio
|
|
262
|
+
add_wall(msp, (10000, 7000), (10000, 10000), thickness=T)
|
|
263
|
+
# Soggiorno / cucina (parete tramezzo anni 80)
|
|
264
|
+
add_wall(msp, (3500, 6000), (7500, 6000), thickness=T)
|
|
265
|
+
|
|
266
|
+
# ----------------------------------------------------------------------
|
|
267
|
+
# Doors (centroid + width)
|
|
268
|
+
# ----------------------------------------------------------------------
|
|
269
|
+
add_door(msp, (1250, 3000), width=800) # ingresso → camera 2
|
|
270
|
+
add_door(msp, (2500, 1500), width=900) # ingresso → soggiorno
|
|
271
|
+
add_door(msp, (5500, 6000), width=800) # soggiorno → cucina
|
|
272
|
+
add_door(msp, (7500, 2000), width=800) # soggiorno → camera 1
|
|
273
|
+
add_door(msp, (7500, 5500), width=800) # corridoio → camera 3
|
|
274
|
+
add_door(msp, (8750, 7000), width=800) # corridoio → bagno
|
|
275
|
+
add_door(msp, (10500, 7000), width=700) # corridoio → ripostiglio
|
|
276
|
+
|
|
277
|
+
# ----------------------------------------------------------------------
|
|
278
|
+
# Windows (perimeter)
|
|
279
|
+
# ----------------------------------------------------------------------
|
|
280
|
+
# Cucina (north)
|
|
281
|
+
add_window(msp, (1000, 10000), (2500, 10000))
|
|
282
|
+
# Cucina (north, second)
|
|
283
|
+
add_window(msp, (3000, 10000), (3500, 10000))
|
|
284
|
+
# Bagno (north)
|
|
285
|
+
add_window(msp, (8500, 10000), (9500, 10000))
|
|
286
|
+
# Camera 3 (east)
|
|
287
|
+
add_window(msp, (12000, 5000), (12000, 6500))
|
|
288
|
+
# Camera 1 (east)
|
|
289
|
+
add_window(msp, (12000, 1000), (12000, 3000))
|
|
290
|
+
# Soggiorno (south, terrace door)
|
|
291
|
+
add_window(msp, (3500, 0), (6500, 0))
|
|
292
|
+
# Camera 2 (west)
|
|
293
|
+
add_window(msp, (0, 4000), (0, 5500))
|
|
294
|
+
# Ingresso (south)
|
|
295
|
+
add_window(msp, (500, 0), (1500, 0))
|
|
296
|
+
|
|
297
|
+
# ----------------------------------------------------------------------
|
|
298
|
+
# Room labels with areas
|
|
299
|
+
# ----------------------------------------------------------------------
|
|
300
|
+
rooms = [
|
|
301
|
+
# (name, center, area_m2)
|
|
302
|
+
("INGRESSO", (1250, 1500), 7.5),
|
|
303
|
+
("CUCINA", (1750, 8000), 14.0),
|
|
304
|
+
("SOGGIORNO", (5000, 3000), 30.0),
|
|
305
|
+
("CAMERA 2", (2000, 4500), 12.0),
|
|
306
|
+
("CAMERA 1", (9750, 2000), 18.0),
|
|
307
|
+
("CAMERA 3", (9750, 5500), 13.5),
|
|
308
|
+
("BAGNO", (8750, 8500), 7.5),
|
|
309
|
+
("RIPOSTIGLIO", (11000, 8500), 6.0),
|
|
310
|
+
]
|
|
311
|
+
for name, center, area in rooms:
|
|
312
|
+
add_room_label(msp, center, name, area)
|
|
313
|
+
|
|
314
|
+
# ----------------------------------------------------------------------
|
|
315
|
+
# Main dimensions (perimeter)
|
|
316
|
+
# ----------------------------------------------------------------------
|
|
317
|
+
add_dimension_h(msp, (0, 0), (12000, 0), -800, text_override="1200")
|
|
318
|
+
add_dimension_h(msp, (0, 10000), (12000, 10000), 800, text_override="1200")
|
|
319
|
+
|
|
320
|
+
# vertical dim left
|
|
321
|
+
dim_v = msp.add_linear_dim(
|
|
322
|
+
base=(-800, 0),
|
|
323
|
+
p1=(0, 0),
|
|
324
|
+
p2=(0, 10000),
|
|
325
|
+
angle=90,
|
|
326
|
+
dimstyle="UNI_DIM",
|
|
327
|
+
text="1000",
|
|
328
|
+
)
|
|
329
|
+
dim_v.render()
|
|
330
|
+
|
|
331
|
+
# ----------------------------------------------------------------------
|
|
332
|
+
# Cartiglio (title block)
|
|
333
|
+
# ----------------------------------------------------------------------
|
|
334
|
+
add_cartiglio(msp, (-1000, -8000))
|
|
335
|
+
|
|
336
|
+
# ----------------------------------------------------------------------
|
|
337
|
+
# Save
|
|
338
|
+
# ----------------------------------------------------------------------
|
|
339
|
+
output_path = Path(output_path)
|
|
340
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
341
|
+
doc.saveas(str(output_path))
|
|
342
|
+
|
|
343
|
+
# Summary
|
|
344
|
+
total_lordo = 12000 * 10000 / 1_000_000 # m²
|
|
345
|
+
total_utile = sum(area for _, _, area in rooms)
|
|
346
|
+
return {
|
|
347
|
+
"output_path": str(output_path),
|
|
348
|
+
"total_lordo_m2": total_lordo,
|
|
349
|
+
"total_utile_m2": total_utile,
|
|
350
|
+
"muratura_m2": total_lordo - total_utile,
|
|
351
|
+
"rooms_count": len(rooms),
|
|
352
|
+
"rooms": [
|
|
353
|
+
{"name": n, "area_m2": a, "center_mm": c}
|
|
354
|
+
for n, c, a in rooms
|
|
355
|
+
],
|
|
356
|
+
"layers": [name for name, _, _ in LAYERS],
|
|
357
|
+
"dxf_version": "R2018",
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def main():
|
|
362
|
+
output = sys.argv[1] if len(sys.argv) > 1 else "stato-attuale.dxf"
|
|
363
|
+
summary = build_attico_brera(Path(output))
|
|
364
|
+
import json
|
|
365
|
+
print(json.dumps(summary, indent=2, ensure_ascii=False))
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
if __name__ == "__main__":
|
|
369
|
+
main()
|