python-materialsdb 0.3.1__py3-none-any.whl → 0.3.2__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.
@@ -5,7 +5,7 @@ MaterialBuilder would create (one entry per IfcMaterial); the Bonsai add-on
5
5
  maps the payload onto its open file without importing this library."""
6
6
 
7
7
  from materialsdb import config, utils
8
- from materialsdb.ifc.material_builder import PSETS, get_value
8
+ from materialsdb.ifc.material_builder import PSETS, get_value, style_for
9
9
 
10
10
 
11
11
  def _resolved_psets(layer, country) -> dict:
@@ -50,6 +50,10 @@ def build_add_materials_payload(store_, items, country=None, lang=None):
50
50
  description = str(utils.get_material_description(material, lang))
51
51
  category = str(getattr(material.information, "group", "") or "")
52
52
  color = getattr(material.information, "color", None)
53
+ color = int(color) if color else None
54
+ # Resolve the surface style server-side: the add-on runs in Blender's
55
+ # interpreter without access to the materialsdb colour scheme.
56
+ style_name, style_rgb = style_for(color, category)
53
57
  entries = []
54
58
  for layer in utils.get_material_layers(material):
55
59
  if wanted is not None and str(layer.id) not in wanted:
@@ -63,7 +67,9 @@ def build_add_materials_payload(store_, items, country=None, lang=None):
63
67
  "name": name,
64
68
  "description": description,
65
69
  "category": category,
66
- "color": int(color) if color else None,
70
+ "color": color,
71
+ "style_name": style_name,
72
+ "style_color": [round(component, 6) for component in style_rgb],
67
73
  "identity": {
68
74
  "material_id": material_id,
69
75
  "company_id": str(summary.company_id or ""),
@@ -120,6 +126,9 @@ def build_add_construction_payload(store_, body, country=None, lang=None):
120
126
  problems.append(f"unknown material id: {layer.material_id}")
121
127
  continue
122
128
  color = getattr(material.information, "color", None)
129
+ color = int(color) if color else None
130
+ category = str(getattr(material.information, "group", "") or "")
131
+ style_name, style_rgb = style_for(color, category)
123
132
  layers.append(
124
133
  {
125
134
  "material_id": layer.material_id,
@@ -128,8 +137,10 @@ def build_add_construction_payload(store_, body, country=None, lang=None):
128
137
  "source_id": layer.material_id,
129
138
  "name": str(utils.get_material_name(material, lang)),
130
139
  "description": str(utils.get_material_description(material, lang)),
131
- "category": str(getattr(material.information, "group", "") or ""),
132
- "color": int(color) if color else None,
140
+ "category": category,
141
+ "color": color,
142
+ "style_name": style_name,
143
+ "style_color": [round(component, 6) for component in style_rgb],
133
144
  "identity": {
134
145
  "material_id": layer.material_id,
135
146
  "company_id": str(summary.company_id or ""),
@@ -2,12 +2,21 @@
2
2
 
3
3
  import json
4
4
  from pathlib import Path
5
+ from typing import TypedDict
5
6
 
6
7
  from materialsdb import config, utils
7
8
 
8
9
  MATERIALSDB_PSET = "materialsdb"
9
10
 
10
- CATEGORIES = {
11
+
12
+ class CategoryStyle(TypedDict):
13
+ """One palette entry. `hatch` is reserved for future pattern support."""
14
+
15
+ hatch: str
16
+ color: tuple[int, int, int]
17
+
18
+
19
+ CATEGORIES: dict[str, CategoryStyle] = {
11
20
  "Others": {"hatch": "", "color": (255, 255, 255)},
12
21
  "Water_Proof": {"hatch": "", "color": (255, 255, 255)},
13
22
  "Vapour_Proof": {"hatch": "", "color": (0, 0, 0)},
@@ -27,6 +36,29 @@ CATEGORIES = {
27
36
  "Soil": {"hatch": "", "color": (142, 84, 52)},
28
37
  }
29
38
 
39
+ # Named colour schemes: a category -> palette. Only the default ships today;
40
+ # more schemes (and a GUI selector) are planned.
41
+ SCHEMES: dict[str, dict[str, CategoryStyle]] = {"Lesosai": CATEGORIES}
42
+ DEFAULT_SCHEME = "Lesosai"
43
+
44
+
45
+ def _rgb_int_components(color: int) -> tuple[float, float, float]:
46
+ """Decimal 0xRRGGBB -> normalised (r, g, b) in 0..1 (IfcColourRgb units)."""
47
+ return (((color >> 16) & 255) / 255, ((color >> 8) & 255) / 255, (color & 255) / 255)
48
+
49
+
50
+ def style_for(color, category, scheme=None):
51
+ """Resolve a material's (IfcSurfaceStyle.Name, (r, g, b) in 0..1).
52
+
53
+ The producer colour wins when present; otherwise the category colour from
54
+ the scheme (default 'Lesosai' = CATEGORIES). Unknown categories fall back
55
+ to 'Others'."""
56
+ if color:
57
+ return f"color {int(color)}", _rgb_int_components(int(color))
58
+ palette = SCHEMES.get(scheme or DEFAULT_SCHEME, CATEGORIES)
59
+ category = category if category in palette else "Others"
60
+ return f"category {category}", tuple(component / 255 for component in palette[category]["color"])
61
+
30
62
 
31
63
  def clean_psets(psets):
32
64
  new_dict = {}
@@ -71,6 +103,7 @@ class MaterialBuilder:
71
103
  name = utils.get_material_name(material, self.lang)
72
104
  description = utils.get_material_description(material, self.lang)
73
105
  category = str(material.information.group or "")
106
+ color = material.information.color
74
107
  if not with_layers:
75
108
  # reuse an already-present material instead of duplicating it;
76
109
  # its identity pset is already in place
@@ -79,15 +112,9 @@ class MaterialBuilder:
79
112
  return [existing]
80
113
  ifc_material = self.file.createIfcMaterial(name, str(description), str(category))
81
114
  self._create_identity_pset(ifc_material, material, company_id, company, verxml)
115
+ self._add_style_chain(color, category)
82
116
  return [ifc_material]
83
- color = material.information.color
84
- surface_style = self.get_surface_style(color, category)
85
- styled_item = self.file.createIfcStyledItem(Styles=[surface_style])
86
- self.file.createIfcStyledRepresentation(
87
- ContextOfItems=self._get_context(),
88
- RepresentationIdentifier="Body",
89
- Items=[styled_item],
90
- )
117
+ self._add_style_chain(color, category)
91
118
  created = []
92
119
  wanted = {str(g) for g in layer_ids} if layer_ids is not None else None
93
120
  for layer in utils.get_material_layers(material):
@@ -191,29 +218,32 @@ class MaterialBuilder:
191
218
  Material=ifc_material,
192
219
  )
193
220
 
194
- def get_surface_style(self, color, category):
195
- if color:
196
- name = f"color {color}"
197
- else:
198
- if not category or category not in CATEGORIES:
199
- category = "Others"
200
- name = f"category {category}"
221
+ def _add_style_chain(self, color, category, scheme=None):
222
+ """Create the floating styled chain MaterialBuilder uses for a
223
+ material's colour (shared style + one styled item per build)."""
224
+ surface_style = self.get_surface_style(color, category, scheme=scheme)
225
+ styled_item = self.file.createIfcStyledItem(Styles=[surface_style])
226
+ self.file.createIfcStyledRepresentation(
227
+ ContextOfItems=self._get_context(),
228
+ RepresentationIdentifier="Body",
229
+ Items=[styled_item],
230
+ )
231
+
232
+ def get_surface_style(self, color, category, scheme=None):
233
+ name, rgb = style_for(color, category, scheme=scheme)
201
234
  if name in self._styles and self._styles[name] in self.file:
202
235
  return self._styles[name]
203
- if color:
204
- style = self.file.createIfcSurfaceStyleShading(SurfaceColour=self.color_xml_to_ifc(color))
205
- else:
206
- style = self.file.createIfcSurfaceStyleShading(
207
- SurfaceColour=self.file.createIfcColourRgb(None, *CATEGORIES[category]["color"]),
208
- )
209
- surface_style = self.file.createIfcSurfaceStyle(Name=name, Side="BOTH", Styles=[style])
236
+ shading = self.file.createIfcSurfaceStyleShading(
237
+ SurfaceColour=self.file.createIfcColourRgb(None, *rgb),
238
+ )
239
+ surface_style = self.file.createIfcSurfaceStyle(Name=name, Side="BOTH", Styles=[shading])
210
240
  self._styles[name] = surface_style
211
241
  return surface_style
212
242
 
213
243
  def color_xml_to_ifc(self, color: int):
214
244
  """Color definition in xml is obscur. We assume that it is a decimal color.
215
245
  See: https://stackoverflow.com/a/2262152/4098083"""
216
- return self.file.createIfcColourRgb(Blue=color & 255, Green=(color >> 8) & 255, Red=(color >> 16) & 255)
246
+ return self.file.createIfcColourRgb(None, *_rgb_int_components(int(color)))
217
247
 
218
248
 
219
249
  def _materials_of(pset):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-materialsdb
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: A library to work with materialsdb.org open standard for building materials.
5
5
  Author-email: Cyril Waechter <cyrwae@hotmail.com>
6
6
  License-Expression: GPL-3.0-or-later
@@ -11,7 +11,7 @@ materialsdb/utils.py,sha256=2xGwr6b4NgOtjT5lxpFVN9jnOSlDsmZPnelSGEs5MDs,3068
11
11
  materialsdb/gui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  materialsdb/gui/__main__.py,sha256=Rha9z_Lxmf2mnCfLUV8s8ZqMRankDhtRrype1v5cm48,1405
13
13
  materialsdb/gui/discovery.py,sha256=au_X0ULkIxjAMV1EWgVAs1aLcl902wi4Kzw6y7M26Ag,792
14
- materialsdb/gui/listener.py,sha256=45DUK4tJALful0lVWX2x0VtfNVGkZ-pwmaWQwmHN0CE,6495
14
+ materialsdb/gui/listener.py,sha256=tfHjQyvu-YkTfXpFUoKwZZQzfm9y6Jo87LCOZkXbJOk,7107
15
15
  materialsdb/gui/server.py,sha256=yMYy_EDPp5Y7kiQiRDc4rGJ_xbSda3RiycWs3CZyN5w,33553
16
16
  materialsdb/gui/static/app-constructions.js,sha256=59oO_oo9li6SJacA1XYQHVG3rx37MJG7ySaM8Mpn5s4,31343
17
17
  materialsdb/gui/static/app.js,sha256=eDb53OkMhslgp5vVghaDZstSK_ooenu0cGumjaMZcOY,22707
@@ -19,15 +19,15 @@ materialsdb/gui/static/constructions.html,sha256=kozoWdVHWrKTiB08kcchXLMuL6jijGE
19
19
  materialsdb/gui/static/index.html,sha256=4pXwmXLIwUIosa7wVBRzVbeuLf_WzlRUs5dxwZsSeNU,3208
20
20
  materialsdb/gui/static/picker-core.js,sha256=bK8308VJcrTgEZECblELwtrU3QW1VZHuqtM3pBPTaIg,4145
21
21
  materialsdb/ifc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
- materialsdb/ifc/material_builder.py,sha256=PESV1ov1BL4aFrurOkI7CMe3i6WEWfK4kgBEDm52-sQ,12245
22
+ materialsdb/ifc/material_builder.py,sha256=PGpznk02_wHcCH4o0jC6jRDoDmugA5kqJO6XL6wL2UY,13523
23
23
  materialsdb/ifc/material_psets.json,sha256=lQ0zQgBq3xnxyYItkmu7BzB5KE9ysFof-rrHawb5T-M,10897
24
24
  materialsdb/ifc/project_library.py,sha256=hOvirB73ZiTYiP6rOu6eN1dU2ZXFRgSOGpQrH2DY4RM,6324
25
25
  materialsdb/schema/MaterialsDBIndex100.xsd,sha256=oK81n2b3_82Mt5G31yEm9vwkMjUmNyM6jglt_zpUQZc,2199
26
26
  materialsdb/schema/materialsdb102.xsd,sha256=IaC6E_B3N1VaU9lhrl6ZGwi8m2rk2p7HTEZKN_Yj2AY,32880
27
27
  materialsdb/schema/materialsdb103.xsd,sha256=iX7Q1ejWEN_ZSuRVCX40zjYt5UraY3f_JxBzqZUFu7Q,37762
28
- python_materialsdb-0.3.1.dist-info/licenses/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
29
- python_materialsdb-0.3.1.dist-info/METADATA,sha256=y09iI0wUVkcDhSEnA3YwIEB4S-CXQx4Ms9IIfMiYvrU,7673
30
- python_materialsdb-0.3.1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
31
- python_materialsdb-0.3.1.dist-info/entry_points.txt,sha256=7bCySVv6oV9hiva7Fn5Dm9oboPRIC6DU6DRlsjCLO6k,66
32
- python_materialsdb-0.3.1.dist-info/top_level.txt,sha256=5ZHbF8Oj1W24bifG65Fl3hCaivZpkO6EyOHHaRavZxE,12
33
- python_materialsdb-0.3.1.dist-info/RECORD,,
28
+ python_materialsdb-0.3.2.dist-info/licenses/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
29
+ python_materialsdb-0.3.2.dist-info/METADATA,sha256=EWVnNfW1XA8YsScGmrwWkLBqKVkvy8dGAvZgX0pk7cw,7673
30
+ python_materialsdb-0.3.2.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
31
+ python_materialsdb-0.3.2.dist-info/entry_points.txt,sha256=7bCySVv6oV9hiva7Fn5Dm9oboPRIC6DU6DRlsjCLO6k,66
32
+ python_materialsdb-0.3.2.dist-info/top_level.txt,sha256=5ZHbF8Oj1W24bifG65Fl3hCaivZpkO6EyOHHaRavZxE,12
33
+ python_materialsdb-0.3.2.dist-info/RECORD,,