forked from 1b-agent/opencadstudio-upstream
General improvements on API
This commit is contained in:
1 parent
56e09cd3f5
commit
55f61a4327
30 files changed
+1820
-2565
No files matched your search
@@ -8,11 +8,11 @@ use std::collections::HashMap;
|
||||
|
||||
use ocs_doc_api::backend::{DocApiBackend, KernelBody};
|
||||
use ocs_doc_api::{
|
||||
Aabb, ApiError, ApiResult, Curve2Spec, EntityView, GeometryErrorKind, GeometryRevision,
|
||||
ObjectId, PlacementSpec,
|
||||
Aabb, ApiError, ApiResult, Curve2Spec, EntityView, GeometryErrorKind, GeometryRevision, ObjectId,
|
||||
PlacementSpec,
|
||||
};
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
#[derive(Default)]
|
||||
pub struct MockBackend {
|
||||
next_id: u64,
|
||||
revision: u64,
|
||||
@@ -68,10 +68,7 @@ fn curve_bounds(spec: &Curve2Spec) -> Aabb {
|
||||
min: [centre[0] - radius, centre[1] - radius, centre[2]],
|
||||
max: [centre[0] + radius, centre[1] + radius, centre[2]],
|
||||
},
|
||||
Curve2Spec::Point { position } => Aabb {
|
||||
min: *position,
|
||||
max: *position,
|
||||
},
|
||||
Curve2Spec::Point { position } => Aabb { min: *position, max: *position },
|
||||
Curve2Spec::Polyline { points, .. } => {
|
||||
let mut min = [f64::INFINITY; 3];
|
||||
let mut max = [f64::NEG_INFINITY; 3];
|
||||
@@ -87,17 +84,9 @@ fn curve_bounds(spec: &Curve2Spec) -> Aabb {
|
||||
min: [centre[0] - radius, centre[1] - radius, centre[2]],
|
||||
max: [centre[0] + radius, centre[1] + radius, centre[2]],
|
||||
},
|
||||
Curve2Spec::Ellipse {
|
||||
centre, major_axis, ..
|
||||
} => {
|
||||
let r = (major_axis[0] * major_axis[0]
|
||||
+ major_axis[1] * major_axis[1]
|
||||
+ major_axis[2] * major_axis[2])
|
||||
.sqrt();
|
||||
Aabb {
|
||||
min: [centre[0] - r, centre[1] - r, centre[2] - r],
|
||||
max: [centre[0] + r, centre[1] + r, centre[2] + r],
|
||||
}
|
||||
Curve2Spec::Ellipse { centre, major_axis, .. } => {
|
||||
let r = (major_axis[0] * major_axis[0] + major_axis[1] * major_axis[1] + major_axis[2] * major_axis[2]).sqrt();
|
||||
Aabb { min: [centre[0] - r, centre[1] - r, centre[2] - r], max: [centre[0] + r, centre[1] + r, centre[2] + r] }
|
||||
}
|
||||
Curve2Spec::Spline { control_points, .. } => {
|
||||
let mut min = [f64::INFINITY; 3];
|
||||
@@ -110,10 +99,7 @@ fn curve_bounds(spec: &Curve2Spec) -> Aabb {
|
||||
}
|
||||
Aabb { min, max }
|
||||
}
|
||||
Curve2Spec::Ray { origin, .. } | Curve2Spec::XLine { origin, .. } => Aabb {
|
||||
min: *origin,
|
||||
max: *origin,
|
||||
},
|
||||
Curve2Spec::Ray { origin, .. } | Curve2Spec::XLine { origin, .. } => Aabb { min: *origin, max: *origin },
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,35 +118,6 @@ impl DocApiBackend for MockBackend {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn create_many(&mut self, specs: &[ocs_doc_api::EntitySpec]) -> ApiResult<Vec<ObjectId>> {
|
||||
let mut next = self.clone();
|
||||
let ids = specs
|
||||
.iter()
|
||||
.map(|spec| match spec {
|
||||
ocs_doc_api::EntitySpec::Solid(spec) => {
|
||||
next.store_solid(&ocs_doc_api::geom::make_solid(spec)?)
|
||||
}
|
||||
ocs_doc_api::EntitySpec::Curve(spec) => {
|
||||
ocs_doc_api::convert::curve_spec_to_entity(spec)?;
|
||||
next.add_curve(spec)
|
||||
}
|
||||
})
|
||||
.collect::<ApiResult<Vec<_>>>()?;
|
||||
next.push_undo("CreateMany");
|
||||
next.finalize_op();
|
||||
*self = next;
|
||||
Ok(ids)
|
||||
}
|
||||
fn transform_many(&mut self, ids: &[ObjectId], placement: &PlacementSpec) -> ApiResult<()> {
|
||||
let mut next = self.clone();
|
||||
for &id in ids {
|
||||
next.transform_entity(id, placement)?;
|
||||
}
|
||||
next.push_undo("TransformMany");
|
||||
next.finalize_op();
|
||||
*self = next;
|
||||
Ok(())
|
||||
}
|
||||
fn add_curve(&mut self, spec: &Curve2Spec) -> ApiResult<ObjectId> {
|
||||
let kind = match spec {
|
||||
Curve2Spec::Line { .. } => "Line",
|
||||
@@ -185,8 +142,7 @@ impl DocApiBackend for MockBackend {
|
||||
}
|
||||
fn add_viewport(&mut self, spec: &ocs_doc_api::ops::ViewportSpec) -> ApiResult<ObjectId> {
|
||||
let id = self.alloc("Viewport");
|
||||
self.viewport_views
|
||||
.insert(id, (spec.view_target, spec.view_height));
|
||||
self.viewport_views.insert(id, (spec.view_target, spec.view_height));
|
||||
Ok(id)
|
||||
}
|
||||
fn add_text(&mut self, spec: &ocs_doc_api::ops::TextSpec) -> ApiResult<ObjectId> {
|
||||
@@ -208,27 +164,17 @@ impl DocApiBackend for MockBackend {
|
||||
}
|
||||
}
|
||||
fn text_content(&self, id: ObjectId) -> ApiResult<String> {
|
||||
self.text_values
|
||||
.get(&id)
|
||||
.cloned()
|
||||
.ok_or(ApiError::UnknownId(id))
|
||||
self.text_values.get(&id).cloned().ok_or(ApiError::UnknownId(id))
|
||||
}
|
||||
fn add_hatch(&mut self, spec: &ocs_doc_api::ops::HatchSpec) -> ApiResult<ObjectId> {
|
||||
let id = self.alloc("Hatch");
|
||||
self.hatch_boundaries
|
||||
.insert(id, vec![spec.boundary.clone()]);
|
||||
self.hatch_boundaries.insert(id, vec![spec.boundary.clone()]);
|
||||
Ok(id)
|
||||
}
|
||||
fn hatch_boundary(&self, id: ObjectId) -> ApiResult<Vec<Vec<[f64; 2]>>> {
|
||||
self.hatch_boundaries
|
||||
.get(&id)
|
||||
.cloned()
|
||||
.ok_or(ApiError::UnknownId(id))
|
||||
self.hatch_boundaries.get(&id).cloned().ok_or(ApiError::UnknownId(id))
|
||||
}
|
||||
fn add_dimension_linear(
|
||||
&mut self,
|
||||
spec: &ocs_doc_api::ops::DimensionSpec,
|
||||
) -> ApiResult<ObjectId> {
|
||||
fn add_dimension_linear(&mut self, spec: &ocs_doc_api::ops::DimensionSpec) -> ApiResult<ObjectId> {
|
||||
let id = self.alloc("Dimension");
|
||||
let d = ((spec.first_point[0] - spec.second_point[0]).powi(2)
|
||||
+ (spec.first_point[1] - spec.second_point[1]).powi(2)
|
||||
@@ -237,54 +183,30 @@ impl DocApiBackend for MockBackend {
|
||||
self.dimension_measurements.insert(id, d);
|
||||
Ok(id)
|
||||
}
|
||||
fn add_dimension_radius(
|
||||
&mut self,
|
||||
spec: &ocs_doc_api::ops::DimensionRadialSpec,
|
||||
) -> ApiResult<ObjectId> {
|
||||
fn add_dimension_radius(&mut self, spec: &ocs_doc_api::ops::DimensionRadialSpec) -> ApiResult<ObjectId> {
|
||||
let id = self.alloc("Dimension");
|
||||
let d = ((spec.center[0] - spec.point[0]).powi(2)
|
||||
+ (spec.center[1] - spec.point[1]).powi(2)
|
||||
+ (spec.center[2] - spec.point[2]).powi(2))
|
||||
.sqrt();
|
||||
let d = ((spec.center[0] - spec.point[0]).powi(2) + (spec.center[1] - spec.point[1]).powi(2) + (spec.center[2] - spec.point[2]).powi(2)).sqrt();
|
||||
self.dimension_measurements.insert(id, d);
|
||||
Ok(id)
|
||||
}
|
||||
fn add_dimension_diameter(
|
||||
&mut self,
|
||||
spec: &ocs_doc_api::ops::DimensionRadialSpec,
|
||||
) -> ApiResult<ObjectId> {
|
||||
fn add_dimension_diameter(&mut self, spec: &ocs_doc_api::ops::DimensionRadialSpec) -> ApiResult<ObjectId> {
|
||||
self.add_dimension_radius(spec)
|
||||
}
|
||||
fn add_dimension_angular(
|
||||
&mut self,
|
||||
_spec: &ocs_doc_api::ops::DimensionAngularSpec,
|
||||
) -> ApiResult<ObjectId> {
|
||||
fn add_dimension_angular(&mut self, _spec: &ocs_doc_api::ops::DimensionAngularSpec) -> ApiResult<ObjectId> {
|
||||
let id = self.alloc("Dimension");
|
||||
self.dimension_measurements.insert(id, 90.0);
|
||||
Ok(id)
|
||||
}
|
||||
fn dimension_measurement(&self, id: ObjectId) -> ApiResult<f64> {
|
||||
self.dimension_measurements
|
||||
.get(&id)
|
||||
.copied()
|
||||
.ok_or(ApiError::UnknownId(id))
|
||||
self.dimension_measurements.get(&id).copied().ok_or(ApiError::UnknownId(id))
|
||||
}
|
||||
fn add_attribute_definition(
|
||||
&mut self,
|
||||
spec: &ocs_doc_api::ops::AttributeDefinitionSpec,
|
||||
) -> ApiResult<ObjectId> {
|
||||
fn add_attribute_definition(&mut self, spec: &ocs_doc_api::ops::AttributeDefinitionSpec) -> ApiResult<ObjectId> {
|
||||
if spec.tag.is_empty() {
|
||||
return Err(ApiError::validation(
|
||||
"CreateAttributeDefinition",
|
||||
"empty tag",
|
||||
));
|
||||
return Err(ApiError::validation("CreateAttributeDefinition", "empty tag"));
|
||||
}
|
||||
Ok(self.alloc("AttributeDefinition"))
|
||||
}
|
||||
fn add_dimension_angular2ln(
|
||||
&mut self,
|
||||
_spec: &ocs_doc_api::ops::DimensionAngularSpec,
|
||||
) -> ApiResult<ObjectId> {
|
||||
fn add_dimension_angular2ln(&mut self, _spec: &ocs_doc_api::ops::DimensionAngularSpec) -> ApiResult<ObjectId> {
|
||||
let id = self.alloc("Dimension");
|
||||
self.dimension_measurements.insert(id, 90.0);
|
||||
Ok(id)
|
||||
@@ -292,10 +214,7 @@ impl DocApiBackend for MockBackend {
|
||||
fn add_table(&mut self, spec: &ocs_doc_api::ops::TableSpec) -> ApiResult<ObjectId> {
|
||||
let cols = spec.data.first().map(|r| r.len()).unwrap_or(0);
|
||||
if spec.data.is_empty() || cols == 0 || spec.data.iter().any(|r| r.len() != cols) {
|
||||
return Err(ApiError::validation(
|
||||
"CreateTable",
|
||||
"table needs a non-empty rectangular grid",
|
||||
));
|
||||
return Err(ApiError::validation("CreateTable", "table needs a non-empty rectangular grid"));
|
||||
}
|
||||
Ok(self.alloc("Table"))
|
||||
}
|
||||
@@ -312,24 +231,15 @@ impl DocApiBackend for MockBackend {
|
||||
Ok(())
|
||||
}
|
||||
fn attributes(&self, id: ObjectId) -> ApiResult<Vec<(String, String)>> {
|
||||
self.attributes_store
|
||||
.get(&id)
|
||||
.cloned()
|
||||
.ok_or(ApiError::UnknownId(id))
|
||||
self.attributes_store.get(&id).cloned().ok_or(ApiError::UnknownId(id))
|
||||
}
|
||||
fn block_entities(&self, _block_name: &str) -> ApiResult<Vec<EntityView>> {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
fn add_raster_image(
|
||||
&mut self,
|
||||
_spec: &ocs_doc_api::ops::RasterImageSpec,
|
||||
) -> ApiResult<ObjectId> {
|
||||
fn add_raster_image(&mut self, _spec: &ocs_doc_api::ops::RasterImageSpec) -> ApiResult<ObjectId> {
|
||||
Ok(self.alloc("RasterImage"))
|
||||
}
|
||||
fn loft(
|
||||
&mut self,
|
||||
sections: &[(cadkernel::space::Plane, Vec<cadkernel::geom2d::Curve>)],
|
||||
) -> ApiResult<ObjectId> {
|
||||
fn loft(&mut self, sections: &[Vec<cadkernel::geom2d::Curve>]) -> ApiResult<ObjectId> {
|
||||
if sections.len() < 2 {
|
||||
return Err(ApiError::validation("Loft", "loft needs >= 2 profiles"));
|
||||
}
|
||||
@@ -337,12 +247,7 @@ impl DocApiBackend for MockBackend {
|
||||
.ok_or_else(|| ApiError::geometry(GeometryErrorKind::InvalidInput, "make cuboid"))?;
|
||||
self.store_solid(&body)
|
||||
}
|
||||
fn set_viewport_view(
|
||||
&mut self,
|
||||
id: ObjectId,
|
||||
view_target: [f64; 3],
|
||||
view_height: f64,
|
||||
) -> ApiResult<()> {
|
||||
fn set_viewport_view(&mut self, id: ObjectId, view_target: [f64; 3], view_height: f64) -> ApiResult<()> {
|
||||
if !self.entity_exists(id) {
|
||||
return Err(ApiError::UnknownId(id));
|
||||
}
|
||||
@@ -350,10 +255,7 @@ impl DocApiBackend for MockBackend {
|
||||
Ok(())
|
||||
}
|
||||
fn viewport_view(&self, id: ObjectId) -> ApiResult<([f64; 3], f64)> {
|
||||
self.viewport_views
|
||||
.get(&id)
|
||||
.copied()
|
||||
.ok_or(ApiError::UnknownId(id))
|
||||
self.viewport_views.get(&id).copied().ok_or(ApiError::UnknownId(id))
|
||||
}
|
||||
fn add_vertex(&mut self, id: ObjectId, _at: usize, _point: [f64; 3]) -> ApiResult<()> {
|
||||
if self.entity_exists(id) {
|
||||
@@ -369,10 +271,7 @@ impl DocApiBackend for MockBackend {
|
||||
fn get_entity(&mut self, id: ObjectId) -> ApiResult<EntityView> {
|
||||
let kind = self.kinds.get(&id).ok_or(ApiError::UnknownId(id))?.clone();
|
||||
let bounds = self.bodies.get(&id).and_then(|b| {
|
||||
cadkernel::brep::body_bounds(b).map(|bb| Aabb {
|
||||
min: bb.min,
|
||||
max: bb.max,
|
||||
})
|
||||
cadkernel::brep::body_bounds(b).map(|bb| Aabb { min: bb.min, max: bb.max })
|
||||
});
|
||||
Ok(EntityView { id, kind, bounds })
|
||||
}
|
||||
@@ -387,9 +286,8 @@ impl DocApiBackend for MockBackend {
|
||||
z_axis: placement.z_axis,
|
||||
origin: placement.origin,
|
||||
};
|
||||
let moved = cadkernel::brep::transform(&body, &place).ok_or_else(|| {
|
||||
ApiError::geometry(GeometryErrorKind::InvalidInput, "transform failed")
|
||||
})?;
|
||||
let moved = cadkernel::brep::transform(&body, &place)
|
||||
.ok_or_else(|| ApiError::geometry(GeometryErrorKind::InvalidInput, "transform failed"))?;
|
||||
self.bodies.insert(id, moved);
|
||||
}
|
||||
Ok(())
|
||||
@@ -402,10 +300,7 @@ impl DocApiBackend for MockBackend {
|
||||
if let Some(body) = self.bodies.get(&id) {
|
||||
let bb = cadkernel::brep::body_bounds(body)
|
||||
.ok_or_else(|| ApiError::geometry(GeometryErrorKind::Empty, "no bounds"))?;
|
||||
return Ok(Aabb {
|
||||
min: bb.min,
|
||||
max: bb.max,
|
||||
});
|
||||
return Ok(Aabb { min: bb.min, max: bb.max });
|
||||
}
|
||||
if let Some(spec) = self.curves.get(&id) {
|
||||
return Ok(curve_bounds(spec));
|
||||
|
||||
Reference in new issue
Block a user