forked from 1b-agent/opencadstudio-upstream
ocs_doc_api: Phase 5 (media & misc, read-mostly)
- entity_kind_name names the media/misc families (RasterImage, Table, Leader, MultiLeader, MLine, Mesh, Helix, Region, Body, Surface, Face3D, Dimension, Hatch) so GetEntity reports a real kind instead of 'Other'. - RasterImage coarse bounds (insertion + u*width + v*height). - Generic delete already works on these families; no typed create in v1 (read-only EntityView per plan). - spec RasterImage/Table read-mostly families; IMPLEMENTATION.md updated. - Test phase5_media_entities_read_kind_and_bounds -> 601 host lib green.
This commit is contained in:
1 parent
7a481c6ce2
commit
f24c0b2d75
6 files changed
+110
-4
No files matched your search
@@ -75,10 +75,14 @@ variants append at enum end.
|
|||||||
viewport-view query (view target/center/scale DTOs).
|
viewport-view query (view target/center/scale DTOs).
|
||||||
|
|
||||||
### Phase 5 — media & misc (read-mostly)
|
### Phase 5 — media & misc (read-mostly)
|
||||||
- **Entities:** raster image, underlay, table, light.
|
- **Done:** media/misc families report a **real `kind`** via `GetEntity`
|
||||||
- **Methods:** CRUD + property queries; few/no geometric actions. These families
|
(`RasterImage`, `Table`, `Leader`, `MultiLeader`, `MLine`, `Mesh`, `Helix`,
|
||||||
largely stay read-only `EntityView` DTOs — typed ops only where the spec
|
`Region`, `Body`, `Surface`, `Face3D`, `Dimension`, `Hatch`) instead of "Other";
|
||||||
declares an action mapping.
|
`RasterImage` has coarse bounds (insertion + u·width + v·height); generic
|
||||||
|
`delete` works on all. Covered by `phase5_*` test.
|
||||||
|
- **Remaining:** typed create/property ops for `RasterImage`/`Table`/light;
|
||||||
|
these largely stay read-only `EntityView` DTOs (typed ops only where the spec
|
||||||
|
declares an action mapping).
|
||||||
|
|
||||||
## 🔧 Outstanding methods on supported families
|
## 🔧 Outstanding methods on supported families
|
||||||
|
|
||||||
|
|||||||
@@ -267,6 +267,25 @@ name = "create_viewport"
|
|||||||
args = [{ name = "center", ty = "[f64; 3]" }, { name = "width", ty = "f64" }, { name = "height", ty = "f64" }, { name = "view_target", ty = "[f64; 3]" }, { name = "view_height", ty = "f64" }]
|
args = [{ name = "center", ty = "[f64; 3]" }, { name = "width", ty = "f64" }, { name = "height", ty = "f64" }, { name = "view_target", ty = "[f64; 3]" }, { name = "view_height", ty = "f64" }]
|
||||||
op = "CreateViewport"
|
op = "CreateViewport"
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# MEDIA & MISC (phase 5, read-mostly) — read-only EntityView, no typed create.
|
||||||
|
# These families report a real `kind` via GetEntity and coarse bounds where
|
||||||
|
# computable; they have no typed construction/geometric ops in v1.
|
||||||
|
# ============================================================================
|
||||||
|
[[family]]
|
||||||
|
name = "RasterImage"
|
||||||
|
acadrust_variant = "RasterImage"
|
||||||
|
handle = "Entity"
|
||||||
|
collection = "entities"
|
||||||
|
description = "Raster image (read-mostly): GetEntity kind + coarse bounds (insertion + u*width + v*height); generic delete. No typed create in v1."
|
||||||
|
|
||||||
|
[[family]]
|
||||||
|
name = "Table"
|
||||||
|
acadrust_variant = "Table"
|
||||||
|
handle = "Entity"
|
||||||
|
collection = "entities"
|
||||||
|
description = "Table (read-only): GetEntity kind; generic delete. No typed create/bounds in v1."
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Cross-cutting ops (generic handles + bulk) — documented in build.rs
|
# Cross-cutting ops (generic handles + bulk) — documented in build.rs
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|||||||
@@ -103,6 +103,14 @@ Paper-space viewport: a width×height window at center looking at view_target wi
|
|||||||
|
|
||||||
- **create_viewport**(`center: [f64; 3], width: f64, height: f64, view_target: [f64; 3], view_height: f64`) -> `Entity`
|
- **create_viewport**(`center: [f64; 3], width: f64, height: f64, view_target: [f64; 3], view_height: f64`) -> `Entity`
|
||||||
|
|
||||||
|
## `Entity` (acadrust `RasterImage`, collection `entities`)
|
||||||
|
|
||||||
|
Raster image (read-mostly): GetEntity kind + coarse bounds (insertion + u*width + v*height); generic delete. No typed create in v1.
|
||||||
|
|
||||||
|
## `Entity` (acadrust `Table`, collection `entities`)
|
||||||
|
|
||||||
|
Table (read-only): GetEntity kind; generic delete. No typed create/bounds in v1.
|
||||||
|
|
||||||
## Generic methods (every handle)
|
## Generic methods (every handle)
|
||||||
|
|
||||||
Every typed handle (`Solid`, `Line`, `Circle`, `Polyline`, `Point`, `Entity`) is a
|
Every typed handle (`Solid`, `Line`, `Circle`, `Polyline`, `Point`, `Entity`) is a
|
||||||
|
|||||||
@@ -201,6 +201,20 @@
|
|||||||
"handle": "Entity",
|
"handle": "Entity",
|
||||||
"methods": [],
|
"methods": [],
|
||||||
"name": "Viewport"
|
"name": "Viewport"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"acadrust_variant": "RasterImage",
|
||||||
|
"collection": "entities",
|
||||||
|
"handle": "Entity",
|
||||||
|
"methods": [],
|
||||||
|
"name": "RasterImage"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"acadrust_variant": "Table",
|
||||||
|
"collection": "entities",
|
||||||
|
"handle": "Entity",
|
||||||
|
"methods": [],
|
||||||
|
"name": "Table"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"layouts": {
|
"layouts": {
|
||||||
|
|||||||
@@ -679,6 +679,43 @@ mod tests {
|
|||||||
assert!((v.center.x - 60.0).abs() < 1e-6);
|
assert!((v.center.x - 60.0).abs() < 1e-6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Phase 5: media & misc (read-mostly) ──────────────────────────────────
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn phase5_media_entities_read_kind_and_bounds() {
|
||||||
|
let mut app = OpenCADStudio::new_for_test();
|
||||||
|
let mut host = HostSession::new(&mut app, 0);
|
||||||
|
// Insert a RasterImage directly (read-mostly: DocApi reads kind + bounds).
|
||||||
|
let img = {
|
||||||
|
use acadrust::entities::RasterImage;
|
||||||
|
use acadrust::types::{Vector2, Vector3};
|
||||||
|
let mut img = RasterImage::default();
|
||||||
|
img.insertion_point = Vector3::new(10.0, 20.0, 0.0);
|
||||||
|
img.u_vector = Vector3::new(0.5, 0.0, 0.0); // 0.5 world-units/pixel in X
|
||||||
|
img.v_vector = Vector3::new(0.0, 0.5, 0.0);
|
||||||
|
img.size = Vector2::new(100.0, 50.0);
|
||||||
|
host.document_mut().add_entity(EntityType::RasterImage(img)).unwrap()
|
||||||
|
};
|
||||||
|
let img_id = handle_to_obj(img);
|
||||||
|
// GetEntity reports kind "RasterImage"; bounds = insertion + u*100 + v*50 = (60, 45).
|
||||||
|
let receipt = dispatch(&mut host, DocApiEnvelope::queries(vec![
|
||||||
|
Query::GetEntity { id: img_id }, Query::GetBounds { id: img_id }])).unwrap();
|
||||||
|
match &receipt.query_results[0] {
|
||||||
|
QueryResult::Entity(e) => assert_eq!(e.kind, "RasterImage"),
|
||||||
|
other => panic!("expected entity, got {other:?}"),
|
||||||
|
}
|
||||||
|
match &receipt.query_results[1] {
|
||||||
|
QueryResult::Bounds(b) => {
|
||||||
|
assert!((b.min[0] - 10.0).abs() < 1e-6 && (b.max[0] - 60.0).abs() < 1e-6, "{b:?}");
|
||||||
|
assert!((b.min[1] - 20.0).abs() < 1e-6 && (b.max[1] - 45.0).abs() < 1e-6, "{b:?}");
|
||||||
|
}
|
||||||
|
other => panic!("expected bounds, got {other:?}"),
|
||||||
|
}
|
||||||
|
// Generic delete works on media entities (read-mostly, but deletable).
|
||||||
|
dispatch(&mut host, DocApiEnvelope::op(Operation::Delete { id: img_id })).unwrap();
|
||||||
|
assert!(host.document().get_entity(img).is_none());
|
||||||
|
}
|
||||||
|
|
||||||
// ── Phase 3: containers (block references) ───────────────────────────────
|
// ── Phase 3: containers (block references) ───────────────────────────────
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -250,6 +250,20 @@ pub fn entity_kind_name(entity: &EntityType) -> &'static str {
|
|||||||
EntityType::Viewport(_) => "Viewport",
|
EntityType::Viewport(_) => "Viewport",
|
||||||
EntityType::Text(_) => "Text",
|
EntityType::Text(_) => "Text",
|
||||||
EntityType::MText(_) => "MText",
|
EntityType::MText(_) => "MText",
|
||||||
|
// Media & misc (phase 5, read-mostly): named so GetEntity reports a real kind.
|
||||||
|
EntityType::RasterImage(_) => "RasterImage",
|
||||||
|
EntityType::Table(_) => "Table",
|
||||||
|
EntityType::Leader(_) => "Leader",
|
||||||
|
EntityType::MultiLeader(_) => "MultiLeader",
|
||||||
|
EntityType::MLine(_) => "MLine",
|
||||||
|
EntityType::Mesh(_) => "Mesh",
|
||||||
|
EntityType::Helix(_) => "Helix",
|
||||||
|
EntityType::Region(_) => "Region",
|
||||||
|
EntityType::Body(_) => "Body",
|
||||||
|
EntityType::Surface(_) => "Surface",
|
||||||
|
EntityType::Face3D(_) => "Face3D",
|
||||||
|
EntityType::Dimension(_) => "Dimension",
|
||||||
|
EntityType::Hatch(_) => "Hatch",
|
||||||
_ => "Other",
|
_ => "Other",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -329,6 +343,16 @@ pub fn entity_bounds(entity: Option<&EntityType>, id: ObjectId) -> ApiResult<Aab
|
|||||||
vp.center.z,
|
vp.center.z,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
EntityType::RasterImage(img) => {
|
||||||
|
// Coarse image rect: origin + u*width + v*height (in world units).
|
||||||
|
let w = img.u_vector.x * img.size.x + img.v_vector.x * img.size.y;
|
||||||
|
let h = img.u_vector.y * img.size.x + img.v_vector.y * img.size.y;
|
||||||
|
let (x0, y0) = (img.insertion_point.x, img.insertion_point.y);
|
||||||
|
Aabb {
|
||||||
|
min: [x0.min(x0 + w), y0.min(y0 + h), img.insertion_point.z],
|
||||||
|
max: [x0.max(x0 + w), y0.max(y0 + h), img.insertion_point.z],
|
||||||
|
}
|
||||||
|
}
|
||||||
// Ray/XLine are unbounded by definition — no finite bounds.
|
// Ray/XLine are unbounded by definition — no finite bounds.
|
||||||
_ => return Err(ApiError::Unsupported("bounds for this entity family is not yet implemented".into())),
|
_ => return Err(ApiError::Unsupported("bounds for this entity family is not yet implemented".into())),
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in new issue
Block a user