mirror of https://codeberg.org/topola/topola.git
feat(topola-egui): Show shape of infringee in addition to inflated infringer's
This commit is contained in:
parent
3078d9d546
commit
f4b78749b1
|
|
@ -67,11 +67,17 @@ impl fmt::Debug for DrawingException {
|
|||
}
|
||||
|
||||
impl DrawingException {
|
||||
pub fn maybe_ghost_and_obstacle(&self) -> Option<(&PrimitiveShape, PrimitiveIndex)> {
|
||||
pub fn maybe_ghosts_and_obstacle(
|
||||
&self,
|
||||
) -> Option<(&PrimitiveShape, &PrimitiveShape, PrimitiveIndex)> {
|
||||
match self {
|
||||
Self::NoTangents(_) => None,
|
||||
Self::Infringement(Infringement(ghost, obstacle)) => Some((ghost, *obstacle)),
|
||||
Self::Collision(Collision(ghost, obstacle)) => Some((ghost, *obstacle)),
|
||||
Self::Infringement(Infringement(infringer_ghost, infringee_ghost, obstacle)) => {
|
||||
Some((infringer_ghost, infringee_ghost, *obstacle))
|
||||
}
|
||||
Self::Collision(Collision(collider_ghost, collidee_ghost, obstacle)) => {
|
||||
Some((collider_ghost, collidee_ghost, *obstacle))
|
||||
}
|
||||
Self::AlreadyConnected(_) => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -86,7 +92,7 @@ impl DrawingException {
|
|||
/// having the same net implies being connectable.
|
||||
#[derive(Error, Debug, Clone, Copy)]
|
||||
#[error("{0:?} infringes on {1:?}")]
|
||||
pub struct Infringement(pub PrimitiveShape, pub PrimitiveIndex);
|
||||
pub struct Infringement(pub PrimitiveShape, pub PrimitiveShape, pub PrimitiveIndex);
|
||||
|
||||
/// A collision is a special case of infringement where the uninflated shapes of
|
||||
/// two primitives themselves intersect. In other words, collision detection is
|
||||
|
|
@ -107,7 +113,7 @@ pub struct Infringement(pub PrimitiveShape, pub PrimitiveIndex);
|
|||
/// net, making them connectable and thus uninfringable.
|
||||
#[derive(Error, Debug, Clone, Copy)]
|
||||
#[error("{0:?} collides with {1:?}")]
|
||||
pub struct Collision(pub PrimitiveShape, pub PrimitiveIndex);
|
||||
pub struct Collision(pub PrimitiveShape, pub PrimitiveShape, pub PrimitiveIndex);
|
||||
|
||||
#[derive(Error, Debug, Clone, Copy)]
|
||||
#[error("{1:?} is already connected to net {0}")]
|
||||
|
|
|
|||
|
|
@ -190,9 +190,9 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
|||
// Infringement with loose dots resulted in false positives for
|
||||
// line-of-sight paths.
|
||||
!matches!(infringer, PrimitiveIndex::LooseDot(..))
|
||||
&& !matches!(infringement.1, PrimitiveIndex::LooseDot(..))
|
||||
&& !matches!(infringement.2, PrimitiveIndex::LooseDot(..))
|
||||
})
|
||||
.filter(move |infringement| !self.are_connectable(infringer, infringement.1))
|
||||
.filter(move |infringement| !self.are_connectable(infringer, infringement.2))
|
||||
}
|
||||
|
||||
pub fn overlapees<'a>(
|
||||
|
|
@ -224,21 +224,28 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
|||
let infringee_conditions = primitive_node.primitive_ref(self).conditions();
|
||||
|
||||
let epsilon = 1.0;
|
||||
let inflated_shape = intersector.primitive_ref(self).shape().inflate(
|
||||
match (&conditions, infringee_conditions) {
|
||||
(None, _) | (_, None) => 0.0,
|
||||
(Some(lhs), Some(rhs)) => {
|
||||
// Note the epsilon comparison.
|
||||
// XXX: Epsilon is probably too large. But what should
|
||||
// it be exactly then?
|
||||
(self.rules().clearance(lhs, &rhs) - epsilon).clamp(0.0, f64::INFINITY)
|
||||
}
|
||||
},
|
||||
);
|
||||
let inflated_infringer_shape = intersector.primitive_ref(self).shape().inflate(match (
|
||||
&conditions,
|
||||
infringee_conditions,
|
||||
) {
|
||||
(None, _) | (_, None) => 0.0,
|
||||
(Some(lhs), Some(rhs)) => {
|
||||
// Note the epsilon comparison.
|
||||
// XXX: Epsilon is probably too large. But what should
|
||||
// it be exactly then?
|
||||
(self.rules().clearance(lhs, &rhs) - epsilon).clamp(0.0, f64::INFINITY)
|
||||
}
|
||||
});
|
||||
|
||||
inflated_shape
|
||||
.intersects(&primitive_node.primitive_ref(self).shape())
|
||||
.then_some(Infringement(inflated_shape, primitive_node))
|
||||
let infringee_shape = primitive_node.primitive_ref(self).shape();
|
||||
|
||||
inflated_infringer_shape
|
||||
.intersects(&infringee_shape)
|
||||
.then_some(Infringement(
|
||||
inflated_infringer_shape,
|
||||
infringee_shape,
|
||||
primitive_node,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -266,11 +273,11 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
|||
collider: PrimitiveIndex,
|
||||
predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
|
||||
) -> Option<Collision> {
|
||||
let shape = collider.primitive_ref(self).shape();
|
||||
let collider_shape = collider.primitive_ref(self).shape();
|
||||
|
||||
self.recording_geometry_with_rtree()
|
||||
.rtree()
|
||||
.locate_in_envelope_intersecting(&shape.full_height_envelope_3d(0.0, 2))
|
||||
.locate_in_envelope_intersecting(&collider_shape.full_height_envelope_3d(0.0, 2))
|
||||
.filter_map(|wrapper| {
|
||||
if let GenericNode::Primitive(collidee) = wrapper.data {
|
||||
Some(collidee)
|
||||
|
|
@ -290,8 +297,15 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
|||
|| matches!(collidee, PrimitiveIndex::SeqLooseSeg(..))))
|
||||
})
|
||||
.filter(|collidee| predicate(&self, collider, *collidee))
|
||||
.find(|collidee| shape.intersects(&collidee.primitive_ref(self).shape()))
|
||||
.map(|collidee| Collision(shape, collidee))
|
||||
.find_map(|collidee| {
|
||||
let collidee_shape = collidee.primitive_ref(self).shape();
|
||||
|
||||
if collider_shape.intersects(&collidee_shape) {
|
||||
Some(Collision(collider_shape, collidee_shape, collidee))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn are_connectable(&self, node1: PrimitiveIndex, node2: PrimitiveIndex) -> bool {
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ impl<R: AccessRules> Layout<R> {
|
|||
!drawing
|
||||
.overlapees(around.into())
|
||||
.find(|overlapee| {
|
||||
PrimitiveIndex::from(overlapee.1)
|
||||
PrimitiveIndex::from(overlapee.2)
|
||||
.primitive_ref(drawing)
|
||||
.limbs()
|
||||
.contains(&infringee)
|
||||
|
|
|
|||
|
|
@ -337,14 +337,14 @@ impl Navmesh {
|
|||
// Ignore overlaps with fillets.
|
||||
if layout
|
||||
.drawing()
|
||||
.compounds(GenericIndex::<()>::new(overlapee.1.index()))
|
||||
.compounds(GenericIndex::<()>::new(overlapee.2.index()))
|
||||
.find(|(label, _)| *label == CompoundEntryLabel::Fillet)
|
||||
.is_some()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let PrimitiveIndex::FixedDot(overlapee) = overlapee.1 else {
|
||||
let PrimitiveIndex::FixedDot(overlapee) = overlapee.2 else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -257,9 +257,11 @@ impl EvalException {
|
|||
Self::Draw(DrawException::NoBitangents(_)) => (Vec::new(), Vec::new(), Vec::new()),
|
||||
Self::Draw(DrawException::CannotFinishIn(_, dwxc))
|
||||
| Self::Draw(DrawException::CannotWrapAround(_, dwxc)) => {
|
||||
match dwxc.maybe_ghost_and_obstacle() {
|
||||
match dwxc.maybe_ghosts_and_obstacle() {
|
||||
None => (Vec::new(), Vec::new(), Vec::new()),
|
||||
Some((ghost, obstacle)) => (vec![*ghost], Vec::new(), vec![obstacle]),
|
||||
Some((infringer_ghost, _, obstacle)) => {
|
||||
(vec![*infringer_ghost], Vec::new(), vec![obstacle])
|
||||
}
|
||||
}
|
||||
}
|
||||
Self::ResolvingPathFailed { .. } => (Vec::new(), Vec::new(), Vec::new()),
|
||||
|
|
|
|||
|
|
@ -308,7 +308,7 @@ impl Prenavmesh {
|
|||
layout
|
||||
.drawing()
|
||||
// TODO: Add `.compounds()` method working on `PrimitiveIndex`.
|
||||
.compounds(GenericIndex::<()>::new(overlapee.1.index()))
|
||||
.compounds(GenericIndex::<()>::new(overlapee.2.index()))
|
||||
.find(|(label, _)| *label == CompoundEntryLabel::Fillet)
|
||||
.is_some()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -110,11 +110,13 @@ impl<R: AccessRules> ThetastarStrategy<Navmesh, f64, BandTermsegIndex>
|
|||
DrawException::CannotWrapAround(.., layout_err) => layout_err,
|
||||
};
|
||||
|
||||
let Some((ghost, obstacle)) = layout_err.maybe_ghost_and_obstacle() else {
|
||||
let Some((infringer_ghost, infringee_ghost, obstacle)) =
|
||||
layout_err.maybe_ghosts_and_obstacle()
|
||||
else {
|
||||
return ControlFlow::Break(None);
|
||||
};
|
||||
|
||||
self.probe_ghosts = vec![*ghost];
|
||||
self.probe_ghosts = vec![*infringer_ghost, *infringee_ghost];
|
||||
self.probe_obstacles = vec![obstacle];
|
||||
|
||||
let Some(initial_parent_navnode) = maybe_initial_parent_navnode else {
|
||||
|
|
|
|||
Loading…
Reference in New Issue