Added method for snapping items to grid. Also added a pour method.
This commit is contained in:
parent
d0596cb0f9
commit
9e40647581
|
|
@ -34,6 +34,26 @@ impl KiCadClient {
|
||||||
let _ = response_payload_as_any(response, RES_PROTOBUF_EMPTY)?;
|
let _ = response_payload_as_any(response, RES_PROTOBUF_EMPTY)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Rebuilds fill geometry for every zone on the current board.
|
||||||
|
pub async fn refill_all_zones(&self) -> Result<(), KiCadError> {
|
||||||
|
let zones = self.get_all_pcb_items_raw().await?;
|
||||||
|
let mut ids: Vec<String> = Vec::new();
|
||||||
|
for (_type_code, items) in zones {
|
||||||
|
for any in items {
|
||||||
|
if any.type_url.ends_with("kiapi.board.types.Zone") {
|
||||||
|
let wrapper = crate::model::item::Item::from_any(any);
|
||||||
|
if let Ok(Some(id)) = wrapper.kiid() {
|
||||||
|
ids.push(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ids.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
self.refill_zones(ids).await
|
||||||
|
}
|
||||||
/// Returns pad polygon responses as raw protobuf payloads.
|
/// Returns pad polygon responses as raw protobuf payloads.
|
||||||
pub async fn get_pad_shape_as_polygon_raw(
|
pub async fn get_pad_shape_as_polygon_raw(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
||||||
|
|
@ -244,6 +244,81 @@ impl Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Snaps all positional coordinates of this item to the nearest multiple of the grid.
|
||||||
|
///
|
||||||
|
/// `grid_x_nm` / `grid_y_nm` are the grid step in nanometres. `grid_x_nm` / `grid_y_nm` of
|
||||||
|
/// `0` or below leaves that axis unchanged.
|
||||||
|
///
|
||||||
|
/// Returns `Ok(true)` if the item's bytes were rewritten. Unsupported kinds (Zone, Dimension,
|
||||||
|
/// Field, Group, ReferenceImage, Unknown) return `Ok(false)`.
|
||||||
|
pub fn snap_position(&mut self, grid_x_nm: i64, grid_y_nm: i64) -> Result<bool, KiCadError> {
|
||||||
|
let gx = grid_x_nm;
|
||||||
|
let gy = grid_y_nm;
|
||||||
|
let value = self.raw.value.as_slice();
|
||||||
|
let (new_bytes, mutated) = match self.kind() {
|
||||||
|
ItemKind::Track => {
|
||||||
|
let mut m = bt::Track::decode(value).map_err(decode_err)?;
|
||||||
|
snap_opt_v2(&mut m.start, gx, gy);
|
||||||
|
snap_opt_v2(&mut m.end, gx, gy);
|
||||||
|
(m.encode_to_vec(), true)
|
||||||
|
}
|
||||||
|
ItemKind::Arc => {
|
||||||
|
let mut m = bt::Arc::decode(value).map_err(decode_err)?;
|
||||||
|
snap_opt_v2(&mut m.start, gx, gy);
|
||||||
|
snap_opt_v2(&mut m.mid, gx, gy);
|
||||||
|
snap_opt_v2(&mut m.end, gx, gy);
|
||||||
|
(m.encode_to_vec(), true)
|
||||||
|
}
|
||||||
|
ItemKind::Via => {
|
||||||
|
let mut m = bt::Via::decode(value).map_err(decode_err)?;
|
||||||
|
snap_opt_v2(&mut m.position, gx, gy);
|
||||||
|
(m.encode_to_vec(), true)
|
||||||
|
}
|
||||||
|
ItemKind::FootprintInstance => {
|
||||||
|
let mut m = bt::FootprintInstance::decode(value).map_err(decode_err)?;
|
||||||
|
snap_opt_v2(&mut m.position, gx, gy);
|
||||||
|
(m.encode_to_vec(), true)
|
||||||
|
}
|
||||||
|
ItemKind::Pad => {
|
||||||
|
let mut m = bt::Pad::decode(value).map_err(decode_err)?;
|
||||||
|
snap_opt_v2(&mut m.position, gx, gy);
|
||||||
|
(m.encode_to_vec(), true)
|
||||||
|
}
|
||||||
|
ItemKind::BoardGraphicShape => {
|
||||||
|
let mut m = bt::BoardGraphicShape::decode(value).map_err(decode_err)?;
|
||||||
|
if let Some(shape) = m.shape.as_mut() {
|
||||||
|
snap_graphic_shape(shape, gx, gy);
|
||||||
|
}
|
||||||
|
(m.encode_to_vec(), true)
|
||||||
|
}
|
||||||
|
ItemKind::BoardText => {
|
||||||
|
let mut m = bt::BoardText::decode(value).map_err(decode_err)?;
|
||||||
|
if let Some(t) = m.text.as_mut() {
|
||||||
|
snap_opt_v2(&mut t.position, gx, gy);
|
||||||
|
}
|
||||||
|
(m.encode_to_vec(), true)
|
||||||
|
}
|
||||||
|
ItemKind::BoardTextBox => {
|
||||||
|
let mut m = bt::BoardTextBox::decode(value).map_err(decode_err)?;
|
||||||
|
if let Some(tb) = m.textbox.as_mut() {
|
||||||
|
snap_opt_v2(&mut tb.top_left, gx, gy);
|
||||||
|
snap_opt_v2(&mut tb.bottom_right, gx, gy);
|
||||||
|
}
|
||||||
|
(m.encode_to_vec(), true)
|
||||||
|
}
|
||||||
|
ItemKind::Zone
|
||||||
|
| ItemKind::Dimension
|
||||||
|
| ItemKind::Field
|
||||||
|
| ItemKind::Group
|
||||||
|
| ItemKind::ReferenceImage
|
||||||
|
| ItemKind::Unknown(_) => (Vec::new(), false),
|
||||||
|
};
|
||||||
|
if mutated {
|
||||||
|
self.raw.value = new_bytes;
|
||||||
|
}
|
||||||
|
Ok(mutated)
|
||||||
|
}
|
||||||
|
|
||||||
/// Builds a new `Group` item wrapping the given member KIIDs.
|
/// Builds a new `Group` item wrapping the given member KIIDs.
|
||||||
///
|
///
|
||||||
/// The returned `Item` has no `id` set, so `CreateItems` assigns a
|
/// The returned `Item` has no `id` set, so `CreateItems` assigns a
|
||||||
|
|
@ -306,6 +381,102 @@ fn decode_err(e: prost::DecodeError) -> KiCadError {
|
||||||
KiCadError::ProtobufDecode(e.to_string())
|
KiCadError::ProtobufDecode(e.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn snap_coord(v: i64, grid: i64) -> i64 {
|
||||||
|
if grid <= 0 { return v; }
|
||||||
|
let q = v.div_euclid(grid);
|
||||||
|
let r = v.rem_euclid(grid);
|
||||||
|
if r * 2 >= grid { (q + 1) * grid } else { q * grid }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn snap_opt_v2(
|
||||||
|
v: &mut Option<crate::proto::kiapi::common::types::Vector2>,
|
||||||
|
gx: i64,
|
||||||
|
gy: i64,
|
||||||
|
) {
|
||||||
|
if let Some(p) = v.as_mut() {
|
||||||
|
p.x_nm = snap_coord(p.x_nm, gx);
|
||||||
|
p.y_nm = snap_coord(p.y_nm, gy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn snap_graphic_shape(
|
||||||
|
shape: &mut crate::proto::kiapi::common::types::GraphicShape,
|
||||||
|
gx: i64,
|
||||||
|
gy: i64,
|
||||||
|
) {
|
||||||
|
use crate::proto::kiapi::common::types::graphic_shape::Geometry;
|
||||||
|
use crate::proto::kiapi::common::types::poly_line_node::Geometry as NodeGeom;
|
||||||
|
if let Some(geo) = shape.geometry.as_mut() {
|
||||||
|
match geo {
|
||||||
|
Geometry::Segment(s) => {
|
||||||
|
snap_opt_v2(&mut s.start, gx, gy);
|
||||||
|
snap_opt_v2(&mut s.end, gx, gy);
|
||||||
|
}
|
||||||
|
Geometry::Rectangle(r) => {
|
||||||
|
snap_opt_v2(&mut r.top_left, gx, gy);
|
||||||
|
snap_opt_v2(&mut r.bottom_right, gx, gy);
|
||||||
|
}
|
||||||
|
Geometry::Arc(a) => {
|
||||||
|
snap_opt_v2(&mut a.start, gx, gy);
|
||||||
|
snap_opt_v2(&mut a.mid, gx, gy);
|
||||||
|
snap_opt_v2(&mut a.end, gx, gy);
|
||||||
|
}
|
||||||
|
Geometry::Circle(c) => {
|
||||||
|
snap_opt_v2(&mut c.center, gx, gy);
|
||||||
|
snap_opt_v2(&mut c.radius_point, gx, gy);
|
||||||
|
}
|
||||||
|
Geometry::Polygon(polyset) => {
|
||||||
|
for poly in polyset.polygons.iter_mut() {
|
||||||
|
if let Some(outline) = poly.outline.as_mut() {
|
||||||
|
snap_polyline_nodes(&mut outline.nodes, gx, gy);
|
||||||
|
}
|
||||||
|
for h in poly.holes.iter_mut() {
|
||||||
|
snap_polyline_nodes(&mut h.nodes, gx, gy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Geometry::Bezier(b) => {
|
||||||
|
snap_opt_v2(&mut b.start, gx, gy);
|
||||||
|
snap_opt_v2(&mut b.control1, gx, gy);
|
||||||
|
snap_opt_v2(&mut b.control2, gx, gy);
|
||||||
|
snap_opt_v2(&mut b.end, gx, gy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn snap_polyline_nodes(
|
||||||
|
nodes: &mut [crate::proto::kiapi::common::types::PolyLineNode],
|
||||||
|
gx: i64,
|
||||||
|
gy: i64,
|
||||||
|
) {
|
||||||
|
for node in nodes.iter_mut() {
|
||||||
|
if let Some(g) = node.geometry.as_mut() {
|
||||||
|
match g {
|
||||||
|
NodeGeom::Point(p) => {
|
||||||
|
p.x_nm = snap_coord(p.x_nm, gx);
|
||||||
|
p.y_nm = snap_coord(p.y_nm, gy);
|
||||||
|
}
|
||||||
|
NodeGeom::Arc(a) => {
|
||||||
|
if let Some(p) = a.start.as_mut() {
|
||||||
|
p.x_nm = snap_coord(p.x_nm, gx);
|
||||||
|
p.y_nm = snap_coord(p.y_nm, gy);
|
||||||
|
}
|
||||||
|
if let Some(p) = a.mid.as_mut() {
|
||||||
|
p.x_nm = snap_coord(p.x_nm, gx);
|
||||||
|
p.y_nm = snap_coord(p.y_nm, gy);
|
||||||
|
}
|
||||||
|
if let Some(p) = a.end.as_mut() {
|
||||||
|
p.x_nm = snap_coord(p.x_nm, gx);
|
||||||
|
p.y_nm = snap_coord(p.y_nm, gy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn unsupported(op: &str, kind: ItemKind) -> KiCadError {
|
fn unsupported(op: &str, kind: ItemKind) -> KiCadError {
|
||||||
KiCadError::InvalidResponse {
|
KiCadError::InvalidResponse {
|
||||||
reason: format!("{op} not supported for {}", kind.type_name()),
|
reason: format!("{op} not supported for {}", kind.type_name()),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue