mirror of https://codeberg.org/topola/topola.git
sdl2-bench: remove the SDL2 bench (aka. SDL2 demo) entirely
First, from now on I'm going to call the "SDL2 demo" the "SDL2 bench", as a demo is software that exists to demonstrate, whereas its purpose lately has been only fast prototyping, as we switched to make all demo animations in the Egui port anyway. Second, I'm removing the SDL2 bench anyway as it's a maintenance burden that lost its utility. It's also affected by a bug in Pathfinder that makes it impossible to zoom beyond a certain threshold which would require someone to dig into Pathfinder's codebase, a task I don't think anyone is interested in.
This commit is contained in:
parent
1e21a501d8
commit
cd6c9fbe76
11
Cargo.toml
11
Cargo.toml
|
|
@ -16,15 +16,10 @@ required-features = ["cli"]
|
|||
name = "topola-egui"
|
||||
required-features = ["egui"]
|
||||
|
||||
[[bin]]
|
||||
name = "topola-sdl2-demo"
|
||||
required-features = ["sdl2"]
|
||||
|
||||
[features]
|
||||
default = ["disable_contracts"]
|
||||
cli = ["dep:clap"]
|
||||
egui = ["dep:eframe", "dep:egui", "dep:rfd", "dep:futures"]
|
||||
sdl2 = ["dep:sdl2", "dep:gl", "dep:pathfinder_canvas", "dep:pathfinder_geometry", "dep:pathfinder_gl", "dep:pathfinder_renderer", "dep:pathfinder_resources"]
|
||||
disable_contracts = ["contracts/disable_contracts"]
|
||||
|
||||
[dependencies]
|
||||
|
|
@ -75,12 +70,6 @@ version = "0.14.0"
|
|||
optional = true
|
||||
version = "0.3.30"
|
||||
|
||||
[dependencies.sdl2]
|
||||
optional = true
|
||||
version = "0.35.2"
|
||||
default-features = false
|
||||
features = ["bundled"]
|
||||
|
||||
[dependencies.gl]
|
||||
optional = true
|
||||
version = "0.14.0"
|
||||
|
|
|
|||
10
INSTALL.md
10
INSTALL.md
|
|
@ -44,16 +44,6 @@ To build and open Topola in your browser, run
|
|||
|
||||
trunk serve
|
||||
|
||||
### SDL2 demo
|
||||
|
||||
Optionally, for shorter build times you may build the SDL2 demo instead
|
||||
of the Egui port:
|
||||
|
||||
cargo build --features sdl2 --bin topola-sdl2-demo
|
||||
cargo run --features sdl2 --bin topola-sdl2-demo
|
||||
|
||||
The downside is that the SDL2 demo's user interface is highly incomplete.
|
||||
|
||||
### Automated tests
|
||||
|
||||
Topola has automated tests to make sure its basic functionalities work.
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
use std::{
|
||||
fs::File,
|
||||
sync::{mpsc::Sender, Arc, Mutex},
|
||||
path::Path,
|
||||
sync::{mpsc::Sender, Arc, Mutex},
|
||||
};
|
||||
|
||||
use topola::{
|
||||
autorouter::invoker::{
|
||||
Command, Execute, ExecuteWithStatus, Invoker, InvokerError, InvokerStatus,
|
||||
},
|
||||
specctra::{mesadata::SpecctraMesadata, design::SpecctraDesign},
|
||||
specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
|
@ -45,8 +45,11 @@ impl Top {
|
|||
) -> Result<(), InvokerError> {
|
||||
let mut open_design =
|
||||
Trigger::new(Action::new("Open", egui::Modifiers::CTRL, egui::Key::O));
|
||||
let mut export_session =
|
||||
Trigger::new(Action::new("Export session file", egui::Modifiers::CTRL, egui::Key::S));
|
||||
let mut export_session = Trigger::new(Action::new(
|
||||
"Export session file",
|
||||
egui::Modifiers::CTRL,
|
||||
egui::Key::S,
|
||||
));
|
||||
let mut import_history = Trigger::new(Action::new(
|
||||
"Import history",
|
||||
egui::Modifiers::CTRL,
|
||||
|
|
|
|||
|
|
@ -1,382 +0,0 @@
|
|||
extern crate sdl2;
|
||||
|
||||
mod painter;
|
||||
|
||||
macro_rules! dbg_dot {
|
||||
($graph:expr) => {
|
||||
use petgraph::dot::Dot;
|
||||
println!("{:?}", Dot::new(&$graph));
|
||||
};
|
||||
}
|
||||
|
||||
use geo::point;
|
||||
use painter::Painter;
|
||||
use petgraph::graph::NodeIndex;
|
||||
use petgraph::visit::{EdgeRef, IntoEdgeReferences};
|
||||
use topola::autorouter::selection::Selection;
|
||||
use topola::autorouter::{Autorouter, AutorouterStatus};
|
||||
use topola::drawing::dot::FixedDotWeight;
|
||||
use topola::drawing::graph::{MakePrimitive, PrimitiveIndex};
|
||||
use topola::drawing::primitive::MakePrimitiveShape;
|
||||
use topola::drawing::rules::{AccessRules, Conditions};
|
||||
use topola::drawing::seg::FixedSegWeight;
|
||||
use topola::drawing::{Infringement, LayoutException};
|
||||
use topola::geometry::primitive::{AccessPrimitiveShape, PrimitiveShape};
|
||||
use topola::geometry::shape::AccessShape;
|
||||
use topola::layout::poly::MakePolyShape;
|
||||
use topola::layout::Layout;
|
||||
use topola::router::draw::DrawException;
|
||||
use topola::router::navmesh::Navmesh;
|
||||
use topola::router::tracer::Tracer;
|
||||
use topola::specctra::design::SpecctraDesign;
|
||||
use topola::specctra::mesadata::SpecctraMesadata;
|
||||
|
||||
use sdl2::event::Event;
|
||||
use sdl2::keyboard::Keycode;
|
||||
use sdl2::video::{GLProfile, Window};
|
||||
use sdl2::EventPump;
|
||||
|
||||
use pathfinder_canvas::{Canvas, CanvasFontContext, ColorU};
|
||||
use pathfinder_geometry::vector::{vec2f, vec2i, Vector2F};
|
||||
use pathfinder_gl::{GLDevice, GLVersion};
|
||||
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
||||
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
||||
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererMode, RendererOptions};
|
||||
use pathfinder_renderer::gpu::renderer::Renderer;
|
||||
use pathfinder_renderer::options::BuildOptions;
|
||||
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::time::Duration;
|
||||
|
||||
use topola::math::Circle;
|
||||
use topola::router::Router;
|
||||
|
||||
struct SimpleRules {
|
||||
net_clearances: HashMap<(usize, usize), f64>,
|
||||
}
|
||||
|
||||
impl AccessRules for SimpleRules {
|
||||
fn clearance(&self, conditions1: &Conditions, conditions2: &Conditions) -> f64 {
|
||||
if let (Some(net1), Some(net2)) = (conditions1.maybe_net, conditions2.maybe_net) {
|
||||
*self.net_clearances.get(&(net1, net2)).unwrap_or(&10.0)
|
||||
} else {
|
||||
10.0
|
||||
}
|
||||
}
|
||||
|
||||
fn largest_clearance(&self, maybe_net: Option<usize>) -> f64 {
|
||||
let mut highest_clearance = 0.0;
|
||||
|
||||
if let Some(net) = maybe_net {
|
||||
for ((net1, net2), clearance) in self.net_clearances.iter() {
|
||||
if *net1 == net || *net2 == net {
|
||||
highest_clearance = *clearance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
highest_clearance
|
||||
}
|
||||
}
|
||||
|
||||
// Clunky enum to work around borrow checker.
|
||||
enum RouterOrLayout<'a, R: AccessRules> {
|
||||
Router(&'a mut Router<'a, R>),
|
||||
Layout(&'a Layout<R>),
|
||||
}
|
||||
|
||||
fn main() -> Result<(), anyhow::Error> {
|
||||
let sdl_context = sdl2::init().unwrap();
|
||||
let video_subsystem = sdl_context.video().unwrap();
|
||||
|
||||
let gl_attr = video_subsystem.gl_attr();
|
||||
gl_attr.set_context_profile(GLProfile::Core);
|
||||
gl_attr.set_context_version(4, 0);
|
||||
|
||||
let window = video_subsystem
|
||||
.window("Topola demo", 800, 600)
|
||||
.opengl()
|
||||
.position_centered()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let _context = window.gl_create_context().unwrap();
|
||||
gl::load_with(|name| video_subsystem.gl_get_proc_address(name) as *const _);
|
||||
|
||||
// doing this later (after pathfinder assumes control of the context) would be a bad idea
|
||||
// but for the early clear it's simpler than passing a blank canvas to pathfinder
|
||||
unsafe {
|
||||
gl::ClearColor(0.0, 0.0, 0.0, 1.0);
|
||||
gl::Clear(gl::COLOR_BUFFER_BIT);
|
||||
}
|
||||
window.gl_swap_window();
|
||||
|
||||
// XXX: not sure if this automatically fallbacks if we get a GL3 context
|
||||
// or if we have to detect it and/or retry
|
||||
let device = GLDevice::new(GLVersion::GL4, 0);
|
||||
|
||||
let mode = RendererMode::default_for_device(&device);
|
||||
let options = RendererOptions {
|
||||
dest: DestFramebuffer::full_window(vec2i(800, 600)),
|
||||
background_color: Some(ColorU::black().to_f32()),
|
||||
//show_debug_ui: true,
|
||||
..RendererOptions::default()
|
||||
};
|
||||
let resource_loader = EmbeddedResourceLoader::new();
|
||||
let mut renderer = Renderer::new(device, &resource_loader, mode, options);
|
||||
let font_context = CanvasFontContext::from_system_source();
|
||||
|
||||
// TODO: make a type like this wrapping the details of pathfinder
|
||||
// so we don't pass so many arguments to render_times()
|
||||
//let mut canvas = window.into_canvas().build().unwrap();
|
||||
|
||||
let mut event_pump = sdl_context.event_pump().unwrap();
|
||||
let _i = 0;
|
||||
/*let mut router = Router::new(Layout::new(SimpleRules {
|
||||
net_clearances: HashMap::from([
|
||||
((1, 2), 8.0),
|
||||
((2, 1), 8.0),
|
||||
((2, 3), 3.0),
|
||||
((3, 2), 3.0),
|
||||
((3, 4), 15.0),
|
||||
((4, 3), 15.0),
|
||||
]),
|
||||
}));*/
|
||||
|
||||
let design_file = File::open(
|
||||
"tests/single_layer/data/de9_tht_female_to_tht_female/de9_tht_female_to_tht_female.dsn",
|
||||
)
|
||||
.unwrap();
|
||||
let design_bufread = BufReader::new(design_file);
|
||||
let design = SpecctraDesign::load(design_bufread)?;
|
||||
let board = design.make_board();
|
||||
|
||||
let mut view = View {
|
||||
pan: vec2f(-80000.0, -60000.0),
|
||||
zoom: 0.005,
|
||||
};
|
||||
|
||||
render_times(
|
||||
&mut event_pump,
|
||||
&window,
|
||||
&mut renderer,
|
||||
&font_context,
|
||||
&mut view,
|
||||
RouterOrLayout::Layout(board.layout()),
|
||||
None,
|
||||
None,
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
-1,
|
||||
);
|
||||
|
||||
let mut autorouter = Autorouter::new(board).unwrap();
|
||||
if let Ok(mut autoroute) = autorouter.autoroute_walk(&Selection::new()) {
|
||||
loop {
|
||||
let status = match autoroute.step(&mut autorouter) {
|
||||
Ok(status) => status,
|
||||
Err(err) => break,
|
||||
};
|
||||
|
||||
if let AutorouterStatus::Finished = status {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// these are both on net 1 in the test file
|
||||
/*let _ = router.route_band(
|
||||
dot_indices[1],
|
||||
dot_indices[2],
|
||||
3.0,
|
||||
)?;*/
|
||||
|
||||
render_times(
|
||||
&mut event_pump,
|
||||
&window,
|
||||
&mut renderer,
|
||||
&font_context,
|
||||
&mut view,
|
||||
RouterOrLayout::Layout(autorouter.board().layout()),
|
||||
None,
|
||||
None,
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
-1,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct View {
|
||||
pan: Vector2F,
|
||||
zoom: f32,
|
||||
}
|
||||
|
||||
fn render_times(
|
||||
event_pump: &mut EventPump,
|
||||
window: &Window,
|
||||
renderer: &mut Renderer<GLDevice>,
|
||||
font_context: &CanvasFontContext,
|
||||
view: &mut View,
|
||||
mut router_or_layout: RouterOrLayout<impl AccessRules>,
|
||||
_unused: Option<()>,
|
||||
mut maybe_navmesh: Option<Navmesh>,
|
||||
path: &[NodeIndex<usize>],
|
||||
ghosts: &[PrimitiveShape],
|
||||
highlighteds: &[PrimitiveIndex],
|
||||
times: i64,
|
||||
) {
|
||||
let mut i = 0;
|
||||
|
||||
'running: loop {
|
||||
for event in event_pump.poll_iter() {
|
||||
match event {
|
||||
Event::Quit { .. }
|
||||
| Event::KeyDown {
|
||||
keycode: Some(Keycode::Escape),
|
||||
..
|
||||
} => break 'running,
|
||||
Event::MouseWheel { y, .. } => {
|
||||
view.zoom *= f32::powf(1.4, y as f32);
|
||||
}
|
||||
Event::MouseMotion {
|
||||
xrel,
|
||||
yrel,
|
||||
mousestate,
|
||||
..
|
||||
} => {
|
||||
if mousestate.left() {
|
||||
view.pan += vec2f(xrel as f32, yrel as f32) / view.zoom;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
renderer.options_mut().background_color = Some(ColorU::new(0, 10, 35, 255).to_f32());
|
||||
|
||||
let window_size = window.size();
|
||||
let mut canvas = Canvas::new(vec2f(window_size.0 as f32, window_size.1 as f32))
|
||||
.get_context_2d(font_context.clone());
|
||||
|
||||
let center = vec2f(400.0, 300.0);
|
||||
canvas.translate(center);
|
||||
canvas.scale(vec2f(view.zoom, view.zoom));
|
||||
canvas.translate(-center + view.pan);
|
||||
|
||||
let mut painter = Painter::new(&mut canvas);
|
||||
|
||||
let layout = match router_or_layout {
|
||||
RouterOrLayout::Router(ref mut router) => {
|
||||
let state = event_pump.mouse_state();
|
||||
|
||||
/*if let Some(band) = maybe_band {
|
||||
router
|
||||
.reroute_band(
|
||||
band,
|
||||
point! {x: state.x() as f64, y: state.y() as f64},
|
||||
3.0,
|
||||
)
|
||||
.ok();
|
||||
maybe_navmesh = None;
|
||||
}*/
|
||||
|
||||
router.layout()
|
||||
}
|
||||
RouterOrLayout::Layout(ref layout) => layout.clone(),
|
||||
};
|
||||
|
||||
for node in layout.drawing().layer_primitive_nodes(1) {
|
||||
let color = if highlighteds.contains(&node) {
|
||||
ColorU::new(100, 100, 255, 255)
|
||||
} else {
|
||||
ColorU::new(52, 52, 200, 255)
|
||||
};
|
||||
|
||||
let shape = node.primitive(layout.drawing()).shape();
|
||||
painter.paint_primitive(&shape, color, view.zoom);
|
||||
}
|
||||
|
||||
for poly in layout.layer_poly_nodes(1) {
|
||||
painter.paint_polygon(
|
||||
&layout.poly(poly).shape().polygon,
|
||||
ColorU::new(52, 52, 200, 255),
|
||||
view.zoom,
|
||||
);
|
||||
}
|
||||
|
||||
for node in layout.drawing().layer_primitive_nodes(0) {
|
||||
let color = if highlighteds.contains(&node) {
|
||||
ColorU::new(255, 100, 100, 255)
|
||||
} else {
|
||||
ColorU::new(200, 52, 52, 255)
|
||||
};
|
||||
|
||||
let shape = node.primitive(layout.drawing()).shape();
|
||||
painter.paint_primitive(&shape, color, view.zoom);
|
||||
}
|
||||
|
||||
for poly in layout.layer_poly_nodes(0) {
|
||||
painter.paint_polygon(
|
||||
&layout.poly(poly).shape().polygon,
|
||||
ColorU::new(200, 52, 52, 255),
|
||||
view.zoom,
|
||||
);
|
||||
}
|
||||
|
||||
for ghost in ghosts {
|
||||
painter.paint_primitive(&ghost, ColorU::new(75, 75, 150, 255), view.zoom);
|
||||
}
|
||||
|
||||
if let Some(ref navmesh) = maybe_navmesh {
|
||||
for edge in navmesh.graph().edge_references() {
|
||||
let from =
|
||||
PrimitiveIndex::from(navmesh.graph().node_weight(edge.source()).unwrap().node)
|
||||
.primitive(layout.drawing())
|
||||
.shape()
|
||||
.center();
|
||||
let to =
|
||||
PrimitiveIndex::from(navmesh.graph().node_weight(edge.target()).unwrap().node)
|
||||
.primitive(layout.drawing())
|
||||
.shape()
|
||||
.center();
|
||||
|
||||
let color = 'blk: {
|
||||
if let (Some(source_pos), Some(target_pos)) = (
|
||||
path.iter().position(|node| *node == edge.source()),
|
||||
path.iter().position(|node| *node == edge.target()),
|
||||
) {
|
||||
if target_pos == source_pos + 1 {
|
||||
break 'blk ColorU::new(250, 250, 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
ColorU::new(125, 125, 125, 255)
|
||||
};
|
||||
|
||||
painter.paint_edge(from, to, color, view.zoom);
|
||||
}
|
||||
}
|
||||
|
||||
let mut scene = SceneProxy::from_scene(
|
||||
canvas.into_canvas().into_scene(),
|
||||
renderer.mode().level,
|
||||
RayonExecutor,
|
||||
);
|
||||
scene.build_and_render(renderer, BuildOptions::default());
|
||||
window.gl_swap_window();
|
||||
|
||||
i += 1;
|
||||
if times != -1 && i >= times {
|
||||
return;
|
||||
}
|
||||
|
||||
::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
use geo::{CoordsIter, Point, Polygon};
|
||||
use pathfinder_canvas::{
|
||||
vec2f, ArcDirection, Canvas, CanvasRenderingContext2D, ColorU, FillRule, Path2D, RectF,
|
||||
};
|
||||
use topola::geometry::primitive::{AccessPrimitiveShape, PrimitiveShape};
|
||||
|
||||
pub struct Painter<'a> {
|
||||
canvas: &'a mut CanvasRenderingContext2D,
|
||||
}
|
||||
|
||||
impl<'a> Painter<'a> {
|
||||
pub fn new(canvas: &'a mut CanvasRenderingContext2D) -> Self {
|
||||
Self { canvas }
|
||||
}
|
||||
|
||||
pub fn paint_primitive(&mut self, shape: &PrimitiveShape, color: ColorU, zoom: f32) {
|
||||
self.canvas.set_stroke_style(color);
|
||||
self.canvas.set_fill_style(color);
|
||||
|
||||
match shape {
|
||||
PrimitiveShape::Dot(dot) => {
|
||||
let mut path = Path2D::new();
|
||||
path.ellipse(
|
||||
vec2f(dot.circle.pos.x() as f32, -dot.circle.pos.y() as f32),
|
||||
dot.circle.r as f32,
|
||||
0.0,
|
||||
0.0,
|
||||
std::f32::consts::TAU,
|
||||
);
|
||||
self.canvas.fill_path(path, FillRule::Winding);
|
||||
}
|
||||
PrimitiveShape::Seg(seg) => {
|
||||
let mut path = Path2D::new();
|
||||
path.move_to(vec2f(seg.from.x() as f32, -seg.from.y() as f32));
|
||||
path.line_to(vec2f(seg.to.x() as f32, -seg.to.y() as f32));
|
||||
self.canvas.set_line_width(seg.width as f32);
|
||||
self.canvas.stroke_path(path);
|
||||
}
|
||||
PrimitiveShape::Bend(bend) => {
|
||||
/*let delta1 = bend.from - bend.c.pos;
|
||||
let delta2 = bend.to - bend.c.pos;
|
||||
|
||||
let angle1 = delta1.y().atan2(delta1.x());
|
||||
let angle2 = delta2.y().atan2(delta2.x());
|
||||
|
||||
let mut path = Path2D::new();
|
||||
path.arc(
|
||||
vec2f(bend.c.pos.x() as f32, -bend.c.pos.y() as f32),
|
||||
bend.circle().r as f32,
|
||||
angle1 as f32,
|
||||
angle2 as f32,
|
||||
ArcDirection::CW,
|
||||
);
|
||||
self.canvas.set_line_width(bend.width as f32);
|
||||
self.canvas.stroke_path(path);*/
|
||||
}
|
||||
}
|
||||
|
||||
let envelope = AccessPrimitiveShape::envelope(shape, 0.0);
|
||||
// XXX: points represented as arrays can't be conveniently converted to vector types
|
||||
let topleft = vec2f(envelope.lower()[0] as f32, -envelope.upper()[1] as f32);
|
||||
let bottomright = vec2f(envelope.upper()[0] as f32, -envelope.lower()[1] as f32);
|
||||
self.canvas.set_line_width(2.0 / zoom);
|
||||
self.canvas
|
||||
.set_stroke_style(ColorU::new(100, 100, 100, 255));
|
||||
self.canvas
|
||||
.stroke_rect(RectF::new(topleft, bottomright - topleft));
|
||||
}
|
||||
|
||||
pub fn paint_polygon(&mut self, polygon: &Polygon, color: ColorU, zoom: f32) {
|
||||
let mut path = Path2D::new();
|
||||
let mut it = polygon.exterior_coords_iter();
|
||||
|
||||
if let Some(initial_vertex) = it.next() {
|
||||
path.move_to(vec2f(initial_vertex.x as f32, -initial_vertex.y as f32));
|
||||
}
|
||||
|
||||
for vertex in it {
|
||||
path.line_to(vec2f(vertex.x as f32, -vertex.y as f32));
|
||||
}
|
||||
|
||||
path.close_path();
|
||||
|
||||
self.canvas.set_stroke_style(color);
|
||||
self.canvas.set_fill_style(color);
|
||||
self.canvas.set_line_width(0.0);
|
||||
self.canvas.fill_path(path, FillRule::Winding);
|
||||
}
|
||||
|
||||
pub fn paint_edge(&mut self, from: Point, to: Point, color: ColorU, zoom: f32) {
|
||||
let mut path = Path2D::new();
|
||||
path.move_to(vec2f(from.x() as f32, from.y() as f32));
|
||||
path.line_to(vec2f(to.x() as f32, to.y() as f32));
|
||||
self.canvas.set_stroke_style(color);
|
||||
self.canvas.set_line_width(2.0 / zoom);
|
||||
self.canvas.stroke_path(path);
|
||||
}
|
||||
}
|
||||
|
|
@ -7,22 +7,19 @@ use crate::{
|
|||
board::{mesadata::AccessMesadata, Board},
|
||||
drawing::{
|
||||
dot::FixedDotWeight,
|
||||
graph::{GetLayer, GetMaybeNet, MakePrimitive},
|
||||
primitive::MakePrimitiveShape,
|
||||
seg::FixedSegWeight,
|
||||
Drawing,
|
||||
graph::{GetMaybeNet, GetLayer, MakePrimitive},
|
||||
primitive::MakePrimitiveShape
|
||||
},
|
||||
geometry::{
|
||||
primitive::{PrimitiveShape},
|
||||
GetWidth,
|
||||
},
|
||||
geometry::{primitive::PrimitiveShape, GetWidth},
|
||||
layout::{poly::SolidPolyWeight, Layout},
|
||||
math::Circle,
|
||||
specctra::{
|
||||
mesadata::SpecctraMesadata,
|
||||
read::{self, ListTokenizer},
|
||||
write::{self, ListWriter},
|
||||
structure::{self, DsnFile, Layer, Pcb, Shape},
|
||||
write::{self, ListWriter},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -58,7 +55,6 @@ impl SpecctraDesign {
|
|||
) -> Result<(), std::io::Error> {
|
||||
let mesadata = board.mesadata();
|
||||
let drawing = board.layout().drawing();
|
||||
//dbg!(&geometry);
|
||||
|
||||
let mut net_outs = HashMap::<usize, structure::NetOut>::new();
|
||||
for index in drawing.primitive_nodes() {
|
||||
|
|
@ -68,10 +64,16 @@ impl SpecctraDesign {
|
|||
let coords = match primitive.shape() {
|
||||
PrimitiveShape::Seg(seg) => {
|
||||
vec![
|
||||
structure::Point { x: seg.from.x(), y: seg.from.y() },
|
||||
structure::Point { x: seg.to.x(), y: seg.to.y() },
|
||||
structure::Point {
|
||||
x: seg.from.x(),
|
||||
y: seg.from.y(),
|
||||
},
|
||||
structure::Point {
|
||||
x: seg.to.x(),
|
||||
y: seg.to.y(),
|
||||
},
|
||||
]
|
||||
},
|
||||
}
|
||||
|
||||
PrimitiveShape::Bend(bend) => {
|
||||
// Since general circle arcs don't seem to be supported
|
||||
|
|
@ -86,12 +88,14 @@ impl SpecctraDesign {
|
|||
|
||||
let mut points = Vec::new();
|
||||
for i in 0..=segment_count {
|
||||
let x = circle.pos.x() + circle.r * (angle_from + i as f64 * angle_step).cos();
|
||||
let y = circle.pos.y() + circle.r * (angle_from + i as f64 * angle_step).sin();
|
||||
let x = circle.pos.x()
|
||||
+ circle.r * (angle_from + i as f64 * angle_step).cos();
|
||||
let y = circle.pos.y()
|
||||
+ circle.r * (angle_from + i as f64 * angle_step).sin();
|
||||
points.push(structure::Point { x, y });
|
||||
}
|
||||
points
|
||||
},
|
||||
}
|
||||
|
||||
// Intentionally skipped for now.
|
||||
// Topola stores trace segments and dots joining them
|
||||
|
|
@ -103,7 +107,10 @@ impl SpecctraDesign {
|
|||
|
||||
let wire = structure::WireOut {
|
||||
path: structure::Path {
|
||||
layer: mesadata.layer_layername(primitive.layer()).unwrap().to_owned(),
|
||||
layer: mesadata
|
||||
.layer_layername(primitive.layer())
|
||||
.unwrap()
|
||||
.to_owned(),
|
||||
width: primitive.width(),
|
||||
coords,
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue