geometry: have a common `Shape` object for both primitives and compounds

This commit is contained in:
Mikolaj Wielgus 2024-04-18 15:41:01 +02:00
parent e5bae501ad
commit 43f1248a76
15 changed files with 171 additions and 137 deletions

View File

@ -6,13 +6,14 @@ use std::{
};
use topola::{
drawing::{graph::MakePrimitive, primitive::MakeShape, Drawing},
drawing::{graph::MakePrimitive, primitive::MakePrimitiveShape, Drawing},
dsn::{design::DsnDesign, rules::DsnRules},
geometry::{
compound::CompoundManagerTrait,
primitive::{BendShape, DotShape, PrimitiveShape, SegShape},
GenericNode,
},
layout::{zone::MakePolygon, Layout},
layout::{zone::MakePolyShape, Layout},
math::Circle,
overlay::Overlay,
};
@ -168,7 +169,10 @@ impl eframe::App for App {
for zone in layout.layer_zones(1) {
painter.paint_polygon(
&zone.polygon(&layout.drawing()),
&layout
.compound_weight(zone)
.shape(&layout.drawing(), zone)
.polygon,
egui::Color32::from_rgb(52, 52, 200),
)
}
@ -190,7 +194,10 @@ impl eframe::App for App {
for zone in layout.layer_zones(0) {
painter.paint_polygon(
&zone.polygon(&layout.drawing()),
&layout
.compound_weight(zone)
.shape(&layout.drawing(), zone)
.polygon,
egui::Color32::from_rgb(200, 52, 52),
)
}

View File

@ -15,7 +15,7 @@ use petgraph::visit::{EdgeRef, IntoEdgeReferences};
use topola::draw::DrawException;
use topola::drawing::dot::FixedDotWeight;
use topola::drawing::graph::{MakePrimitive, PrimitiveIndex};
use topola::drawing::primitive::MakeShape;
use topola::drawing::primitive::MakePrimitiveShape;
use topola::drawing::rules::{Conditions, RulesTrait};
use topola::drawing::seg::FixedSegWeight;
use topola::drawing::zone::MakePolygon;

View File

@ -21,7 +21,9 @@ use crate::drawing::{
bend::{FixedBendIndex, LooseBendIndex, LooseBendWeight},
dot::{DotIndex, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight},
graph::{MakePrimitive, PrimitiveIndex, PrimitiveWeight},
primitive::{GenericPrimitive, GetCore, GetInnerOuter, GetJoints, GetOtherJoint, MakeShape},
primitive::{
GenericPrimitive, GetCore, GetInnerOuter, GetJoints, GetOtherJoint, MakePrimitiveShape,
},
seg::{
FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SegIndex,
SeqLooseSegIndex, SeqLooseSegWeight,
@ -37,7 +39,6 @@ use crate::geometry::{
SegWeightTrait,
};
use crate::graph::{GenericIndex, GetNodeIndex};
use crate::layout::zone::{ZoneIndex, ZoneWeight};
use crate::math::NoTangents;
use super::bend::BendWeight;

View File

@ -6,7 +6,7 @@ use crate::{
bend::BendIndex,
dot::{DotIndex, FixedDotIndex, LooseDotIndex},
graph::MakePrimitive,
primitive::{GetCore, GetInnerOuter, GetOtherJoint, GetWeight, MakeShape},
primitive::{GetCore, GetInnerOuter, GetOtherJoint, GetWeight, MakePrimitiveShape},
rules::GetConditions,
Drawing,
},

View File

@ -34,7 +34,7 @@ pub trait GetWeight<W> {
}
#[enum_dispatch]
pub trait MakeShape {
pub trait MakePrimitiveShape {
fn shape(&self) -> PrimitiveShape;
}
@ -160,7 +160,7 @@ macro_rules! impl_loose_primitive {
GetMaybeNet,
GetWidth,
GetDrawing,
MakeShape,
MakePrimitiveShape,
GetLimbs,
GetConditions
)]
@ -279,7 +279,7 @@ impl<'a, CW: Copy, R: RulesTrait> FixedDot<'a, CW, R> {
}
}
impl<'a, CW: Copy, R: RulesTrait> MakeShape for FixedDot<'a, CW, R> {
impl<'a, CW: Copy, R: RulesTrait> MakePrimitiveShape for FixedDot<'a, CW, R> {
fn shape(&self) -> PrimitiveShape {
self.drawing.geometry().dot_shape(self.index.into())
}
@ -325,7 +325,7 @@ impl<'a, CW: Copy, R: RulesTrait> LooseDot<'a, CW, R> {
}
}
impl<'a, CW: Copy, R: RulesTrait> MakeShape for LooseDot<'a, CW, R> {
impl<'a, CW: Copy, R: RulesTrait> MakePrimitiveShape for LooseDot<'a, CW, R> {
fn shape(&self) -> PrimitiveShape {
self.drawing.geometry().dot_shape(self.index.into())
}
@ -348,7 +348,7 @@ impl<'a, CW: Copy, R: RulesTrait> GetLimbs for LooseDot<'a, CW, R> {
pub type FixedSeg<'a, CW, R> = GenericPrimitive<'a, FixedSegWeight, CW, R>;
impl_fixed_primitive!(FixedSeg, FixedSegWeight);
impl<'a, CW: Copy, R: RulesTrait> MakeShape for FixedSeg<'a, CW, R> {
impl<'a, CW: Copy, R: RulesTrait> MakePrimitiveShape for FixedSeg<'a, CW, R> {
fn shape(&self) -> PrimitiveShape {
self.drawing.geometry().seg_shape(self.index.into())
}
@ -374,7 +374,7 @@ impl<'a, CW: Copy, R: RulesTrait> GetOtherJoint<FixedDotIndex, FixedDotIndex>
pub type LoneLooseSeg<'a, CW, R> = GenericPrimitive<'a, LoneLooseSegWeight, CW, R>;
impl_loose_primitive!(LoneLooseSeg, LoneLooseSegWeight);
impl<'a, CW: Copy, R: RulesTrait> MakeShape for LoneLooseSeg<'a, CW, R> {
impl<'a, CW: Copy, R: RulesTrait> MakePrimitiveShape for LoneLooseSeg<'a, CW, R> {
fn shape(&self) -> PrimitiveShape {
self.drawing.geometry().seg_shape(self.index.into())
}
@ -402,7 +402,7 @@ impl<'a, CW: Copy, R: RulesTrait> GetOtherJoint<FixedDotIndex, FixedDotIndex>
pub type SeqLooseSeg<'a, CW, R> = GenericPrimitive<'a, SeqLooseSegWeight, CW, R>;
impl_loose_primitive!(SeqLooseSeg, SeqLooseSegWeight);
impl<'a, CW: Copy, R: RulesTrait> MakeShape for SeqLooseSeg<'a, CW, R> {
impl<'a, CW: Copy, R: RulesTrait> MakePrimitiveShape for SeqLooseSeg<'a, CW, R> {
fn shape(&self) -> PrimitiveShape {
self.drawing.geometry().seg_shape(self.index.into())
}
@ -446,7 +446,7 @@ impl<'a, CW: Copy, R: RulesTrait> GetBendIndex for FixedBend<'a, CW, R> {
}
}
impl<'a, CW: Copy, R: RulesTrait> MakeShape for FixedBend<'a, CW, R> {
impl<'a, CW: Copy, R: RulesTrait> MakePrimitiveShape for FixedBend<'a, CW, R> {
fn shape(&self) -> PrimitiveShape {
self.drawing.geometry().bend_shape(self.index.into())
}
@ -487,7 +487,7 @@ impl<'a, CW: Copy, R: RulesTrait> From<LooseBend<'a, CW, R>> for BendIndex {
}
}
impl<'a, CW: Copy, R: RulesTrait> MakeShape for LooseBend<'a, CW, R> {
impl<'a, CW: Copy, R: RulesTrait> MakePrimitiveShape for LooseBend<'a, CW, R> {
fn shape(&self) -> PrimitiveShape {
self.drawing.geometry().bend_shape(self.index.into())
}

View File

@ -12,10 +12,7 @@ use crate::{
},
geometry::compound::CompoundManagerTrait,
graph::{GenericIndex, GetNodeIndex},
layout::{
zone::{SolidZoneWeight, ZoneIndex},
Layout,
},
layout::{zone::SolidZoneWeight, Layout},
math::Circle,
};
@ -367,7 +364,7 @@ impl DsnDesign {
layer,
maybe_net: Some(net),
},
ZoneIndex::Solid(GenericIndex::new(zone.node_index())),
zone,
)
.unwrap();
let dot_2_1 = layout
@ -380,7 +377,7 @@ impl DsnDesign {
layer,
maybe_net: Some(net),
},
ZoneIndex::Solid(GenericIndex::new(zone.node_index())),
zone,
)
.unwrap();
let dot_2_2 = layout
@ -393,7 +390,7 @@ impl DsnDesign {
layer,
maybe_net: Some(net),
},
ZoneIndex::Solid(GenericIndex::new(zone.node_index())),
zone,
)
.unwrap();
let dot_1_2 = layout
@ -406,7 +403,7 @@ impl DsnDesign {
layer,
maybe_net: Some(net),
},
ZoneIndex::Solid(GenericIndex::new(zone.node_index())),
zone,
)
.unwrap();
// Sides.
@ -419,7 +416,7 @@ impl DsnDesign {
layer,
maybe_net: Some(net),
},
ZoneIndex::Solid(GenericIndex::new(zone.node_index())),
zone,
)
.unwrap();
layout
@ -431,7 +428,7 @@ impl DsnDesign {
layer,
maybe_net: Some(net),
},
ZoneIndex::Solid(GenericIndex::new(zone.node_index())),
zone,
)
.unwrap();
layout
@ -443,7 +440,7 @@ impl DsnDesign {
layer,
maybe_net: Some(net),
},
ZoneIndex::Solid(GenericIndex::new(zone.node_index())),
zone,
)
.unwrap();
layout
@ -455,7 +452,7 @@ impl DsnDesign {
layer,
maybe_net: Some(net),
},
ZoneIndex::Solid(GenericIndex::new(zone.node_index())),
zone,
)
.unwrap();
}
@ -567,7 +564,7 @@ impl DsnDesign {
},
// TODO: This manual retagging shouldn't be necessary, `.into()` should suffice.
//GenericIndex::new(zone.node_index()).into(),
ZoneIndex::Solid(GenericIndex::new(zone.node_index())),
zone,
)
.unwrap();
@ -592,7 +589,7 @@ impl DsnDesign {
maybe_net: Some(net),
},
// TODO: This manual retagging shouldn't be necessary, `.into()` should suffice.
ZoneIndex::Solid(GenericIndex::new(zone.node_index())),
zone,
)
.unwrap();
@ -607,7 +604,7 @@ impl DsnDesign {
maybe_net: Some(net),
},
// TODO: This manual retagging shouldn't be necessary, `.into()` should suffice.
ZoneIndex::Solid(GenericIndex::new(zone.node_index())),
zone,
)
.unwrap();

View File

@ -1,6 +1,7 @@
#[macro_use]
mod geometry;
pub mod compound;
pub mod poly;
pub mod primitive;
pub mod shape;
pub mod with_rtree;

15
src/geometry/poly.rs Normal file
View File

@ -0,0 +1,15 @@
use enum_dispatch::enum_dispatch;
use geo::{Contains, Point, Polygon};
use crate::geometry::shape::ShapeTrait;
#[derive(Debug, Clone, PartialEq)]
pub struct PolyShape {
pub polygon: Polygon,
}
impl ShapeTrait for PolyShape {
fn contains_point(&self, p: Point) -> bool {
self.polygon.contains(&p)
}
}

View File

@ -1,11 +0,0 @@
use enum_dispatch::enum_dispatch;
pub struct PolygonShape {
pub polygon: Polygon,
}
impl ShapeTrait for PolygonShape {
fn contains_point(&self, p: Point) -> bool {
self.polygon.contains(p)
}
}

View File

@ -1,9 +1,31 @@
use enum_dispatch::enum_dispatch;
use geo::Point;
use crate::geometry::primitive::PrimitiveShape;
use crate::geometry::{
poly::PolyShape,
primitive::{BendShape, DotShape, PrimitiveShape, SegShape},
};
#[enum_dispatch]
pub trait ShapeTrait {
fn contains_point(&self, p: Point) -> bool;
}
#[enum_dispatch(ShapeTrait)]
#[derive(Debug, Clone, PartialEq)]
pub enum Shape {
Dot(DotShape),
Seg(SegShape),
Bend(BendShape),
Poly(PolyShape),
}
impl From<PrimitiveShape> for Shape {
fn from(primitive: PrimitiveShape) -> Self {
match primitive {
PrimitiveShape::Dot(dot) => Shape::Dot(dot),
PrimitiveShape::Seg(seg) => Shape::Seg(seg),
PrimitiveShape::Bend(bend) => Shape::Bend(bend),
}
}
}

View File

@ -17,15 +17,15 @@ use crate::{
Drawing, Infringement, LayoutException,
},
geometry::{
compound::CompoundManagerTrait, BendWeightTrait, DotWeightTrait, GenericNode, Geometry,
GeometryLabel, GetWidth, SegWeightTrait,
compound::CompoundManagerTrait, poly::PolyShape, BendWeightTrait, DotWeightTrait,
GenericNode, Geometry, GeometryLabel, GetWidth, SegWeightTrait,
},
graph::{GenericIndex, GetNodeIndex},
layout::{
connectivity::{
BandIndex, BandWeight, ConnectivityLabel, ConnectivityWeight, ContinentIndex,
},
zone::{PourZoneIndex, SolidZoneIndex, ZoneIndex, ZoneWeight},
zone::{PourZoneIndex, SolidZoneIndex, ZoneWeight},
},
};
@ -92,13 +92,12 @@ impl<R: RulesTrait> Layout<R> {
pub fn add_zone_fixed_dot(
&mut self,
weight: FixedDotWeight,
zone: ZoneIndex,
zone: GenericIndex<ZoneWeight>,
) -> Result<FixedDotIndex, Infringement> {
let maybe_dot = self.drawing.add_fixed_dot(weight);
if let Ok(dot) = maybe_dot {
self.drawing
.add_to_compound(dot, GenericIndex::new(zone.node_index()));
self.drawing.add_to_compound(dot, zone);
}
maybe_dot
@ -118,13 +117,12 @@ impl<R: RulesTrait> Layout<R> {
from: FixedDotIndex,
to: FixedDotIndex,
weight: FixedSegWeight,
zone: ZoneIndex,
zone: GenericIndex<ZoneWeight>,
) -> Result<FixedSegIndex, Infringement> {
let maybe_seg = self.add_fixed_seg(from, to, weight);
if let Ok(seg) = maybe_seg {
self.drawing
.add_to_compound(seg, GenericIndex::new(zone.node_index()));
self.drawing.add_to_compound(seg, zone);
}
maybe_seg
@ -170,22 +168,17 @@ impl<R: RulesTrait> Layout<R> {
ContinentIndex::new(0.into())
}
pub fn zones(&self) -> impl Iterator<Item = ZoneIndex> + '_ {
pub fn zones(&self) -> impl Iterator<Item = GenericIndex<ZoneWeight>> + '_ {
self.drawing.rtree().iter().filter_map(|wrapper| {
if let NodeIndex::Compound(zone) = wrapper.data {
Some(match self.drawing.geometry().compound_weight(zone) {
ZoneWeight::Solid(..) => {
ZoneIndex::Solid(SolidZoneIndex::new(zone.node_index()))
}
ZoneWeight::Pour(..) => ZoneIndex::Pour(PourZoneIndex::new(zone.node_index())),
})
Some(zone)
} else {
None
}
})
}
pub fn layer_zones(&self, layer: u64) -> impl Iterator<Item = ZoneIndex> + '_ {
pub fn layer_zones(&self, layer: u64) -> impl Iterator<Item = GenericIndex<ZoneWeight>> + '_ {
self.drawing
.rtree()
.locate_in_envelope_intersecting(&AABB::from_corners(
@ -194,21 +187,17 @@ impl<R: RulesTrait> Layout<R> {
))
.filter_map(|wrapper| {
if let NodeIndex::Compound(zone) = wrapper.data {
Some(match self.drawing.geometry().compound_weight(zone) {
ZoneWeight::Solid(..) => {
ZoneIndex::Solid(SolidZoneIndex::new(zone.node_index()))
}
ZoneWeight::Pour(..) => {
ZoneIndex::Pour(PourZoneIndex::new(zone.node_index()))
}
})
Some(zone)
} else {
None
}
})
}
pub fn zone_members(&self, zone: ZoneIndex) -> impl Iterator<Item = PrimitiveIndex> + '_ {
pub fn zone_members(
&self,
zone: GenericIndex<ZoneWeight>,
) -> impl Iterator<Item = PrimitiveIndex> + '_ {
self.drawing
.geometry()
.compound_members(GenericIndex::new(zone.node_index()))

View File

@ -11,23 +11,20 @@ use crate::{
rules::RulesTrait,
Drawing,
},
geometry::GetPos,
geometry::{poly::PolyShape, GetPos},
graph::{GenericIndex, GetNodeIndex},
};
#[enum_dispatch]
pub trait MakePolygon {
fn polygon<R: RulesTrait>(&self, drawing: &Drawing<impl Copy, R>) -> Polygon;
pub trait MakePolyShape {
fn shape<R: RulesTrait>(
&self,
drawing: &Drawing<ZoneWeight, R>,
index: GenericIndex<ZoneWeight>,
) -> PolyShape;
}
#[enum_dispatch(GetNodeIndex, MakePolygon)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ZoneIndex {
Solid(SolidZoneIndex),
Pour(PourZoneIndex),
}
#[enum_dispatch(GetLayer)]
#[enum_dispatch(GetLayer, MakePolyShape)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ZoneWeight {
Solid(SolidZoneWeight),
@ -52,15 +49,18 @@ impl<'a> GetMaybeNet for SolidZoneWeight {
}
}
pub type SolidZoneIndex = GenericIndex<SolidZoneWeight>;
impl MakePolygon for SolidZoneIndex {
fn polygon<R: RulesTrait>(&self, drawing: &Drawing<impl Copy, R>) -> Polygon {
Polygon::new(
impl MakePolyShape for SolidZoneWeight {
fn shape<R: RulesTrait>(
&self,
drawing: &Drawing<ZoneWeight, R>,
index: GenericIndex<ZoneWeight>,
) -> PolyShape {
PolyShape {
polygon: Polygon::new(
LineString::from(
drawing
.geometry()
.compound_members(GenericIndex::new(self.node_index()))
.compound_members(index)
.filter_map(|primitive_node| {
if let Ok(dot) = DotIndex::try_from(primitive_node) {
Some(drawing.geometry().dot_weight(dot).pos())
@ -71,9 +71,12 @@ impl MakePolygon for SolidZoneIndex {
.collect::<Vec<Point>>(),
),
vec![],
)
),
}
}
}
pub type SolidZoneIndex = GenericIndex<SolidZoneWeight>;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PourZoneWeight {
@ -93,15 +96,18 @@ impl<'a> GetMaybeNet for PourZoneWeight {
}
}
pub type PourZoneIndex = GenericIndex<PourZoneWeight>;
impl MakePolygon for PourZoneIndex {
fn polygon<R: RulesTrait>(&self, drawing: &Drawing<impl Copy, R>) -> Polygon {
Polygon::new(
impl MakePolyShape for PourZoneWeight {
fn shape<R: RulesTrait>(
&self,
drawing: &Drawing<ZoneWeight, R>,
index: GenericIndex<ZoneWeight>,
) -> PolyShape {
PolyShape {
polygon: Polygon::new(
LineString::from(
drawing
.geometry()
.compound_members(GenericIndex::new(self.node_index()))
.compound_members(index)
.filter_map(|primitive_node| {
if let Ok(dot) = DotIndex::try_from(primitive_node) {
Some(drawing.geometry().dot_weight(dot).pos())
@ -112,6 +118,9 @@ impl MakePolygon for PourZoneIndex {
.collect::<Vec<Point>>(),
),
vec![],
)
),
}
}
}
pub type PourZoneIndex = GenericIndex<PourZoneWeight>;

View File

@ -6,12 +6,18 @@ use rstar::AABB;
use crate::{
drawing::{
graph::{GetLayer, MakePrimitive, PrimitiveIndex},
primitive::MakeShape,
primitive::MakePrimitiveShape,
rules::RulesTrait,
},
geometry::shape::ShapeTrait,
geometry::{
compound::CompoundManagerTrait,
shape::{Shape, ShapeTrait},
},
graph::GenericIndex,
layout::{zone::ZoneWeight, Layout, NodeIndex},
layout::{
zone::{MakePolyShape, ZoneWeight},
Layout, NodeIndex,
},
};
pub struct Overlay {
@ -61,20 +67,18 @@ impl Overlay {
node: NodeIndex,
p: Point,
) -> bool {
match node {
NodeIndex::Primitive(primitive) => {
if primitive
.primitive(layout.drawing())
.shape()
.contains_point(p)
{
let shape: Shape = match node {
NodeIndex::Primitive(primitive) => primitive.primitive(layout.drawing()).shape().into(),
NodeIndex::Compound(compound) => layout
.compound_weight(compound)
.shape(layout.drawing(), compound)
.into(),
};
if shape.contains_point(p) {
self.toggle_selection(node);
return true;
}
}
NodeIndex::Compound(compound) => (), // TODO.
}
false
}

View File

@ -13,7 +13,7 @@ use crate::{
bend::{FixedBendIndex, LooseBendIndex},
dot::FixedDotIndex,
graph::{MakePrimitive, PrimitiveIndex},
primitive::{GetCore, MakeShape, Primitive},
primitive::{GetCore, MakePrimitiveShape, Primitive},
Drawing,
},
geometry::primitive::PrimitiveShapeTrait,

View File

@ -7,7 +7,7 @@ use thiserror::Error;
use crate::drawing::{
dot::FixedDotIndex,
graph::{MakePrimitive, PrimitiveIndex},
primitive::MakeShape,
primitive::MakePrimitiveShape,
rules::RulesTrait,
};
use crate::geometry::primitive::PrimitiveShapeTrait;