lots of cool work
This commit is contained in:
parent
556719f52d
commit
2d5d2fda4b
@ -2,6 +2,7 @@ use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::math::{Point2, Region, Region1, Region2, Scalar};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Var<T: Clone, TRegion: Region<T>> {
|
||||
@ -9,6 +10,12 @@ pub struct Var<T: Clone, TRegion: Region<T>> {
|
||||
constraints: TRegion,
|
||||
}
|
||||
|
||||
impl<T: Clone + fmt::Display, TRegion: Region<T> + fmt::Display> fmt::Display for Var<T, TRegion> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{{ {} ∈ {} }}", self.value, self.constraints)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone, TRegion: Region<T>> Var<T, TRegion> {
|
||||
pub fn new(value: T, constraints: TRegion) -> Self {
|
||||
Self { value, constraints }
|
||||
@ -42,7 +49,7 @@ impl<T: Clone, TRegion: Region<T>> Var<T, TRegion> {
|
||||
}
|
||||
|
||||
type ScalarVar = Var<Scalar, Region1>;
|
||||
type PointVar = Var<Point2, Region2>;
|
||||
type PointVar = Var<Point2<Scalar>, Region2>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Point {
|
||||
@ -58,6 +65,12 @@ impl Point {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Point {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Point {{ pos: {} }}", self.pos)
|
||||
}
|
||||
}
|
||||
|
||||
struct Line {
|
||||
p1: PointRef,
|
||||
p2: PointRef,
|
||||
|
39
src/main.rs
39
src/main.rs
@ -18,38 +18,38 @@ mod relation;
|
||||
|
||||
fn main() {
|
||||
use entity::{Point, PointRef, Var};
|
||||
use math::{Point2, eqn};
|
||||
use math::{Point2, eqn, Region2};
|
||||
use relation::{Relation, ResolveResult};
|
||||
|
||||
env_logger::init();
|
||||
|
||||
println!("Hello, world!");
|
||||
// let u1 = math::eqn::Unknown(1);
|
||||
// let u2 = math::eqn::Unknown(2);
|
||||
let u1 = eqn::Expr::from(1.);
|
||||
let u2 = eqn::Expr::from(1.);
|
||||
let u1 = math::eqn::Unknown(1);
|
||||
let u2 = math::eqn::Unknown(2);
|
||||
// let u1 = eqn::Expr::from(1.);
|
||||
// let u2 = eqn::Expr::from(1.);
|
||||
let origin = Point::new_ref(Var::new_single(Point2::new((0.).into(), (0.).into())));
|
||||
// let p1 = Point::new_ref(Var::new_full(Point2::new((1.).into(), (1.).into())));
|
||||
let p1 = Point::new_ref(Var::new_single(Point2::new((u1).into(), (u2).into())));
|
||||
let p1 = Point::new_ref(Var::new(Point2::new(1.,1.), Region2::Singleton(Point2::new((u1).into(), (u2).into()))));
|
||||
let p2 = Point::new_ref(Var::new_full(Point2::new((4.).into(), (4.).into())));
|
||||
let p3 = Point::new_ref(Var::new_full(Point2::new((2.).into(), (2.).into())));
|
||||
let mut points: Vec<PointRef> = vec![origin.clone(), p1.clone(), p2.clone(), p3.clone()];
|
||||
let print_points = |points: &Vec<PointRef>| {
|
||||
println!(
|
||||
"origin, p1, p2, p3:\n {:?}\n {:?}\n {:?}\n {:?}",
|
||||
points[0], points[1], points[2], points[3],
|
||||
"origin, p1, p2, p3:\n {}\n {}\n {}\n {}",
|
||||
points[0].borrow(), points[1].borrow(), points[2].borrow(), points[3].borrow(),
|
||||
);
|
||||
};
|
||||
print_points(&points);
|
||||
// let c1 = relation::Coincident {
|
||||
// p1: origin.clone(),
|
||||
// p2: p1.clone(),
|
||||
// };
|
||||
let c2 = relation::PointAngle::new_vertical(p1.clone(), p2.clone());
|
||||
let c1 = relation::Coincident {
|
||||
p1: origin.clone(),
|
||||
p2: p1.clone(),
|
||||
};
|
||||
let c4 = relation::PointAngle::new_vertical(p1.clone(), p2.clone());
|
||||
let c3 = relation::PointAngle::new_horizontal(p2.clone(), p3.clone());
|
||||
let c4 = relation::AlignedDistance::new_vertical(p1.clone(), p2.clone(), 12.);
|
||||
let c2 = relation::AlignedDistance::new_vertical(p1.clone(), p2.clone(), 12.);
|
||||
let mut relations: Vec<Box<dyn Relation>> =
|
||||
vec![/*Box::new(c1), */Box::new(c2), Box::new(c3), Box::new(c4)];
|
||||
vec![/*Box::new(c1),*/ Box::new(c2), Box::new(c3), Box::new(c4)];
|
||||
let mut constrained: Vec<Box<dyn Relation>> = Vec::new();
|
||||
let mut any_underconstrained = true;
|
||||
let mut any_constrained = true;
|
||||
@ -60,17 +60,10 @@ fn main() {
|
||||
let newly_constrained = relations.drain_filter(|r| {
|
||||
let rr = r.resolve();
|
||||
println!("resolve result: {:?}", rr);
|
||||
println!(
|
||||
"origin, p1, p2, p3:\n {:?}\n {:?}\n {:?}\n {:?}",
|
||||
origin, p1, p2, p3
|
||||
);
|
||||
print_points(&points);
|
||||
let mut pos = p2.borrow().pos.val().clone();
|
||||
pos.x = pos.x.distribute().simplify();
|
||||
pos.y = pos.y.distribute().simplify();
|
||||
println!("p2 pos: {}", pos);
|
||||
let mut pos = p3.borrow().pos.val().clone();
|
||||
pos.x = pos.x.distribute().simplify();
|
||||
pos.y = pos.y.distribute().simplify();
|
||||
println!("p3 pos: {}", pos);
|
||||
match rr {
|
||||
ResolveResult::Underconstrained => {
|
||||
|
@ -147,11 +147,11 @@ fn group_sum(es: Exprs) -> Exprs {
|
||||
}
|
||||
|
||||
fn product_fold(l: Expr, r: Expr) -> Expr {
|
||||
use itertools::Itertools;
|
||||
use Expr::*;
|
||||
match (l, r) {
|
||||
(Const(lc), Const(rc)) => Const(lc * rc),
|
||||
(Const(c), o) | (o, Const(c)) if relative_eq!(c, 1.) => o,
|
||||
(Const(c), _) | (_, Const(c)) if relative_eq!(c, 0.) => Const(0.),
|
||||
(Div(num, den), mul) | (mul, Div(num, den)) => {
|
||||
if mul == *den {
|
||||
*num
|
||||
@ -165,30 +165,34 @@ fn product_fold(l: Expr, r: Expr) -> Expr {
|
||||
|
||||
fn group_product(es: Exprs) -> Exprs {
|
||||
use Expr::*;
|
||||
let mut common: BTreeMap<UnknownSet, Expr> = BTreeMap::new();
|
||||
// let mut common: BTreeMap<UnknownSet, Expr> = BTreeMap::new();
|
||||
let mut common: Option<Expr> = None;
|
||||
for e in es {
|
||||
let unkns = e.unknowns();
|
||||
match common.get_mut(&unkns) {
|
||||
// match common.get_mut(&unkns) {
|
||||
match &mut common {
|
||||
None => {
|
||||
match e {
|
||||
Const(c) if relative_eq!(c, 1.) => (),
|
||||
e => {
|
||||
common.insert(unkns, e);
|
||||
// common.insert(unkns, e);
|
||||
common = Some(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
Some(existing) => {
|
||||
match existing {
|
||||
Sum(ref mut es) => {
|
||||
// Product(ref mut es) => {
|
||||
// already failed at merging, so just add it to the list
|
||||
es.push(e);
|
||||
}
|
||||
// es.push(e);
|
||||
// }
|
||||
other => *other = product_fold(other.clone(), e),
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
common.into_iter().map(|(_, v)| v).collect()
|
||||
// common.into_iter().map(|(_, v)| v).collect()
|
||||
common.into_iter().collect()
|
||||
}
|
||||
|
||||
fn distribute_product_sums(mut es: Exprs) -> Expr {
|
||||
@ -276,22 +280,55 @@ impl Expr {
|
||||
Expr::new_div(Expr::Const(1.), den)
|
||||
}
|
||||
|
||||
pub fn is_zero(&self) -> bool {
|
||||
pub fn is_zero(self) -> bool {
|
||||
use Expr::*;
|
||||
match self {
|
||||
Const(c) => relative_eq!(*c, 0.),
|
||||
match self.simplify() {
|
||||
Const(c) => relative_eq!(c, 0.),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_one(&self) -> bool {
|
||||
pub fn is_one(self) -> bool {
|
||||
use Expr::*;
|
||||
match self {
|
||||
Const(c) => relative_eq!(*c, 1.),
|
||||
match self.simplify() {
|
||||
Const(c) => relative_eq!(c, 1.),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn evaluate_with(self, eqns: &Eqns) -> Expr {
|
||||
use Expr::*;
|
||||
for eqn in &eqns.0 {
|
||||
if self == eqn.0 {
|
||||
return eqn.1.clone();
|
||||
}
|
||||
}
|
||||
match self {
|
||||
Sum(mut es) => {
|
||||
for e in &mut es {
|
||||
*e = e.clone().evaluate_with(eqns);
|
||||
}
|
||||
Sum(es)
|
||||
}
|
||||
Product(mut es) => {
|
||||
for e in &mut es {
|
||||
*e = e.clone().evaluate_with(eqns);
|
||||
}
|
||||
Product(es)
|
||||
}
|
||||
Neg(mut e) => {
|
||||
*e = e.evaluate_with(eqns);
|
||||
Neg(e)
|
||||
}
|
||||
Div(mut num, mut den) => {
|
||||
*num = num.evaluate_with(eqns);
|
||||
*den = den.evaluate_with(eqns);
|
||||
Div(num, den)
|
||||
}
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn simplify(self) -> Expr {
|
||||
use Expr::*;
|
||||
match self {
|
||||
|
482
src/math/mod.rs
482
src/math/mod.rs
@ -1,8 +1,12 @@
|
||||
use std::fmt;
|
||||
|
||||
pub mod eqn;
|
||||
pub mod ops;
|
||||
pub mod vec;
|
||||
|
||||
pub use eqn::Unknown;
|
||||
pub use eqn::{Expr, Unknown};
|
||||
pub use ops::*;
|
||||
pub use vec::*;
|
||||
|
||||
pub type Scalar = f64;
|
||||
// #[derive(Clone, Copy, PartialEq, Debug)]
|
||||
@ -14,236 +18,110 @@ pub type Value = eqn::Expr;
|
||||
|
||||
// pub type Vec2 = nalgebra::Vector2<Value>;
|
||||
// pub type Point2 = nalgebra::Point2<Value>;
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct Vec2 {
|
||||
pub x: Value,
|
||||
pub y: Value,
|
||||
}
|
||||
|
||||
impl Vec2 {
|
||||
pub fn new(x: Value, y: Value) -> Self {
|
||||
Self { x, y }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Add<Vec2> for Vec2 {
|
||||
type Output = Vec2;
|
||||
fn add(self, rhs: Vec2) -> Vec2 {
|
||||
Vec2 {
|
||||
x: self.x + rhs.x,
|
||||
y: self.y + rhs.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct Point2 {
|
||||
pub x: Value,
|
||||
pub y: Value,
|
||||
}
|
||||
|
||||
impl Point2 {
|
||||
pub fn new(x: Value, y: Value) -> Point2 {
|
||||
Point2 { x, y }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Add<Vec2> for Point2 {
|
||||
type Output = Point2;
|
||||
fn add(self, rhs: Vec2) -> Point2 {
|
||||
Point2 {
|
||||
x: self.x + rhs.x,
|
||||
y: self.y + rhs.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Sub<Vec2> for Point2 {
|
||||
type Output = Point2;
|
||||
fn sub(self, rhs: Vec2) -> Point2 {
|
||||
Point2 {
|
||||
x: self.x - rhs.x,
|
||||
y: self.y - rhs.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Sub<Point2> for Point2 {
|
||||
type Output = Vec2;
|
||||
fn sub(self, rhs: Point2) -> Vec2 {
|
||||
Vec2 {
|
||||
x: self.x - rhs.x,
|
||||
y: self.y - rhs.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use std::fmt;
|
||||
|
||||
impl fmt::Display for Point2 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "({}, {})", self.x, self.y)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct Rot2 {
|
||||
cos: Value,
|
||||
sin: Value,
|
||||
}
|
||||
|
||||
impl Rot2 {
|
||||
pub fn from_cos_sin_unchecked(cos: Value, sin: Value) -> Self {
|
||||
Self { cos, sin }
|
||||
}
|
||||
|
||||
pub fn from_angle(angle: Scalar) -> Self {
|
||||
Self {
|
||||
cos: angle.cos().into(),
|
||||
sin: angle.sin().into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cardinal(index: i64) -> Self {
|
||||
match index % 4 {
|
||||
0 => Rot2 {
|
||||
cos: (1.).into(),
|
||||
sin: (0.).into(),
|
||||
},
|
||||
1 => Rot2 {
|
||||
cos: (0.).into(),
|
||||
sin: (1.).into(),
|
||||
},
|
||||
2 => Rot2 {
|
||||
cos: (-1.).into(),
|
||||
sin: (0.).into(),
|
||||
},
|
||||
3 => Rot2 {
|
||||
cos: (0.).into(),
|
||||
sin: (-1.).into(),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cos(&self) -> &Value {
|
||||
&self.cos
|
||||
}
|
||||
|
||||
pub fn sin(&self) -> &Value {
|
||||
&self.sin
|
||||
}
|
||||
|
||||
pub fn conj(self) -> Self {
|
||||
Self {
|
||||
cos: self.cos,
|
||||
sin: -self.sin,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Mul<Scalar> for Rot2 {
|
||||
type Output = Vec2;
|
||||
fn mul(self, rhs: Scalar) -> Vec2 {
|
||||
Vec2 {
|
||||
x: self.cos * rhs,
|
||||
y: self.sin * rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Mul<Value> for Rot2 {
|
||||
type Output = Vec2;
|
||||
fn mul(self, rhs: Value) -> Vec2 {
|
||||
Vec2 {
|
||||
x: self.cos * rhs.clone(),
|
||||
y: self.sin * rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Add<Rot2> for Rot2 {
|
||||
type Output = Rot2;
|
||||
fn add(self, rhs: Rot2) -> Rot2 {
|
||||
Rot2 {
|
||||
cos: self.cos.clone() * rhs.cos.clone() - self.sin.clone() * rhs.sin.clone(),
|
||||
sin: self.cos * rhs.sin + self.sin * rhs.cos,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Sub<Rot2> for Rot2 {
|
||||
type Output = Rot2;
|
||||
fn sub(self, rhs: Rot2) -> Rot2 {
|
||||
Rot2 {
|
||||
cos: self.cos.clone() * rhs.cos.clone() + self.sin.clone() * rhs.sin.clone(),
|
||||
sin: self.sin * rhs.cos - self.cos * rhs.sin,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Mul<Vec2> for Rot2 {
|
||||
type Output = Vec2;
|
||||
fn mul(self, rhs: Vec2) -> Vec2 {
|
||||
Vec2 {
|
||||
x: self.cos.clone() * rhs.x.clone() - self.sin.clone() * rhs.y.clone(),
|
||||
y: self.cos * rhs.y + self.sin * rhs.x,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pub type Rot2 = nalgebra::UnitComplex<Value>;
|
||||
|
||||
pub trait Region<T> {
|
||||
fn full() -> Self;
|
||||
fn singleton(value: T) -> Self;
|
||||
// fn intersection(self, other: Self) -> Self;
|
||||
|
||||
fn nearest(&self, value: &T) -> Option<T>;
|
||||
fn contains(&self, value: &T) -> bool;
|
||||
fn contains(&self, value: &T) -> Option<bool>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Region1 {
|
||||
Empty,
|
||||
Singleton(Scalar),
|
||||
Range(Scalar, Scalar),
|
||||
Union(Box<Region1>, Box<Region1>),
|
||||
Singleton(Value),
|
||||
Range(Value, Value),
|
||||
Intersection(Box<Region1>, Box<Region1>),
|
||||
// Union(Box<Region1>, Box<Region1>),
|
||||
Full,
|
||||
}
|
||||
|
||||
impl fmt::Display for Region1 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use Region1::*;
|
||||
match self {
|
||||
Empty => write!(f, "Ø"),
|
||||
Singleton(v) => write!(f, "{{ {} }}", v),
|
||||
Range(l, u) => write!(f, "[ {}, {} ]", l, u),
|
||||
Intersection(r1, r2) => write!(f, "{} ∩ {}", r1, r2),
|
||||
Full => write!(f, "ℝ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Region1 {
|
||||
pub fn intersection(self, other: Region1) -> Self {
|
||||
Region1::Intersection(Box::new(self), Box::new(other))
|
||||
}
|
||||
|
||||
pub fn simplify(self) -> Self {
|
||||
use Region1::*;
|
||||
match self {
|
||||
Singleton(n) => Singleton(n.simplify()),
|
||||
Range(l, u) => Range(l.simplify(), u.simplify()),
|
||||
Intersection(r1, r2) => r1.simplify().intersection(r2.simplify()),
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Region<Scalar> for Region1 {
|
||||
fn full() -> Self {
|
||||
Region1::Full
|
||||
}
|
||||
|
||||
fn singleton(value: Scalar) -> Self {
|
||||
Region1::Singleton(value)
|
||||
Region1::Singleton(value.into())
|
||||
}
|
||||
|
||||
fn contains(&self, n: &Scalar) -> bool {
|
||||
fn contains(&self, n: &Scalar) -> Option<bool> {
|
||||
use Expr::Const;
|
||||
use Region1::*;
|
||||
match self {
|
||||
Empty => false,
|
||||
Singleton(n1) => relative_eq!(n1, n),
|
||||
Range(l, u) => *l <= *n && *n <= *u,
|
||||
Union(r1, r2) => r1.contains(n) || r2.contains(n),
|
||||
Full => true,
|
||||
Empty => Some(false),
|
||||
Singleton(n1) => match n1 {
|
||||
Const(c) => Some(relative_eq!(c, n)),
|
||||
_ => None,
|
||||
},
|
||||
Range(l, u) => match (l, u) {
|
||||
(Const(cl), Const(cu)) => Some(*cl <= *n && *n <= *cu),
|
||||
_ => None,
|
||||
},
|
||||
Intersection(r1, r2) => r1
|
||||
.contains(n)
|
||||
.and_then(|c1| r2.contains(n).map(|c2| c1 && c2)),
|
||||
// Union(r1, r2) => r1.contains(n) || r2.contains(n),
|
||||
Full => Some(true),
|
||||
}
|
||||
}
|
||||
|
||||
fn nearest(&self, s: &Scalar) -> Option<Scalar> {
|
||||
use Expr::Const;
|
||||
use Region1::*;
|
||||
match self {
|
||||
Empty => None,
|
||||
Full => Some(*s),
|
||||
Singleton(n) => Some(*n),
|
||||
Range(l, u) => match (l < s, s < u) {
|
||||
(true, true) => Some(*s),
|
||||
(true, false) => Some(*u),
|
||||
(false, true) => Some(*l),
|
||||
Singleton(n) => match n {
|
||||
Const(c) => Some(*c),
|
||||
_ => None,
|
||||
},
|
||||
Union(r1, r2) => {
|
||||
Range(l, u) => match (l, u) {
|
||||
(Const(cl), Const(cu)) => match (cl < s, s < cu) {
|
||||
(true, true) => Some(*s),
|
||||
(true, false) => Some(*cu),
|
||||
(false, true) => Some(*cl),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
},
|
||||
Intersection(r1, r2) => {
|
||||
unimplemented!()
|
||||
}
|
||||
/*Union(r1, r2) => {
|
||||
let distance = |a: Scalar, b: Scalar| (a - b).abs();
|
||||
match (r1.nearest(s), r2.nearest(s)) {
|
||||
(None, None) => None,
|
||||
@ -256,7 +134,7 @@ impl Region<Scalar> for Region1 {
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -265,54 +143,91 @@ impl Region<Scalar> for Region1 {
|
||||
// ie. start + (cos dir, sin dir) * t for t in extent
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Line2 {
|
||||
start: Point2,
|
||||
start: Point2<Value>,
|
||||
dir: Rot2,
|
||||
extent: Region1,
|
||||
}
|
||||
|
||||
impl fmt::Display for Line2 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{{ (x, y) = {} + {} * {} }}", self.start, self.dir, self.extent)
|
||||
}
|
||||
}
|
||||
|
||||
impl Line2 {
|
||||
pub fn new(start: Point2, dir: Rot2, extent: Region1) -> Self {
|
||||
pub fn new(start: Point2<Value>, dir: Rot2, extent: Region1) -> Self {
|
||||
Self { start, dir, extent }
|
||||
}
|
||||
|
||||
pub fn evaluate(&self, t: Value) -> Point2 {
|
||||
pub fn evaluate(&self, t: Value) -> Point2<Value> {
|
||||
self.start.clone() + self.dir.clone() * t
|
||||
}
|
||||
|
||||
pub fn nearest(&self, p: &Point2) -> Point2 {
|
||||
pub fn evaluate_extent(&self) -> Option<Point2<Value>> {
|
||||
match &self.extent {
|
||||
Region1::Singleton(t) => Some(self.evaluate(t.clone())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_extent(self, new_extent: Region1) -> Line2 {
|
||||
Line2 { start: self.start, dir: self.dir, extent: new_extent }
|
||||
}
|
||||
|
||||
pub fn nearest(&self, p: &Point2<Value>) -> Point2<Value> {
|
||||
// rotate angle 90 degrees
|
||||
let perp_dir = self.dir.clone() + Rot2::cardinal(1);
|
||||
let perp = Line2::new(p.clone(), perp_dir, Region1::Full);
|
||||
if let Region2::Singleton(np) = self.intersect(&perp) {
|
||||
np
|
||||
} else {
|
||||
panic!("Line2::nearest not found!");
|
||||
match self.intersect(&perp) {
|
||||
Region2::Singleton(np) => np,
|
||||
Region2::Line(l) => l.evaluate_extent().expect("Line2::nearest not found"),
|
||||
_ => panic!("Line2::nearest not found!")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intersect(&self, other: &Line2) -> Region2 {
|
||||
// if the two lines are parallel...
|
||||
let dirs = self.dir.clone() - other.dir.clone();
|
||||
/*
|
||||
if relative_eq!(dirs.sin(), 0.) {
|
||||
let starts = self.dir.to_rotation_matrix().inverse() * (other.start - self.start);
|
||||
return if relative_eq!(starts.y, 0.) {
|
||||
let starts = self.dir.conj() * (other.start.clone() - self.start.clone());
|
||||
return if starts.y.simplify().is_zero() {
|
||||
// and they are colinear
|
||||
Region2::Line(self.clone())
|
||||
} else {
|
||||
// they are parallel and never intersect
|
||||
Region2::Empty
|
||||
};
|
||||
}*/
|
||||
}
|
||||
// TODO: respect extent
|
||||
let (a, b) = (self, other);
|
||||
let (a_0, a_v, b_0, b_v) = (a.start.clone(), a.dir.clone(), b.start.clone(), b.dir.clone());
|
||||
let (a_0, a_v, b_0, b_v) = (
|
||||
a.start.clone(),
|
||||
a.dir.clone(),
|
||||
b.start.clone(),
|
||||
b.dir.clone(),
|
||||
);
|
||||
let (a_c, a_s, b_c, b_s) = (a_v.cos(), a_v.sin(), b_v.cos(), b_v.sin());
|
||||
let t_b = (a_0.x.clone() * a_s.clone() - a_0.y.clone() * a_c.clone()
|
||||
+ a_0.x.clone() * a_s.clone()
|
||||
- b_0.x.clone() * a_s.clone()
|
||||
+ b_0.y.clone() * a_c.clone())
|
||||
/ (a_s.clone() * b_c.clone() - a_c.clone() * b_s.clone());
|
||||
Region2::Singleton(b.evaluate(t_b))
|
||||
// Region2::Singleton(b.evaluate(t_b))
|
||||
let res = Region2::Line(b.clone().with_extent(Region1::Singleton(t_b.simplify())));
|
||||
trace!("intersect a: {}, b: {} = {}", a, b, res);
|
||||
res
|
||||
}
|
||||
|
||||
pub fn simplify(self) -> Region2 {
|
||||
let new_l = Line2 {
|
||||
start: self.start.simplify(),
|
||||
dir: self.dir,
|
||||
extent: self.extent.simplify(),
|
||||
};
|
||||
trace!("line {}: simplify evaluate extent: {:?}", new_l, new_l.evaluate_extent());
|
||||
if let Some(p) = new_l.evaluate_extent() {
|
||||
return Region2::Singleton(p.simplify());
|
||||
}
|
||||
Region2::Line(new_l)
|
||||
}
|
||||
}
|
||||
|
||||
@ -320,53 +235,133 @@ impl Line2 {
|
||||
pub enum Region2 {
|
||||
Empty,
|
||||
// single point at 0
|
||||
Singleton(Point2),
|
||||
Singleton(Point2<Value>),
|
||||
Line(Line2),
|
||||
#[allow(dead_code)]
|
||||
Union(Box<Region2>, Box<Region2>),
|
||||
// #[allow(dead_code)]
|
||||
// Union(Box<Region2>, Box<Region2>),
|
||||
Intersection(Box<Region2>, Box<Region2>),
|
||||
Full,
|
||||
}
|
||||
|
||||
impl Region<Point2> for Region2 {
|
||||
impl fmt::Display for Region2 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use Region2::*;
|
||||
match self {
|
||||
Empty => write!(f, "ز"),
|
||||
Singleton(v) => write!(f, "{{ {} }}", v),
|
||||
Line(l) => l.fmt(f),
|
||||
Intersection(r1, r2) => write!(f, "{} ∩ {}", r1, r2),
|
||||
Full => write!(f, "ℝ²")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Region<Point2<Scalar>> for Region2 {
|
||||
fn full() -> Self {
|
||||
Region2::Full
|
||||
}
|
||||
|
||||
fn singleton(value: Point2) -> Self {
|
||||
fn singleton(value: Point2<Scalar>) -> Self {
|
||||
Region2::Singleton(value.into())
|
||||
}
|
||||
|
||||
fn contains(&self, p: &Point2<Scalar>) -> Option<bool> {
|
||||
self.nearest(p).map(|n| n == *p)
|
||||
}
|
||||
|
||||
fn nearest(&self, p: &Point2<Scalar>) -> Option<Point2<Scalar>> {
|
||||
use Expr::Const;
|
||||
use Region2::*;
|
||||
match self {
|
||||
Empty => None,
|
||||
Full => Some(p.clone()),
|
||||
Singleton(n) => match (&n.x, &n.y) {
|
||||
(Const(cx), Const(cy)) => Some(Point2::new(*cx, *cy)),
|
||||
_ => None,
|
||||
},
|
||||
Line(line) => {
|
||||
let pv: Point2<Value> = p.clone().into();
|
||||
let n = line.nearest(&pv).simplify();
|
||||
trace!("line {} nearest to {}: {}", line, pv, n);
|
||||
match (n.x, n.y) {
|
||||
(Const(cx), Const(cy)) => Some(Point2::new(cx, cy)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
Intersection(r1, r2) => {
|
||||
None
|
||||
// r1.clone().intersect((**r2).clone()).nearest(p)
|
||||
}
|
||||
/*Union(r1, r2) => {
|
||||
use nalgebra::distance;
|
||||
match (r1.nearest(p), r2.nearest(p)) {
|
||||
(None, None) => None,
|
||||
(Some(n), None) | (None, Some(n)) => Some(n),
|
||||
(Some(n1), Some(n2)) => Some({
|
||||
if distance(p, &n1) <= distance(p, &n2) {
|
||||
n1
|
||||
} else {
|
||||
n2
|
||||
}
|
||||
}),
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Region<Point2<Value>> for Region2 {
|
||||
fn full() -> Self {
|
||||
Region2::Full
|
||||
}
|
||||
|
||||
fn singleton(value: Point2<Value>) -> Self {
|
||||
Region2::Singleton(value)
|
||||
}
|
||||
|
||||
fn contains(&self, p: &Point2) -> bool {
|
||||
self.nearest(p)
|
||||
.map_or(false, |n| true /*relative_eq!(n, p)*/)
|
||||
fn contains(&self, p: &Point2<Value>) -> Option<bool> {
|
||||
self.nearest(p).map(|n| n.simplify() == p.clone().simplify())
|
||||
}
|
||||
|
||||
fn nearest(&self, p: &Point2) -> Option<Point2> {
|
||||
fn nearest(&self, p: &Point2<Value>) -> Option<Point2<Value>> {
|
||||
use Region2::*;
|
||||
match self {
|
||||
Empty => None,
|
||||
Full => Some(p.clone()),
|
||||
Singleton(n) => Some(n.clone()),
|
||||
Line(line) => Some(line.nearest(p)),
|
||||
Union(r1, r2) => {
|
||||
Intersection(r1, r2) => {
|
||||
r1.clone().intersect((**r2).clone()).nearest(p)
|
||||
}
|
||||
/*Union(r1, r2) => {
|
||||
use nalgebra::distance;
|
||||
match (r1.nearest(p), r2.nearest(p)) {
|
||||
(None, None) => None,
|
||||
(Some(n), None) | (None, Some(n)) => Some(n),
|
||||
(Some(n1), Some(n2)) => Some({
|
||||
// if distance(p, &n1) <= distance(p, &n2) {
|
||||
n1
|
||||
// } else {
|
||||
// n2
|
||||
// }
|
||||
if distance(p, &n1) <= distance(p, &n2) {
|
||||
n1
|
||||
} else {
|
||||
n2
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Region2 {
|
||||
pub fn intersection(self, other: Self) -> Self {
|
||||
use Region2::*;
|
||||
match (self, other) {
|
||||
(Empty, _) | (_, Empty) => Empty,
|
||||
(Full, r) | (r, Full) => r,
|
||||
(r1, r2) => Intersection(Box::new(r1), Box::new(r2)),
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn union(r1: Region2, r2: Region2) -> Region2 {
|
||||
use Region2::*;
|
||||
match (r1, r2) {
|
||||
@ -375,30 +370,45 @@ impl Region2 {
|
||||
(r1, r2) => Union(Box::new(r1), Box::new(r2)),
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn intersect(&self, other: &Region2) -> Region2 {
|
||||
pub fn intersect(self, other: Region2) -> Region2 {
|
||||
use Region2::*;
|
||||
match (self, other) {
|
||||
(Empty, _) | (_, Empty) => Empty,
|
||||
(Full, r) | (r, Full) => r.clone(),
|
||||
(Singleton(n1), Singleton(n2)) => {
|
||||
if n1 == n2 {
|
||||
Singleton(n1.clone())
|
||||
Singleton(n1)
|
||||
} else {
|
||||
Empty
|
||||
Region2::intersection(Singleton(n1), Singleton(n2))
|
||||
}
|
||||
}
|
||||
(Singleton(n), o) | (o, Singleton(n)) => {
|
||||
if o.contains(n) {
|
||||
Singleton(n.clone())
|
||||
if o.contains(&n).unwrap_or(false) {
|
||||
Singleton(n)
|
||||
} else {
|
||||
Empty
|
||||
Region2::intersection(Singleton(n), o)
|
||||
}
|
||||
}
|
||||
(Line(l1), Line(l2)) => l1.intersect(l2),
|
||||
(Union(un1, un2), o) | (o, Union(un1, un2)) => {
|
||||
Self::union(un1.intersect(o), un2.intersect(o))
|
||||
(Intersection(r1, r2), o) | (o, Intersection(r1, r2)) => {
|
||||
r1.intersect(*r2).intersect(o)
|
||||
}
|
||||
(Line(l1), Line(l2)) => l1.intersect(&l2).simplify(),
|
||||
/*(Union(un1, un2), o) | (o, Union(un1, un2)) => {
|
||||
Self::union(un1.intersect(o), un2.intersect(o))
|
||||
}*/
|
||||
(r1, r2) => Intersection(Box::new(r1), Box::new(r2)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn simplify(self) -> Region2 {
|
||||
use Region2::*;
|
||||
match self {
|
||||
Singleton(n) => Singleton(n.simplify()),
|
||||
Line(l) => l.simplify(),
|
||||
Intersection(r1, r2) => r1.simplify().intersect(r2.simplify()),
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
276
src/math/vec.rs
Normal file
276
src/math/vec.rs
Normal file
@ -0,0 +1,276 @@
|
||||
use super::{Scalar, Value};
|
||||
|
||||
use std::ops;
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct Vec2<T> {
|
||||
pub x: T,
|
||||
pub y: T,
|
||||
}
|
||||
|
||||
impl<T> Vec2<T> {
|
||||
pub fn new(x: T, y: T) -> Self {
|
||||
Self { x, y }
|
||||
}
|
||||
}
|
||||
|
||||
impl Vec2<Scalar> {
|
||||
pub fn normal2(self) -> Scalar {
|
||||
self.x * self.x + self.y * self.y
|
||||
}
|
||||
|
||||
pub fn normal(self) -> Scalar {
|
||||
self.normal2().sqrt()
|
||||
}
|
||||
|
||||
pub fn normalize(self) -> Vec2<Scalar> {
|
||||
self.clone() / self.normal()
|
||||
}
|
||||
}
|
||||
|
||||
impl Vec2<Value> {
|
||||
pub fn simplify(self) -> Self {
|
||||
Self {
|
||||
x: self.x.simplify(),
|
||||
y: self.y.simplify(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ops::Add<U>, U> ops::Add<Vec2<U>> for Vec2<T> {
|
||||
type Output = Vec2<T::Output>;
|
||||
fn add(self, rhs: Vec2<U>) -> Self::Output {
|
||||
Self::Output {
|
||||
x: self.x + rhs.x,
|
||||
y: self.y + rhs.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ops::Sub<U>, U> ops::Sub<Vec2<U>> for Vec2<T> {
|
||||
type Output = Vec2<T::Output>;
|
||||
fn sub(self, rhs: Vec2<U>) -> Self::Output {
|
||||
Self::Output {
|
||||
x: self.x - rhs.x,
|
||||
y: self.y - rhs.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ops::Mul<U>, U: Clone> ops::Mul<U> for Vec2<T> {
|
||||
type Output = Vec2<T::Output>;
|
||||
fn mul(self, rhs: U) -> Self::Output {
|
||||
Self::Output {
|
||||
x: self.x * rhs.clone(),
|
||||
y: self.y * rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ops::Div<U>, U: Clone> ops::Div<U> for Vec2<T> {
|
||||
type Output = Vec2<T::Output>;
|
||||
fn div(self, rhs: U) -> Self::Output {
|
||||
Self::Output {
|
||||
x: self.x / rhs.clone(),
|
||||
y: self.y / rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct Point2<T> {
|
||||
pub x: T,
|
||||
pub y: T,
|
||||
}
|
||||
|
||||
impl<T> Point2<T> {
|
||||
pub fn new(x: T, y: T) -> Point2<T> {
|
||||
Point2 { x, y }
|
||||
}
|
||||
}
|
||||
|
||||
impl Point2<Value> {
|
||||
pub fn simplify(self) -> Self {
|
||||
Self {
|
||||
x: self.x.simplify(),
|
||||
y: self.y.simplify(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Point2<Scalar>> for Point2<Value> {
|
||||
fn from(sp: Point2<Scalar>) -> Self {
|
||||
Self { x: sp.x.into(), y: sp.y.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ops::Add<U>, U> ops::Add<Vec2<U>> for Point2<T> {
|
||||
type Output = Point2<T::Output>;
|
||||
fn add(self, rhs: Vec2<U>) -> Self::Output {
|
||||
Point2 {
|
||||
x: self.x + rhs.x,
|
||||
y: self.y + rhs.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ops::Sub<U>, U> ops::Sub<Vec2<U>> for Point2<T> {
|
||||
type Output = Point2<T::Output>;
|
||||
fn sub(self, rhs: Vec2<U>) -> Self::Output {
|
||||
Point2 {
|
||||
x: self.x - rhs.x,
|
||||
y: self.y - rhs.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ops::Sub<U>, U> ops::Sub<Point2<U>> for Point2<T> {
|
||||
type Output = Vec2<T::Output>;
|
||||
fn sub(self, rhs: Point2<U>) -> Self::Output {
|
||||
Vec2 {
|
||||
x: self.x - rhs.x,
|
||||
y: self.y - rhs.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use std::fmt;
|
||||
|
||||
impl<T: fmt::Display> fmt::Display for Point2<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "({}, {})", self.x, self.y)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub struct Rot2 {
|
||||
cos: Scalar,
|
||||
sin: Scalar,
|
||||
}
|
||||
|
||||
impl fmt::Display for Rot2 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "({}, {})", self.cos, self.sin)
|
||||
}
|
||||
}
|
||||
|
||||
impl Rot2 {
|
||||
pub fn from_cos_sin_unchecked(cos: Scalar, sin: Scalar) -> Self {
|
||||
Self { cos, sin }
|
||||
}
|
||||
|
||||
pub fn from_cos_sin(cos: Scalar, sin: Scalar) -> Self {
|
||||
Vec2 { x: cos, y: sin }.into()
|
||||
}
|
||||
|
||||
pub fn from_angle(angle: Scalar) -> Self {
|
||||
Self {
|
||||
cos: angle.cos().into(),
|
||||
sin: angle.sin().into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cardinal(index: i64) -> Self {
|
||||
match index % 4 {
|
||||
0 => Rot2 {
|
||||
cos: (1.).into(),
|
||||
sin: (0.).into(),
|
||||
},
|
||||
1 => Rot2 {
|
||||
cos: (0.).into(),
|
||||
sin: (1.).into(),
|
||||
},
|
||||
2 => Rot2 {
|
||||
cos: (-1.).into(),
|
||||
sin: (0.).into(),
|
||||
},
|
||||
3 => Rot2 {
|
||||
cos: (0.).into(),
|
||||
sin: (-1.).into(),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cos(&self) -> Scalar {
|
||||
self.cos
|
||||
}
|
||||
|
||||
pub fn sin(&self) -> Scalar {
|
||||
self.sin
|
||||
}
|
||||
|
||||
pub fn conj(self) -> Self {
|
||||
Self {
|
||||
cos: self.cos,
|
||||
sin: -self.sin,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec2<Scalar>> for Rot2 {
|
||||
fn from(v: Vec2<Scalar>) -> Rot2 {
|
||||
let v = v.normalize();
|
||||
Rot2 { cos: v.x, sin: v.y }
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Mul<Scalar> for Rot2 {
|
||||
type Output = Vec2<Scalar>;
|
||||
fn mul(self, rhs: Scalar) -> Vec2<Scalar> {
|
||||
Vec2 {
|
||||
x: self.cos * rhs,
|
||||
y: self.sin * rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Mul<Value> for Rot2 {
|
||||
type Output = Vec2<Value>;
|
||||
fn mul(self, rhs: Value) -> Vec2<Value> {
|
||||
Vec2 {
|
||||
x: rhs.clone() * self.cos,
|
||||
y: rhs * self.sin,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Add<Rot2> for Rot2 {
|
||||
type Output = Rot2;
|
||||
fn add(self, rhs: Rot2) -> Rot2 {
|
||||
Rot2 {
|
||||
cos: self.cos.clone() * rhs.cos.clone() - self.sin.clone() * rhs.sin.clone(),
|
||||
sin: self.cos * rhs.sin + self.sin * rhs.cos,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Sub<Rot2> for Rot2 {
|
||||
type Output = Rot2;
|
||||
fn sub(self, rhs: Rot2) -> Rot2 {
|
||||
Rot2 {
|
||||
cos: self.cos.clone() * rhs.cos.clone() + self.sin.clone() * rhs.sin.clone(),
|
||||
sin: self.sin * rhs.cos - self.cos * rhs.sin,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Mul<Vec2<Scalar>> for Rot2 {
|
||||
type Output = Vec2<Scalar>;
|
||||
fn mul(self, rhs: Vec2<Scalar>) -> Vec2<Scalar> {
|
||||
Vec2 {
|
||||
x: self.cos * rhs.x - self.sin * rhs.y,
|
||||
y: self.cos * rhs.y + self.sin * rhs.x,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Mul<Vec2<Value>> for Rot2 {
|
||||
type Output = Vec2<Value>;
|
||||
fn mul(self, rhs: Vec2<Value>) -> Vec2<Value> {
|
||||
Vec2 {
|
||||
x: rhs.x.clone() * self.cos - rhs.y.clone() * self.sin,
|
||||
y: rhs.y * self.cos + rhs.x * self.sin,
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::entity::{Point as PointEntity, PointRef};
|
||||
use crate::math::{Line2, Vec2, Point2, Region1, Region2, Rot2, Scalar};
|
||||
use crate::math::{Line2, Vec2, Point2, Region1, Region2, Rot2, Scalar, Value, Region};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum ResolveResult {
|
||||
@ -31,7 +31,7 @@ pub struct Coincident {
|
||||
impl Relation for Coincident {
|
||||
fn resolve(&self) -> ResolveResult {
|
||||
let (mut p1, mut p2) = (self.p1.borrow_mut(), self.p2.borrow_mut());
|
||||
let r = { p1.pos.constraints().intersect(p2.pos.constraints()) };
|
||||
let r = { p1.pos.constraints().clone().intersect(p2.pos.constraints().clone()).simplify() };
|
||||
p1.pos.reconstrain(r.clone());
|
||||
p2.pos.reconstrain(r.clone());
|
||||
ResolveResult::from_r2(&r)
|
||||
@ -62,9 +62,9 @@ impl Relation for PointAngle {
|
||||
fn resolve(&self) -> ResolveResult {
|
||||
use Region2::*;
|
||||
let (mut p1, mut p2) = (self.p1.borrow_mut(), self.p2.borrow_mut());
|
||||
let constrain_line = |p1: &Point2, p2: &mut PointEntity| {
|
||||
let constrain_line = |p1: &Point2<Value>, p2: &mut PointEntity| {
|
||||
let line = Region2::Line(Line2::new(p1.clone(), self.angle.clone(), Region1::Full));
|
||||
let new_constraint = p2.pos.constraints().intersect(&line);
|
||||
let new_constraint = p2.pos.constraints().clone().intersection(line).simplify();
|
||||
p2.pos.reconstrain(new_constraint);
|
||||
ResolveResult::from_r2(p2.pos.constraints())
|
||||
};
|
||||
@ -123,17 +123,17 @@ impl Relation for AlignedDistance {
|
||||
fn resolve(&self) -> ResolveResult {
|
||||
use Region2::*;
|
||||
let (mut p1, mut p2) = (self.p1.borrow_mut(), self.p2.borrow_mut());
|
||||
let constrain_line = |p1: Point2, p2: &mut PointEntity| {
|
||||
let constrain_line = |p1: Point2<Value>, p2: &mut PointEntity| {
|
||||
let angle = match self.axis {
|
||||
Axis::Horizontal => Rot2::from_cos_sin_unchecked((0.).into(), (1.).into()),
|
||||
Axis::Vertical => Rot2::from_cos_sin_unchecked((1.).into(), (0.).into()),
|
||||
};
|
||||
let line = Region2::Line(Line2::new(p1, angle, Region1::Full));
|
||||
let new_constraint = p2.pos.constraints().intersect(&line);
|
||||
let line = Region2::Line(Line2::new(p1.clone(), angle, Region1::Full));
|
||||
let new_constraint = p2.pos.constraints().clone().intersection(line).simplify();
|
||||
p2.pos.reconstrain(new_constraint);
|
||||
ResolveResult::from_r2(p2.pos.constraints())
|
||||
};
|
||||
let offset = match self.axis {
|
||||
let offset: Vec2<Scalar> = match self.axis {
|
||||
Axis::Horizontal => Vec2::new(self.distance.into(), (0.).into()),
|
||||
Axis::Vertical => Vec2::new((0.).into(), self.distance.into()),
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user