Imrao commited on
Commit
410126b
·
1 Parent(s): d632ee1

update1.2

Browse files
Files changed (1) hide show
  1. app.py +41 -56
app.py CHANGED
@@ -69,34 +69,33 @@ async def get_rpk_info(filename: str):
69
 
70
  formatted_attrs = []
71
 
72
- # Handle Dictionary return type (common in some PyPRT versions)
73
- if isinstance(attrs_info, dict):
74
- for name, attr in attrs_info.items():
75
- # attr is likely the Attribute object
76
- default_val = ""
77
- attr_type = "string"
78
-
79
- if hasattr(attr, 'get_default_value'):
80
- default_val = attr.get_default_value()
81
- elif hasattr(attr, 'get_defaultValue'): # Try alternate naming
82
- default_val = attr.get_defaultValue()
83
-
84
- if hasattr(attr, 'get_type'):
85
- attr_type = str(attr.get_type())
86
-
87
- formatted_attrs.append({
88
- "name": name,
89
- "type": attr_type,
90
- "defaultValue": default_val
91
- })
92
  # Handle List of Objects return type (standard PyPRT)
93
- elif hasattr(attrs_info, '__iter__'):
94
  for attr in attrs_info:
95
  if hasattr(attr, 'get_name'):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  formatted_attrs.append({
97
- "name": attr.get_name(),
98
- "type": str(attr.get_type()),
99
- "defaultValue": attr.get_default_value(),
 
100
  })
101
  elif isinstance(attr, str):
102
  # Fallback if list of strings
@@ -109,7 +108,7 @@ async def get_rpk_info(filename: str):
109
  return {"attributes": formatted_attrs}
110
  except Exception as e:
111
  logger.error(f"Error inspecting RPK: {e}")
112
- # Return empty attributes instead of 500 if inspection fails, to allow partial functioning
113
  return {"attributes": []}
114
 
115
  @app.post("/generate")
@@ -136,41 +135,30 @@ async def generate_model(request: GenerateRequest):
136
  if geom_dict.get("type") != "Polygon":
137
  raise HTTPException(status_code=400, detail="Only Polygons are supported")
138
 
139
- # Extract coordinates
140
- # Shapely polygon exterior coords: [(x, y, z?), ...]
141
- # PyPRT expects flat list or specific structure depending on version
142
- # Using simple approach: create initial shape from vertices
143
-
144
- # Coordinate Processing for Local Tangent Plane
145
- # The frontend now sends coordinates in proper local meters (ENU frame).
146
- # We do NOT project or transform them. We explicitly trust the frontend input.
147
-
148
- # We also don't need to re-center, as the frontend sends relative coordinates from the centroid (0,0).
149
- # But to be safe, we can ensure centering if the frontend doesn't perfectly center around 0,0.
150
- # Actually, DrawTools sends vectors from center, so they are practically centered.
151
- # We'll calculate bounds just for logging.
152
- bounds = shape.bounds
153
- logger.info(f"Received geometry bounds: {bounds}")
154
 
155
- # Centroid should be near 0,0
 
 
 
 
 
156
  centroid = shape.centroid
157
  logger.info(f"Geometry Centroid: {centroid.x}, {centroid.y}")
158
-
159
- coords = list(shape.exterior.coords)
 
 
 
 
160
  # Remove last point if duplicate (closed loop)
161
  if coords[0] == coords[-1]:
162
  coords = coords[:-1]
163
 
164
- # Flatten and ensure 3D (x, z, y) or (x, y, z) - Mapbox/Cesium usually (lng, lat)
165
- # PyPRT often expects local coordinates or projected.
166
- # WARNING: PyPRT does not handle re-projection automatically usually.
167
- # For this example, we assume coordinates are suitable for PyPRT (e.g. meter based if RPK expects meters)
168
- # OR we just pass them and let PyPRT handle if it's geographic.
169
- # Standard CityEngine works best with metric local coordinates.
170
-
171
  # Flatten coordinates: [(x, y), ...] -> [x, 0, y, x, 0, y, ...]
172
- # PyPRT expects a flattened list of coords.
173
- flattened_coords = []
174
  flattened_coords = []
175
  for p in coords:
176
  x = p[0]
@@ -190,10 +178,7 @@ async def generate_model(request: GenerateRequest):
190
  output_filename = "model"
191
 
192
  # Generate
193
- # PyPRT generate_model signature:
194
- # (self: ModelGenerator, shapeAttributes: list[dict], rulePackagePath: str, geometryEncoderName: str, geometryEncoderOptions: dict)
195
-
196
- # Generate using OBJ Encoder (Workaround for broken GLB encoder)
197
  models = model_generator.generate_model(
198
  [request.attributes],
199
  rpk_path,
 
69
 
70
  formatted_attrs = []
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  # Handle List of Objects return type (standard PyPRT)
73
+ if hasattr(attrs_info, '__iter__'):
74
  for attr in attrs_info:
75
  if hasattr(attr, 'get_name'):
76
+ name = attr.get_name()
77
+ attr_type = str(attr.get_type())
78
+ default_val = attr.get_default_value()
79
+ annotations = []
80
+
81
+ if hasattr(attr, 'get_annotations'):
82
+ py_annotations = attr.get_annotations()
83
+ # Convert PyPRT annotations to serializable format
84
+ # Annotations are typically list of objects or similar
85
+ for anno in py_annotations:
86
+ # anno might be an object with get_key(), get_value_type(), get_arguments()
87
+ if hasattr(anno, 'get_key'):
88
+ key = anno.get_key()
89
+ args = []
90
+ if hasattr(anno, 'get_arguments'):
91
+ args = anno.get_arguments()
92
+ annotations.append({"key": key, "arguments": args})
93
+
94
  formatted_attrs.append({
95
+ "name": name,
96
+ "type": attr_type,
97
+ "defaultValue": default_val,
98
+ "annotations": annotations
99
  })
100
  elif isinstance(attr, str):
101
  # Fallback if list of strings
 
108
  return {"attributes": formatted_attrs}
109
  except Exception as e:
110
  logger.error(f"Error inspecting RPK: {e}")
111
+ # Return empty attributes instead of 500 if inspection fails
112
  return {"attributes": []}
113
 
114
  @app.post("/generate")
 
135
  if geom_dict.get("type") != "Polygon":
136
  raise HTTPException(status_code=400, detail="Only Polygons are supported")
137
 
138
+ # 1. Enforce Counter-Clockwise (CCW) Winding
139
+ # This prevents the model from being generated upside-down (mirrored on Z)
140
+ if not shape.is_valid:
141
+ shape = shape.buffer(0)
 
 
 
 
 
 
 
 
 
 
 
142
 
143
+ # shapely.ops.orient(geom, sign=1.0) -> CCW
144
+ shape = shapely.ops.orient(shape, sign=1.0)
145
+
146
+ # 2. Re-Center Geometry
147
+ # To ensure the model is generated around (0,0,0) so it can be placed correctly
148
+ # at the centroid by the frontend.
149
  centroid = shape.centroid
150
  logger.info(f"Geometry Centroid: {centroid.x}, {centroid.y}")
151
+
152
+ # Translate shape so centroid is at (0,0)
153
+ # origin = (0,0)
154
+ shape_centered = translate(shape, xoff=-centroid.x, yoff=-centroid.y)
155
+
156
+ coords = list(shape_centered.exterior.coords)
157
  # Remove last point if duplicate (closed loop)
158
  if coords[0] == coords[-1]:
159
  coords = coords[:-1]
160
 
 
 
 
 
 
 
 
161
  # Flatten coordinates: [(x, y), ...] -> [x, 0, y, x, 0, y, ...]
 
 
162
  flattened_coords = []
163
  for p in coords:
164
  x = p[0]
 
178
  output_filename = "model"
179
 
180
  # Generate
181
+ # Using OBJ Encdoer for stability
 
 
 
182
  models = model_generator.generate_model(
183
  [request.attributes],
184
  rpk_path,