mirror of
https://github.com/brunopostle/ifcurl.git
synced 2026-07-12 10:18:14 +00:00
render: fix render_diff — tuple unpack, IfcProduct filter, diff-area zoom
- git.py: unpack (repo, is_stale) tuple from _get_repo() in diff_text; was AttributeError 'tuple has no attribute commit' on every render_diff - render.py: filter removed_entities and _entity_bounds include list to IfcProduct only; non-geometric entities (IfcTaskTime etc) crash the ifcopenshell geom iterator - render.py: replace reset_camera(bounds=diff_bounds) with explicit camera positioning; pyvista's reset_camera re-expands clipping to all actors so the full scene remained visible — now camera is repositioned at the default viewing direction but at a distance sized to the diff bounds, zooming tightly to just the changed elements Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
134bd4d887
commit
837a9d10c8
3 changed files with 29 additions and 5 deletions
|
|
@ -43,7 +43,11 @@
|
|||
{"id":"ifcurl-ei8","title":"Fix syncCameraUrl: convert WebGL coords to IFC world space","description":"syncCameraUrl in viewer.py currently records camera.position/direction/up directly from Three.js, which are in WebGL/Three.js coordinate space (Y-up, different scale/orientation than IFC). The ifc:// URL spec expects IFC world coordinates (Z-up, matching BCF viewpoint conventions). Need to find the IFC→Three.js transform that @thatopen/components applies when loading a model, then apply its inverse in syncCameraUrl before serialising the camera params. Repos cloned for reference: ~/src/engine_components and ~/src/engine_fragment.","status":"closed","priority":2,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-23T05:53:06Z","created_by":"Bruno Postle","updated_at":"2026-04-23T06:14:36Z","closed_at":"2026-04-23T06:14:36Z","close_reason":"Split into atomic tasks: ifcurl-ldk, ifcurl-j2s, ifcurl-cmd","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||
{"id":"ifcurl-i1s","title":"Test Phase 3b web viewer end-to-end","description":"After deploying the footer template (ifcurl-ach), test the full flow: open an .ifc file in Forgejo at localhost:3000, click 'View in 3D', verify the viewer loads the model. CDN versions (@thatopen/components 2.4.0, three 0.160.0, web-ifc 0.0.66) may need adjustment if the API has changed.","status":"closed","priority":2,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-23T05:48:01Z","created_by":"Bruno Postle","updated_at":"2026-04-23T20:05:04Z","started_at":"2026-04-23T19:54:56Z","closed_at":"2026-04-23T20:05:04Z","close_reason":"Closed","dependencies":[{"issue_id":"ifcurl-i1s","depends_on_id":"ifcurl-49o","type":"blocks","created_at":"2026-04-23T07:14:12Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"ifcurl-i1s","depends_on_id":"ifcurl-4yu","type":"blocks","created_at":"2026-04-23T07:14:11Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"ifcurl-i1s","depends_on_id":"ifcurl-ach","type":"blocks","created_at":"2026-04-23T06:48:10Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"ifcurl-i1s","depends_on_id":"ifcurl-ahd","type":"blocks","created_at":"2026-04-23T07:02:54Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":4,"dependent_count":1,"comment_count":0}
|
||||
{"id":"ifcurl-ach","title":"Deploy Phase 3b footer template to Forgejo","description":"The footer.tmpl file that injects a 'View in 3D' button on .ifc file pages has been written but not yet deployed. Deploy it to /etc/forgejo/templates/custom/footer.tmpl and verify the button appears when viewing an .ifc file on localhost:3000.","status":"closed","priority":2,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-04-23T05:47:53Z","created_by":"Bruno Postle","updated_at":"2026-04-23T06:14:35Z","closed_at":"2026-04-23T06:14:35Z","close_reason":"Split into atomic tasks: ifcurl-ohq, ifcurl-49o","dependencies":[{"issue_id":"ifcurl-ach","depends_on_id":"ifcurl-ahd","type":"blocks","created_at":"2026-04-23T07:02:40Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0}
|
||||
{"id":"ifcurl-a9x","title":"viewer: typing in selector box does not filter or apply selector","description":"Typing an IfcOpenShell selector expression (e.g. 'IfcWall') into the selector input box has no effect. The selector should be applied to the model, updating the view to show only matching elements.","status":"open","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T21:37:17Z","created_by":"Bruno Postle","updated_at":"2026-04-25T21:37:17Z","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||
{"id":"ifcurl-irp","title":"viewer: no render_diff preview shown on Forgejo commit pages","description":"When viewing a commit in Forgejo that contains .ifc file changes (e.g. /bruno/simple-ifc/commit/61e64e05d783e621d77869feadfc218a0858c499), no 3D diff preview image is injected. The footer.tmpl is supposed to detect .ifc diffs on commit pages and inject an img tag pointing to /render_diff. Either the detection is not firing or the render_diff request is failing.","status":"open","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T22:17:59Z","created_by":"Bruno Postle","updated_at":"2026-04-25T22:17:59Z","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||
{"id":"ifcurl-3sz","title":"preview: visibility=highlight renders non-selected elements as opaque grey instead of transparent grey","description":"In the rendered PNG, visibility=highlight shows selected elements normally but non-selected elements appear as opaque grey rather than transparent grey (semi-transparent). The highlight mode should make non-selected elements translucent so the selected elements are visually emphasised against a faded context.","status":"open","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T22:15:42Z","created_by":"Bruno Postle","updated_at":"2026-04-25T22:15:42Z","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||
{"id":"ifcurl-d7m","title":"viewer: visibility=highlight renders as isolate (non-selected elements should be transparent grey)","description":"In the viewer, visibility=highlight and visibility=isolate produce identical results — only selected elements are shown. The correct behaviour for highlight is to show selected elements normally and render all other elements as transparent grey. Isolate should hide non-selected elements entirely. The preview service already handles both modes correctly.","status":"open","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T22:15:41Z","created_by":"Bruno Postle","updated_at":"2026-04-25T22:15:41Z","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||
{"id":"ifcurl-xy9","title":"viewer: orthographic projection not implemented (works in preview)","description":"The viewer ignores the 'scale' parameter that selects orthographic projection. The preview service renders orthographic views correctly, but the 3D viewer in the browser always shows perspective. The viewer needs to switch to an orthographic camera when the IFC URL contains 'scale=' instead of 'fov='.","status":"open","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T22:15:38Z","created_by":"Bruno Postle","updated_at":"2026-04-25T22:15:38Z","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||
{"id":"ifcurl-a9x","title":"viewer: typing in selector box does not filter or apply selector","description":"Typing an IfcOpenShell selector expression (e.g. 'IfcWall') into the selector input box has no effect. The selector should be applied to the model, updating the view to show only matching elements.","status":"closed","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T21:37:17Z","created_by":"Bruno Postle","updated_at":"2026-04-25T22:36:10Z","closed_at":"2026-04-25T22:36:10Z","close_reason":"selector box now working in viewer","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||
{"id":"ifcurl-66h","title":"viewer: browse branches/tags button does not navigate to selected ref","description":"The browse branches and tags button does not appear to do anything when clicked. The ref input box has a datalist populated with heads/main but selecting a branch/tag and clicking browse does not navigate to that ref.","status":"open","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T21:37:16Z","created_by":"Bruno Postle","updated_at":"2026-04-25T21:37:16Z","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||
{"id":"ifcurl-njq","title":"viewer: 'open new issue' link uses https:// but Forgejo may be on http://","description":"The 'open new issue' link hardcodes https:// scheme, but the Forgejo instance may be served over http:// (e.g. on localhost for development). Should use the same scheme as the current page or derive it from the Forgejo base URL.","status":"open","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T21:37:14Z","created_by":"Bruno Postle","updated_at":"2026-04-25T21:37:14Z","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||
{"id":"ifcurl-uo9","title":"viewer: BCF export does not include preview PNG","description":"BCF export produces a valid BCF file but the viewpoint snapshot (preview PNG) is missing. BCF spec requires a snapshot image in each viewpoint. The ifcurl render service should be called to generate this.","status":"open","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T21:37:13Z","created_by":"Bruno Postle","updated_at":"2026-04-25T21:37:13Z","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ def diff_text(base_url: IfcUrl, head_url: IfcUrl, token: str | None = None) -> s
|
|||
f"(got {base_url.path!r} vs {head_url.path!r})"
|
||||
)
|
||||
|
||||
repo = _get_repo(base_url, token=token)
|
||||
repo, _ = _get_repo(base_url, token=token)
|
||||
try:
|
||||
base_hexsha = repo.commit(base_url.git_ref()).hexsha
|
||||
head_hexsha = repo.commit(head_url.git_ref()).hexsha
|
||||
|
|
|
|||
|
|
@ -556,8 +556,11 @@ def _entity_bounds(model: ifcopenshell.file, entities: list) -> list[float] | No
|
|||
"""Return [xmin,xmax,ymin,ymax,zmin,zmax] for *entities* in world coords, or None."""
|
||||
if not entities:
|
||||
return None
|
||||
products = [e for e in entities if e.is_a("IfcProduct")]
|
||||
if not products:
|
||||
return None
|
||||
settings = _build_geom_settings(model)
|
||||
it = ifcopenshell.geom.iterator(settings, model, _WORKER_COUNT, include=entities)
|
||||
it = ifcopenshell.geom.iterator(settings, model, _WORKER_COUNT, include=products)
|
||||
if not it.initialize():
|
||||
return None
|
||||
all_verts: list[np.ndarray] = []
|
||||
|
|
@ -656,7 +659,9 @@ def render_diff(
|
|||
removed_entities = []
|
||||
for eid in removed_ids:
|
||||
try:
|
||||
removed_entities.append(model_base.by_id(eid))
|
||||
e = model_base.by_id(eid)
|
||||
if e.is_a("IfcProduct"):
|
||||
removed_entities.append(e)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
|
@ -718,8 +723,23 @@ def render_diff(
|
|||
if camera is not None:
|
||||
_apply_camera(plotter1, camera, fov, scale)
|
||||
elif diff_bounds is not None:
|
||||
plotter1.reset_camera(bounds=diff_bounds)
|
||||
# Reset first to establish a good viewing direction, then reposition
|
||||
# close to the diff area. reset_camera(bounds=...) re-expands the
|
||||
# clipping range to include all actors, so it doesn't actually zoom;
|
||||
# explicit positioning is required.
|
||||
plotter1.reset_camera()
|
||||
plotter1.camera.up = (0, 0, 1)
|
||||
xmin, xmax, ymin, ymax, zmin, zmax = diff_bounds
|
||||
cx, cy, cz = (xmin + xmax) / 2, (ymin + ymax) / 2, (zmin + zmax) / 2
|
||||
max_dim = max(xmax - xmin, ymax - ymin, zmax - zmin, 1e-3)
|
||||
cam_pos = np.array(plotter1.camera.position)
|
||||
focal = np.array(plotter1.camera.focal_point)
|
||||
direction = cam_pos - focal
|
||||
direction /= np.linalg.norm(direction)
|
||||
fov_rad = np.radians(plotter1.camera.view_angle)
|
||||
dist = (max_dim / 2) / np.tan(fov_rad / 2) * 1.5
|
||||
plotter1.camera.focal_point = (cx, cy, cz)
|
||||
plotter1.camera.position = tuple(np.array([cx, cy, cz]) + direction * dist)
|
||||
if scale is not None:
|
||||
plotter1.camera.parallel_projection = True
|
||||
plotter1.camera.parallel_scale = scale
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue