mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-30 16:43:00 +00:00
ifcviewer: overhaul model/object ID tracking
Rename the two overloaded model identifiers and make object_id assignment single-authority, fixing a pick -> properties mismatch. Identifiers: - Per-model UUID fed_id -> model_id; the uint32 runtime handle model_id -> session_model_id (SessionState accessors + mirror hashes renamed to match). "fed_id" was a misnomer -- the federation is the whole collection, not one model. object_id assignment (fixes wrong class on click): - Producers (GeometryStreamer, .ifcview sidecar) now stamp model-LOCAL object_ids; ViewportCore::applyCachedModel is the sole authority that assigns the session-global id (base + local). Removed SceneLoader::next_object_id_, GeometryStreamer::lastObjectId(), and the streamer's start_object_id parameter. - The element table is stamped by the same base on both load paths (applySidecarData and onStreamerFinished), so registry ids match the ids pick returns. Previously the sidecar path double-rebased instances vs the registry (click IfcSite -> showed IfcDoor); the live-stream path had the same latent mismatch. Both closed. Naming / cleanup: - SceneLoader::addFiles -> queueModels; startStreamLoadFor -> loadFromGeometryStreamer; readSidecarMetadataOnly -> readSidecarMetadata. - Federation::addModel takes an explicit display_name (no QFileInfo fallback); callers pass QFileInfo(path).fileName(). - Disambiguate cryptic short locals (d->sidecar, m->model, c->chunk, ...) in SceneLoader, Federation, ViewportWindow, AreaMeasurement, SectionGizmoRenderer, and the SidecarData/SidecarReadPlan spots in ViewportCore. Tests: 125/125 pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+25
-26
@@ -69,61 +69,61 @@ public:
|
||||
bool shouldReadSidecar() const { return should_read_sidecar_; }
|
||||
bool shouldWriteSidecar() const { return should_write_sidecar_; }
|
||||
|
||||
// Returns the model_ids assigned to the enqueued paths, in order.
|
||||
// Returns the session_model_ids assigned to the enqueued paths, in order.
|
||||
// Callers can use these to set up per-model UI state (tree roots, etc.)
|
||||
// before any load signal fires.
|
||||
std::vector<uint32_t> addFiles(const QStringList& paths);
|
||||
std::vector<uint32_t> queueModels(const QStringList& paths);
|
||||
void cancelCurrentLoad();
|
||||
bool isLoading() const { return loading_model_id_ != 0 || !load_queue_.empty(); }
|
||||
bool isLoadingModel(uint32_t mid) const { return loading_model_id_ == mid; }
|
||||
bool isLoading() const { return loading_session_model_id_ != 0 || !load_queue_.empty(); }
|
||||
bool isLoadingModel(uint32_t session_model_id) const { return loading_session_model_id_ == session_model_id; }
|
||||
size_t modelCount() const { return models_.size(); }
|
||||
|
||||
// Drop the loader's tracking for `mid` — its streamer, file path, georef
|
||||
// Drop the loader's tracking for `session_model_id` — its streamer, file path, georef
|
||||
// cache, and queue slot if still pending. Caller is responsible for the
|
||||
// viewport / UI cleanup; this only releases the loader's own state.
|
||||
// Refuses while the model is the active load (use cancelCurrentLoad first).
|
||||
void removeModel(uint32_t mid);
|
||||
void removeModel(uint32_t session_model_id);
|
||||
|
||||
QString filePath(uint32_t mid) const;
|
||||
QString displayName(uint32_t mid) const;
|
||||
ifcopenshell::file* ifcFile(uint32_t mid) const;
|
||||
QString filePath(uint32_t session_model_id) const;
|
||||
QString displayName(uint32_t session_model_id) const;
|
||||
ifcopenshell::file* ifcFile(uint32_t session_model_id) const;
|
||||
|
||||
// Lazily computes the model's georef matrix + unit scales the first
|
||||
// time it's asked for, caches the result, and returns a pointer into the
|
||||
// cache. Returns nullptr when the IFC file isn't available yet (e.g.
|
||||
// sidecar-hit path before the data-source thread populates the streamer).
|
||||
const ModelGeoref* modelGeoref(uint32_t mid);
|
||||
const ModelGeoref* modelGeoref(uint32_t session_model_id);
|
||||
|
||||
signals:
|
||||
void progressChanged(int percent);
|
||||
void loadStarted(uint32_t mid, QString display_name);
|
||||
void loadStarted(uint32_t session_model_id, QString display_name);
|
||||
|
||||
// Fired once per sidecar hit, before loadedFromSidecar, with the full
|
||||
// packed element set. Consumer is responsible for decoding + tree/
|
||||
// property-map population. Moved arguments — avoid unnecessary copies.
|
||||
void sidecarElementsReady(uint32_t mid,
|
||||
void sidecarElementsReady(uint32_t session_model_id,
|
||||
std::vector<ElementTableRecord> elements,
|
||||
std::string string_table);
|
||||
void loadedFromSidecar(uint32_t mid, qint64 elapsed_ms);
|
||||
void loadedFromSidecar(uint32_t session_model_id, qint64 elapsed_ms);
|
||||
|
||||
// Fired after a sidecar-hit model has its .rdb/.ifc opened as a
|
||||
// property data source in the background. Consumers can refresh
|
||||
// any UI that queries ifcFile(mid) for attributes/properties.
|
||||
void dataSourceReady(uint32_t mid);
|
||||
// any UI that queries ifcFile(session_model_id) for attributes/properties.
|
||||
void dataSourceReady(uint32_t session_model_id);
|
||||
|
||||
// Fired repeatedly while streaming, as the worker thread produces
|
||||
// elements. Each batch contains whatever accumulated since the last
|
||||
// poll tick.
|
||||
void streamedElementsReady(uint32_t mid, std::vector<ElementInfo> elements);
|
||||
void streamedElementsReady(uint32_t session_model_id, std::vector<ElementInfo> elements);
|
||||
|
||||
// Fired once after the streamer finishes and the viewport has been
|
||||
// finalized. Consumer may synchronously perform work that needs all
|
||||
// elements to be known (e.g. sidecar write) — SceneLoader will only
|
||||
// start the next queued load after all slots return.
|
||||
void loadedFromStream(uint32_t mid, qint64 elapsed_ms);
|
||||
void loadCancelled(uint32_t mid);
|
||||
void loadedFromStream(uint32_t session_model_id, qint64 elapsed_ms);
|
||||
void loadCancelled(uint32_t session_model_id);
|
||||
|
||||
void loadError(uint32_t mid, QString message);
|
||||
void loadError(uint32_t session_model_id, QString message);
|
||||
void allLoadsFinished();
|
||||
|
||||
private slots:
|
||||
@@ -143,7 +143,7 @@ private:
|
||||
GeometryStreamer* streamer = nullptr;
|
||||
QElapsedTimer load_timer;
|
||||
|
||||
// Cached on first SceneLoader::modelGeoref(mid) call once the
|
||||
// Cached on first SceneLoader::modelGeoref(session_model_id) call once the
|
||||
// streamer has its IFC file loaded.
|
||||
ModelGeoref georef;
|
||||
bool has_georef = false;
|
||||
@@ -158,21 +158,20 @@ private:
|
||||
};
|
||||
|
||||
void startNextLoad();
|
||||
void startStreamLoadFor(uint32_t mid);
|
||||
void loadFromGeometryStreamer(uint32_t session_model_id);
|
||||
void connectStreamer(GeometryStreamer* streamer);
|
||||
void joinSidecarThread();
|
||||
void joinDataSourceThreads();
|
||||
void applySidecarData(uint32_t mid, StreamingSidecar metadata);
|
||||
void startDataSourceLoad(uint32_t mid);
|
||||
void applySidecarData(uint32_t session_model_id, StreamingSidecar metadata);
|
||||
void startDataSourceLoad(uint32_t session_model_id);
|
||||
|
||||
ViewportWindow* viewport_ = nullptr;
|
||||
bool should_read_sidecar_ = false;
|
||||
bool should_write_sidecar_ = false;
|
||||
std::map<uint32_t, Model> models_;
|
||||
std::deque<uint32_t> load_queue_;
|
||||
uint32_t next_model_id_ = 1;
|
||||
uint32_t next_object_id_ = 1;
|
||||
uint32_t loading_model_id_ = 0;
|
||||
uint32_t next_session_model_id_ = 1;
|
||||
uint32_t loading_session_model_id_ = 0;
|
||||
std::thread sidecar_read_thread_;
|
||||
// One thread per sidecar-hit model while its .rdb/.ifc opens in the
|
||||
// background. Joined only at destruction so a slow SPF parse on model
|
||||
|
||||
Reference in New Issue
Block a user