mirror of https://codeberg.org/topola/topola.git
[WIP]
This commit is contained in:
parent
9c007a8ccb
commit
7b16328a6c
|
|
@ -54,7 +54,7 @@ impl From<RatvertexIndex> for crate::layout::NodeIndex {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct RatvertexWeight {
|
pub struct RatvertexWeight {
|
||||||
vertex: RatvertexIndex,
|
pub(crate) vertex: RatvertexIndex,
|
||||||
pub pos: Point,
|
pub pos: Point,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
use petgraph::stable_graph::NodeIndex;
|
use petgraph::stable_graph::NodeIndex;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{drawing::Drawing, graph::GetPetgraphIndex};
|
use crate::{drawing::Drawing, graph::GetPetgraphIndex};
|
||||||
|
|
||||||
|
|
@ -89,7 +90,7 @@ macro_rules! impl_loose_weight {
|
||||||
// TODO: This enum shouldn't exist: we shouldn't be carrying the tag around like this. Instead we
|
// TODO: This enum shouldn't exist: we shouldn't be carrying the tag around like this. Instead we
|
||||||
// should be getting it from the graph when it's needed.
|
// should be getting it from the graph when it's needed.
|
||||||
#[enum_dispatch(GetPetgraphIndex, MakePrimitive)]
|
#[enum_dispatch(GetPetgraphIndex, MakePrimitive)]
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||||
pub enum PrimitiveIndex {
|
pub enum PrimitiveIndex {
|
||||||
FixedDot(FixedDotIndex),
|
FixedDot(FixedDotIndex),
|
||||||
LooseDot(LooseDotIndex),
|
LooseDot(LooseDotIndex),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Topola contributors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
//! A work-in-progress brute-force routing implementation
|
||||||
|
//!
|
||||||
|
//! This should always (except in pathological cases like a non-planar ratsnest)
|
||||||
|
//! be able to find an optimal solution, but potentially require extremely long
|
||||||
|
//! run/walltime to do so. It is intended as a benchmark for heuristic approximations
|
||||||
|
//! of such optimal routing (to compare to potentially suboptimal routing).
|
||||||
|
|
||||||
|
pub mod topo_navmesh;
|
||||||
|
|
@ -0,0 +1,361 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Topola contributors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
//! A topological navmesh implmentation
|
||||||
|
// idea: see issue #132
|
||||||
|
|
||||||
|
use bimap::BiMap;
|
||||||
|
use geo::Point;
|
||||||
|
use petgraph::graph::{NodeIndex, UnGraph};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use spade::HasPosition;
|
||||||
|
|
||||||
|
use crate::{autorouter::ratsnest::Ratsnest, layout::NodeIndex as LayoutNodeIndex};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
pub struct NodeWeight {
|
||||||
|
/// Position of a node. Warning: multiple nodes might have the same position
|
||||||
|
pub pos: Point,
|
||||||
|
|
||||||
|
/// can we pass through this point when constructing a route?
|
||||||
|
///
|
||||||
|
/// e.g. primal nodes are not passable, nodes used by etched paths are not passable,
|
||||||
|
/// the remaining dual nodes are passable.
|
||||||
|
pub is_passable: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
|
pub struct EdgeWeight<P> {
|
||||||
|
/// indicates if this is part of an etched path (`P` is the type of the path index)
|
||||||
|
pub path: Option<P>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A topological navmesh,
|
||||||
|
/// built upon the merging of the primary and dual graph,
|
||||||
|
/// and with an operation to create barriers.
|
||||||
|
///
|
||||||
|
/// This is basically a planar graph embedding, and is used for enumeration of such embeddings.
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
pub struct Navmesh<P> {
|
||||||
|
// a merging of the primary and dual graph
|
||||||
|
graph: UnGraph<NodeWeight, EdgeWeight<P>>,
|
||||||
|
|
||||||
|
// association between primary graph and this one
|
||||||
|
primals: BiMap<LayoutNodeIndex, NodeIndex>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trianvertices are the vertices of the triangulation before it is converted
|
||||||
|
/// to the navmesh.
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
struct Trianvertex<T: geo::CoordNum> {
|
||||||
|
pub idx: LayoutNodeIndex,
|
||||||
|
pub pos: Point<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: geo::CoordNum + spade::SpadeNum> HasPosition for Trianvertex<T> {
|
||||||
|
type Scalar = T;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn position(&self) -> spade::Point2<T> {
|
||||||
|
let pos = self.pos.0.clone();
|
||||||
|
spade::Point2 { x: pos.x, y: pos.y }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn voronoi_vertex_get_weight<V, DE, UE, F>(
|
||||||
|
vertex: &spade::handles::VoronoiVertex<'_, V, DE, UE, F>,
|
||||||
|
) -> NodeWeight
|
||||||
|
where
|
||||||
|
V: HasPosition<Scalar = f64>,
|
||||||
|
{
|
||||||
|
fn outer_halfspace_get_weight<V: HasPosition<Scalar = f64>, DE, UE, F>(
|
||||||
|
face: &spade::handles::DirectedVoronoiEdge<'_, V, DE, UE, F>,
|
||||||
|
) -> NodeWeight {
|
||||||
|
let delauney = face.as_delaunay_edge();
|
||||||
|
let from = delauney.from().position();
|
||||||
|
let from = geo::point! { x: from.x, y: from.y };
|
||||||
|
let to = delauney.to().position();
|
||||||
|
let to = geo::point! { x: to.x, y: to.y };
|
||||||
|
let diff = to - from;
|
||||||
|
let orth = geo::point! {
|
||||||
|
x: -diff.y(),
|
||||||
|
y: diff.x()
|
||||||
|
};
|
||||||
|
|
||||||
|
NodeWeight {
|
||||||
|
pos: (from + to + orth) / 2.0,
|
||||||
|
is_passable: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use spade::handles::VoronoiVertex as VV;
|
||||||
|
match vertex {
|
||||||
|
VV::Inner(face) => {
|
||||||
|
let cc = face.circumcenter();
|
||||||
|
NodeWeight {
|
||||||
|
pos: geo::point! { x: cc.x, y: cc.y },
|
||||||
|
is_passable: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VV::Outer(out) => outer_halfspace_get_weight(out),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P> Navmesh<P> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
graph: UnGraph::new_undirected(),
|
||||||
|
primals: BiMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a navmesh based upon a ratsnest
|
||||||
|
pub fn from_ratsnest(ratsnest: &Ratsnest) -> Result<Self, spade::InsertionError> {
|
||||||
|
use spade::Triangulation;
|
||||||
|
let mut triangulation = spade::DelaunayTriangulation::<Trianvertex<f64>, ()>::new();
|
||||||
|
|
||||||
|
let rng = ratsnest.graph();
|
||||||
|
for node in rng.node_indices() {
|
||||||
|
let weight = &rng[node];
|
||||||
|
triangulation.insert(Trianvertex {
|
||||||
|
idx: LayoutNodeIndex::from(weight.vertex),
|
||||||
|
pos: weight.pos,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self::from_triangulation(&triangulation))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a navmesh based upon a triangulation
|
||||||
|
pub fn from_triangulation<T>(triangulation: &T) -> Self
|
||||||
|
where
|
||||||
|
T: spade::Triangulation<Vertex = Trianvertex<f64>>,
|
||||||
|
{
|
||||||
|
let mut this = UnGraph::new_undirected();
|
||||||
|
// `primals` maps between layout node indices and indices in this graph
|
||||||
|
let mut primals = BiMap::with_capacity(triangulation.num_vertices());
|
||||||
|
// `voronoi_verts` maps between dual node indices
|
||||||
|
// (computed from face indices) and our navmesh graph indices
|
||||||
|
let mut voronoi_verts = std::collections::HashMap::<usize, NodeIndex>::with_capacity(
|
||||||
|
triangulation.num_all_faces(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut handle_voronoi_vertex = |this: &mut UnGraph<NodeWeight, EdgeWeight<P>>,
|
||||||
|
vertex: &spade::handles::VoronoiVertex<
|
||||||
|
'_,
|
||||||
|
Trianvertex<f64>,
|
||||||
|
T::DirectedEdge,
|
||||||
|
T::UndirectedEdge,
|
||||||
|
T::Face,
|
||||||
|
>| {
|
||||||
|
use spade::handles::VoronoiVertex as VV;
|
||||||
|
let index = match vertex {
|
||||||
|
VV::Inner(face) => face.index() << 1,
|
||||||
|
VV::Outer(face) => (face.index() << 1) + 1,
|
||||||
|
};
|
||||||
|
*voronoi_verts
|
||||||
|
.entry(index)
|
||||||
|
.or_insert_with(|| this.add_node(voronoi_vertex_get_weight(vertex)))
|
||||||
|
};
|
||||||
|
|
||||||
|
for node in triangulation.vertices() {
|
||||||
|
let graph_idx = this.add_node(NodeWeight {
|
||||||
|
pos: node.data().pos,
|
||||||
|
is_passable: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if primals
|
||||||
|
.insert_no_overwrite(node.data().idx, graph_idx)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
panic!("duplicate layout node index");
|
||||||
|
}
|
||||||
|
|
||||||
|
for edge in node.as_voronoi_face().adjacent_edges() {
|
||||||
|
// to convert dual edges around a node into dual nodes around a node,
|
||||||
|
// we use the dual nodes that the edges point to.
|
||||||
|
let graph_idx2 = handle_voronoi_vertex(&mut this, &edge.to());
|
||||||
|
this.update_edge(graph_idx, graph_idx2, EdgeWeight { path: None });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for edge in triangulation.undirected_voronoi_edges() {
|
||||||
|
let [a, b] = edge.vertices();
|
||||||
|
let gridx_a = handle_voronoi_vertex(&mut this, &a);
|
||||||
|
let gridx_b = handle_voronoi_vertex(&mut this, &b);
|
||||||
|
this.update_edge(gridx_a, gridx_b, EdgeWeight { path: None });
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
graph: this,
|
||||||
|
primals,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn graph(&self) -> &UnGraph<NodeWeight, EdgeWeight<P>> {
|
||||||
|
&self.graph
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn primals(&self) -> &BiMap<LayoutNodeIndex, NodeIndex> {
|
||||||
|
&self.primals
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn neighbors(&self, idx: NodeIndex) -> petgraph::graph::Neighbors<'_, EdgeWeight<P>, u32> {
|
||||||
|
self.graph.neighbors(idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Advance "etching" by a single step.
|
||||||
|
///
|
||||||
|
/// * `prev` is the previous node in the path (if there is any), and possibly
|
||||||
|
/// the companions from the previous step (edges to which should form a grid)
|
||||||
|
/// * `current` is the currently selected node
|
||||||
|
/// * `dest` is the next node in the path (edges to there should be duplicated)
|
||||||
|
fn etch_path_make_companions(
|
||||||
|
&mut self,
|
||||||
|
prev: Option<(NodeIndex, Option<(NodeIndex, NodeIndex)>)>,
|
||||||
|
current: NodeIndex,
|
||||||
|
next: Option<NodeIndex>,
|
||||||
|
) -> Option<(NodeIndex, NodeIndex)> {
|
||||||
|
let node_cur = self.graph.node_weight(current)?.clone();
|
||||||
|
if prev.is_none() && next.is_none() || node_cur.is_passable != true {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
use std::collections::BTreeSet;
|
||||||
|
let cur_pos = node_cur.pos;
|
||||||
|
let mut link_angles: Vec<_> = self
|
||||||
|
.graph
|
||||||
|
.neighbors(current)
|
||||||
|
.map(|i| {
|
||||||
|
(
|
||||||
|
i,
|
||||||
|
self.graph
|
||||||
|
.node_weight(i)
|
||||||
|
.expect("encountered invalid edge endpoint")
|
||||||
|
.pos
|
||||||
|
- cur_pos,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map(|(i, oth_pos_rel)| (i, oth_pos_rel.y().atan2(oth_pos_rel.x())))
|
||||||
|
.collect();
|
||||||
|
link_angles.sort_unstable_by(|a, b| f64::total_cmp(&a.1, &b.1));
|
||||||
|
|
||||||
|
// positions in the list of angles
|
||||||
|
// make `prev` the first item in the link_angles
|
||||||
|
if let Some(xpos) = prev
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|(i, _)| link_angles.iter().position(|(j, _)| i == j))
|
||||||
|
{
|
||||||
|
let mut tmp: Vec<_> = link_angles.drain(..xpos).collect();
|
||||||
|
link_angles.append(&mut tmp);
|
||||||
|
let prev_idx = prev.unwrap().0;
|
||||||
|
// the prev isn't duplicated
|
||||||
|
assert_eq!(link_angles[0].0, prev_idx);
|
||||||
|
assert_eq!(
|
||||||
|
link_angles[1..].iter().position(|(j, _)| &prev_idx == j),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
|
||||||
|
// subtract prev angle from all angles, and get them into `[0, 2π)`
|
||||||
|
let prev_angle = link_angles[0].1;
|
||||||
|
link_angles.iter_mut().for_each(|(_, i)| {
|
||||||
|
*i -= prev_angle;
|
||||||
|
use core::f64::consts::PI;
|
||||||
|
if *i < 0.0 {
|
||||||
|
*i += 2.0 * PI;
|
||||||
|
} else if *i >= 2.0 * PI {
|
||||||
|
*i -= 2.0 * PI;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assert!(link_angles.is_sorted_by(|a, b| &a.1 <= &b.1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// split the list at the next, categorize links into left vs right
|
||||||
|
if let Some(xpos) = next
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|i| link_angles.iter().position(|(j, _)| i == j))
|
||||||
|
{
|
||||||
|
let (lhs, rhs) = link_angles.split_at(xpos);
|
||||||
|
// don't put xpos into either
|
||||||
|
let rhs = &rhs[1..];
|
||||||
|
} else {
|
||||||
|
// split at π
|
||||||
|
let split_point = match link_angles
|
||||||
|
.binary_search_by(|x| f64::total_cmp(&x.1, &core::f64::consts::PI))
|
||||||
|
{
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(x) => x,
|
||||||
|
};
|
||||||
|
let (lhs, rhs) = link_angles.split_at(split_point);
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut link_lhs = BTreeSet::new();
|
||||||
|
let mut link_rhs = BTreeSet::new();
|
||||||
|
let mut link_middle = BTreeSet::new();
|
||||||
|
|
||||||
|
if let Some((prev, prev_links)) = prev {
|
||||||
|
match prev_links {
|
||||||
|
None => {
|
||||||
|
//assert!(link_middle_pre.contains(&prev));
|
||||||
|
link_lhs.insert(prev);
|
||||||
|
link_rhs.insert(prev);
|
||||||
|
link_middle.insert(prev);
|
||||||
|
}
|
||||||
|
Some((old_lhs, old_rhs)) => {
|
||||||
|
//assert!(link_middle_pre.contains(&prev));
|
||||||
|
link_lhs.insert(old_lhs);
|
||||||
|
link_rhs.insert(old_rhs);
|
||||||
|
link_middle.insert(prev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
link_lhs.insert(current);
|
||||||
|
link_rhs.insert(current);
|
||||||
|
|
||||||
|
if let Some(next) = next {
|
||||||
|
link_lhs.insert(next);
|
||||||
|
link_rhs.insert(next);
|
||||||
|
link_middle.insert(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// "etch" a taken route into the navmesh (marking it such that it doesn't get crossed later)
|
||||||
|
/// basically marking the path itself, and also creating new dual paths to the left and right of it
|
||||||
|
///
|
||||||
|
/// @returns `false` if invalid edges or nodes were encountered
|
||||||
|
pub fn etch_path(&mut self, path: &[NodeIndex]) -> bool {
|
||||||
|
if path.len() < 2 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut it = path.windows(2).map(|i| (i[0], i[1]));
|
||||||
|
let mut prev = None;
|
||||||
|
|
||||||
|
for (i0, i1) in it {
|
||||||
|
prev = Some((i0, self.etch_path_make_companions(prev, i0, Some(i1))));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.etch_path_make_companions(prev, *path.last().unwrap(), None);
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn first_node() {
|
||||||
|
let fi = NodeIndex::FIRST;
|
||||||
|
assert!(fi.ty < NodeTy::Compound);
|
||||||
|
assert!(fi.ty < NodeTy::DualInner);
|
||||||
|
assert!(fi.ty < NodeTy::DualOuter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
pub mod astar;
|
pub mod astar;
|
||||||
|
pub mod brute_force;
|
||||||
pub mod draw;
|
pub mod draw;
|
||||||
pub mod navcord;
|
pub mod navcord;
|
||||||
pub mod navcorder;
|
pub mod navcorder;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
(pcb test.dsn
|
||||||
|
(parser
|
||||||
|
(string_quote ")
|
||||||
|
(space_in_quoted_tokens on)
|
||||||
|
(host_cad "KiCad's Pcbnew")
|
||||||
|
(host_version "7.0.9")
|
||||||
|
)
|
||||||
|
(resolution um 10)
|
||||||
|
(unit um)
|
||||||
|
(structure
|
||||||
|
(layer F.Cu
|
||||||
|
(type signal)
|
||||||
|
(property
|
||||||
|
(index 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(layer B.Cu
|
||||||
|
(type signal)
|
||||||
|
(property
|
||||||
|
(index 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(boundary
|
||||||
|
(path pcb 0 61846 -50400 2162.05 -50400 2162.05 -14754.8 61846 -14754.8
|
||||||
|
61846 -50400)
|
||||||
|
)
|
||||||
|
(via "Via[0-1]_800:400_um")
|
||||||
|
(rule
|
||||||
|
(width 600)
|
||||||
|
(clearance 200.1)
|
||||||
|
(clearance 200.1 (type default_smd))
|
||||||
|
(clearance 50 (type smd_smd))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(placement
|
||||||
|
(component Connector_Pin:Pin_D1.0mm_L10.0mm
|
||||||
|
(place REF21 16510.000000 -46990.000000 front 0.000000 (PN Pin_D1.0mm_L10.0mm))
|
||||||
|
(place REF11 53340.000000 -17653.000000 front 0.000000 (PN Pin_D1.0mm_L10.0mm))
|
||||||
|
(place REF31 12700.000000 -40640.000000 front 0.000000 (PN Pin_D1.0mm_L10.0mm))
|
||||||
|
(place REF22 45720.000000 -35560.000000 front 0.000000 (PN Pin_D1.0mm_L10.0mm))
|
||||||
|
(place REF12 10668.000000 -32258.000000 front 0.000000 (PN Pin_D1.0mm_L10.0mm))
|
||||||
|
(place REF32 35560.000000 -24130.000000 front 0.000000 (PN Pin_D1.0mm_L10.0mm))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(library
|
||||||
|
(image Connector_Pin:Pin_D1.0mm_L10.0mm
|
||||||
|
(outline (path signal 120 1251 0 1231.99 -217.234 1175.56 -427.867 1083.4 -625.5
|
||||||
|
958.322 -804.127 804.127 -958.322 625.5 -1083.4 427.867 -1175.56
|
||||||
|
217.234 -1231.99 0 -1251 -217.234 -1231.99 -427.867 -1175.56
|
||||||
|
-625.5 -1083.4 -804.127 -958.322 -958.322 -804.127 -1083.4 -625.5
|
||||||
|
-1175.56 -427.867 -1231.99 -217.234 -1251 0 -1231.99 217.234
|
||||||
|
-1175.56 427.867 -1083.4 625.5 -958.322 804.127 -804.127 958.322
|
||||||
|
-625.5 1083.4 -427.867 1175.56 -217.234 1231.99 0 1251 217.234 1231.99
|
||||||
|
427.867 1175.56 625.5 1083.4 804.127 958.322 958.322 804.127
|
||||||
|
1083.4 625.5 1175.56 427.867 1231.99 217.234 1251 0))
|
||||||
|
(outline (path signal 50 1500 0 1480.58 -240.617 1422.81 -475.002 1328.18 -697.085
|
||||||
|
1199.16 -901.113 1039.09 -1081.8 852.097 -1234.48 643.039 -1355.18
|
||||||
|
417.326 -1440.78 180.805 -1489.06 -60.399 -1498.78 -300.039 -1469.69
|
||||||
|
-531.907 -1402.52 -750 -1299.04 -948.668 -1161.91 -1122.77 -994.684
|
||||||
|
-1267.79 -801.699 -1379.97 -587.95 -1456.41 -358.973 -1495.14 -120.7
|
||||||
|
-1495.14 120.7 -1456.41 358.973 -1379.97 587.95 -1267.79 801.699
|
||||||
|
-1122.77 994.684 -948.668 1161.91 -750 1299.04 -531.907 1402.52
|
||||||
|
-300.039 1469.69 -60.399 1498.78 180.805 1489.06 417.326 1440.78
|
||||||
|
643.039 1355.18 852.097 1234.48 1039.09 1081.8 1199.16 901.113
|
||||||
|
1328.18 697.085 1422.81 475.002 1480.58 240.617 1500 0))
|
||||||
|
(outline (path signal 120 500 0 481.459 -134.898 427.21 -259.792 341.277 -365.418
|
||||||
|
230.033 -443.943 101.728 -489.542 -34.121 -498.834 -167.44 -471.13
|
||||||
|
-288.34 -408.485 -387.856 -315.544 -458.606 -199.201 -495.343 -68.083
|
||||||
|
-495.343 68.083 -458.606 199.201 -387.856 315.544 -288.34 408.485
|
||||||
|
-167.44 471.13 -34.121 498.834 101.728 489.542 230.033 443.943
|
||||||
|
341.277 365.418 427.21 259.792 481.459 134.898 500 0))
|
||||||
|
(outline (path signal 120 1000 0 980.785 -195.09 923.88 -382.683 831.47 -555.57
|
||||||
|
707.107 -707.107 555.57 -831.47 382.683 -923.88 195.09 -980.785
|
||||||
|
0 -1000 -195.09 -980.785 -382.683 -923.88 -555.57 -831.47
|
||||||
|
-707.107 -707.107 -831.47 -555.57 -923.88 -382.683 -980.785 -195.09
|
||||||
|
-1000 0 -980.785 195.09 -923.88 382.683 -831.47 555.57 -707.107 707.107
|
||||||
|
-555.57 831.47 -382.683 923.88 -195.09 980.785 0 1000 195.09 980.785
|
||||||
|
382.683 923.88 555.57 831.47 707.107 707.107 831.47 555.57
|
||||||
|
923.88 382.683 980.785 195.09 1000 0))
|
||||||
|
(pin Round[A]Pad_2000_um 1 0 0)
|
||||||
|
)
|
||||||
|
(padstack Round[A]Pad_2000_um
|
||||||
|
(shape (circle F.Cu 2000))
|
||||||
|
(shape (circle B.Cu 2000))
|
||||||
|
(attach off)
|
||||||
|
)
|
||||||
|
(padstack "Via[0-1]_800:400_um"
|
||||||
|
(shape (circle F.Cu 800))
|
||||||
|
(shape (circle B.Cu 800))
|
||||||
|
(attach off)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(network
|
||||||
|
(net 1
|
||||||
|
(pins REF11-1 REF12-1)
|
||||||
|
)
|
||||||
|
(net 2
|
||||||
|
(pins REF21-1 REF22-1)
|
||||||
|
)
|
||||||
|
(net 3
|
||||||
|
(pins REF31-1 REF32-1)
|
||||||
|
)
|
||||||
|
(class kicad_default "" 1 2 3
|
||||||
|
(circuit
|
||||||
|
(use_via Via[0-1]_800:400_um)
|
||||||
|
)
|
||||||
|
(rule
|
||||||
|
(width 600)
|
||||||
|
(clearance 200.1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(class test unconnected
|
||||||
|
(circuit
|
||||||
|
(use_via Via[0-1]_800:400_um)
|
||||||
|
)
|
||||||
|
(rule
|
||||||
|
(width 300)
|
||||||
|
(clearance 500.1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(wiring
|
||||||
|
(wire (path F.Cu 600 20000 -50000 60000 -50000)(net unconnected)(type route))
|
||||||
|
(wire (path F.Cu 600 60000 -20000 40000 -20000 40000 -40000)(net unconnected)(type route))
|
||||||
|
(wire (path F.Cu 600 50000 -40000 50000 -30000)(net unconnected)(type route))
|
||||||
|
(wire (path F.Cu 600 60000 -50000 60000 -20000)(net unconnected)(type route))
|
||||||
|
(wire (path F.Cu 600 20000 -20000 20000 -50000)(net unconnected)(type route))
|
||||||
|
(wire (path F.Cu 600 40000 -40000 50000 -40000)(net unconnected)(type route))
|
||||||
|
(via "Via[0-1]_800:400_um" 20000 -50000 (net unconnected)(type route))
|
||||||
|
(via "Via[0-1]_800:400_um" 60000 -50000 (net unconnected)(type route))
|
||||||
|
(via "Via[0-1]_800:400_um" 50000 -40000 (net unconnected)(type route))
|
||||||
|
(via "Via[0-1]_800:400_um" 40000 -20000 (net unconnected)(type route))
|
||||||
|
(via "Via[0-1]_800:400_um" 20000 -20000 (net unconnected)(type route))
|
||||||
|
(via "Via[0-1]_800:400_um" 40000 -40000 (net unconnected)(type route))
|
||||||
|
(via "Via[0-1]_800:400_um" 60000 -20000 (net unconnected)(type route))
|
||||||
|
(via "Via[0-1]_800:400_um" 50000 -30000 (net unconnected)(type route))
|
||||||
|
)
|
||||||
|
)
|
||||||
Loading…
Reference in New Issue