Imrao commited on
Commit
759d72e
·
verified ·
1 Parent(s): beb81ba

material api integration

Browse files
Files changed (1) hide show
  1. app.py +47 -19
app.py CHANGED
@@ -49,6 +49,10 @@ RPK_DIR = os.path.join(os.path.dirname(__file__), "rpk")
49
  if not os.path.exists(RPK_DIR):
50
  os.makedirs(RPK_DIR)
51
 
 
 
 
 
52
  class GenerateRequest(BaseModel):
53
  rpk_name: str
54
  geometry: Dict[str, Any] # GeoJSON Feature or Geometry
@@ -125,6 +129,26 @@ def _ensure_report_attrs(rpk_name: str, attrs: Dict[str, Any]) -> Dict[str, Any]
125
  return merged
126
 
127
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  def _extract_reports(
129
  initial_shape: "pyprt.InitialShape",
130
  clean_attrs: Dict[str, Any],
@@ -291,26 +315,23 @@ async def generate_model(request: GenerateRequest):
291
  indices = list(range(len(coords)))
292
  face_counts = [len(coords)]
293
 
294
- initial_shape = pyprt.InitialShape(flattened_coords, indices, face_counts)
 
 
 
 
 
 
 
 
295
 
296
  # Setup Model Generator
297
- # Prepare Options
298
- # We use OBJ encoder then convert to GLB.
299
- # "emitReport": True is needed to get the attributes back? No, that's get_attributes.
300
  export_options = {
301
- "outputPath": tempfile.mkdtemp(), # Create a unique temp directory
302
- "outputFilename": "model", # GLTFEncoder defaults to building model.glb if we pass proper flags
303
  "emitReport": True,
304
  "emitGeometry": True
305
  }
306
-
307
- # Generate
308
- logger.info(f"Generating with RPK: {rpk_path}")
309
- logger.info(f"Using attributes: {request.attributes}")
310
-
311
- # Sanitise attributes
312
- clean_attributes = _clean_attributes(request.attributes)
313
- logger.info(f"Clean attributes: {clean_attributes}")
314
 
315
  is_geometry_only = request.rpk_name in GEOMETRY_ONLY_RPKS
316
 
@@ -475,7 +496,13 @@ async def generate_i3s(request: GenerateRequest):
475
  indices = list(range(len(ecef_coords_all)))
476
  face_counts = [len(ecef_coords_all)]
477
 
478
- initial_shape = pyprt.InitialShape(flattened_coords, indices, face_counts)
 
 
 
 
 
 
479
 
480
  # 4. Encoder Options
481
  layer_id = str(uuid.uuid4())
@@ -495,8 +522,6 @@ async def generate_i3s(request: GenerateRequest):
495
  'globalOffset': anchor_ecef
496
  }
497
 
498
- # Sanitise attributes
499
- clean_attributes = _clean_attributes(request.attributes)
500
  logger.info(f"Generating I3S to {output_dir}")
501
 
502
  # Pass 1 – extract CGA reports via PyEncoder
@@ -721,10 +746,13 @@ async def get_model_report(request: GenerateRequest):
721
 
722
  indices = list(range(len(coords)))
723
  face_counts = [len(coords)]
724
- initial_shape = pyprt.InitialShape(flattened_coords, indices, face_counts)
725
 
726
- # --- Sanitise attributes ---
727
  clean_attributes = _clean_attributes(request.attributes)
 
 
 
 
728
 
729
  # --- Run PyEncoder report pass ---
730
  try:
 
49
  if not os.path.exists(RPK_DIR):
50
  os.makedirs(RPK_DIR)
51
 
52
+ # Base URL of the Material Library API — used to build absolute texture URIs for PyPRT's
53
+ # built-in HTTP resolver. Set MATERIAL_API_URL env var in production (HF Spaces, Docker).
54
+ MATERIAL_API_BASE = os.environ.get("MATERIAL_API_URL", "http://localhost:8000")
55
+
56
  class GenerateRequest(BaseModel):
57
  rpk_name: str
58
  geometry: Dict[str, Any] # GeoJSON Feature or Geometry
 
129
  return merged
130
 
131
 
132
+ def _build_texture_resolve_map(clean_attrs: Dict[str, Any]) -> Dict[str, str]:
133
+ """Build a PyPRT resolve_map for Material API texture paths.
134
+
135
+ When the user picks a texture from the Material Library UI the frontend stores
136
+ the API path (e.g. ``/texture/Architectural/Walls/Brick/.../Color.jpg``) as a
137
+ string attribute value. The CGA rule calls ``texture(WallTexture)`` so PRT looks
138
+ up that exact string in the ResolveMap. This helper maps every such value to an
139
+ absolute HTTP URL so PRT's built-in HTTP resolver can fetch and embed the texture.
140
+
141
+ Only string values starting with ``/texture/`` are mapped; all other attributes
142
+ are left to the RPK's internal ResolveMap (assets bundled inside the RPK).
143
+ """
144
+ resolve_map: Dict[str, str] = {}
145
+ for val in clean_attrs.values():
146
+ if isinstance(val, str) and val.startswith("/texture/"):
147
+ resolve_map[val] = f"{MATERIAL_API_BASE}{val}"
148
+ logger.info(f"Texture resolve_map: {val!r} → {resolve_map[val]!r}")
149
+ return resolve_map
150
+
151
+
152
  def _extract_reports(
153
  initial_shape: "pyprt.InitialShape",
154
  clean_attrs: Dict[str, Any],
 
315
  indices = list(range(len(coords)))
316
  face_counts = [len(coords)]
317
 
318
+ # Sanitise attributes before InitialShape so we can build the texture resolve_map
319
+ clean_attributes = _clean_attributes(request.attributes)
320
+ logger.info(f"Generating with RPK: {rpk_path}")
321
+ logger.info(f"Clean attributes: {clean_attributes}")
322
+
323
+ initial_shape = pyprt.InitialShape(
324
+ flattened_coords, indices, face_counts,
325
+ resolve_map=_build_texture_resolve_map(clean_attributes),
326
+ )
327
 
328
  # Setup Model Generator
 
 
 
329
  export_options = {
330
+ "outputPath": tempfile.mkdtemp(),
331
+ "outputFilename": "model",
332
  "emitReport": True,
333
  "emitGeometry": True
334
  }
 
 
 
 
 
 
 
 
335
 
336
  is_geometry_only = request.rpk_name in GEOMETRY_ONLY_RPKS
337
 
 
496
  indices = list(range(len(ecef_coords_all)))
497
  face_counts = [len(ecef_coords_all)]
498
 
499
+ # Sanitise attributes before InitialShape so we can build the texture resolve_map
500
+ clean_attributes = _clean_attributes(request.attributes)
501
+
502
+ initial_shape = pyprt.InitialShape(
503
+ flattened_coords, indices, face_counts,
504
+ resolve_map=_build_texture_resolve_map(clean_attributes),
505
+ )
506
 
507
  # 4. Encoder Options
508
  layer_id = str(uuid.uuid4())
 
522
  'globalOffset': anchor_ecef
523
  }
524
 
 
 
525
  logger.info(f"Generating I3S to {output_dir}")
526
 
527
  # Pass 1 – extract CGA reports via PyEncoder
 
746
 
747
  indices = list(range(len(coords)))
748
  face_counts = [len(coords)]
 
749
 
750
+ # --- Sanitise attributes before InitialShape so we can build the texture resolve_map ---
751
  clean_attributes = _clean_attributes(request.attributes)
752
+ initial_shape = pyprt.InitialShape(
753
+ flattened_coords, indices, face_counts,
754
+ resolve_map=_build_texture_resolve_map(clean_attributes),
755
+ )
756
 
757
  # --- Run PyEncoder report pass ---
758
  try: