我可以简化分离轴定理的这种实现吗?

时间:2017-12-06 10:14:07

标签: rust collision-detection separating-axis-theorem

我有一个基于分离轴定理(SAT)的凸二维多边形与凸二维多边形碰撞测试。

我的问题是: 是否可能在不校正某种形式的MTV方向的情况下实现该算法? (通过注意缠绕顺序,向外的法线或其他我可能错误的细节)。

SAT产生最小的平移向量。我发现很难让MTV的方向正确,因为它指向错误的方向大约一半的时间(如果多边形A和B传递给碰撞检测功能,则MTV应始终为A)。只有在添加检查两个投影之间重叠方向的代码之后,它才开始正常工作,而不仅仅是两个投影重叠。

pub struct Projection {
    min: f64,
    max: f64,
}

impl Projection {
   // omitted some other functions not relevant to the question

   /// Calculates the direction of overlap between two projections.
   /// In case of no overlap, None is returned
   pub fn overlap(&self, other: &Self) -> Option<f64> {
        let sum = (self.max - self.min) + (other.max - other.min);    
        let extent = self.max.max(other.max) - self.min.min(other.min);
        if (sum - extent).is_sign_negative() {
            None
        }
        else if self.max - other.min < other.max - self.min {
            Some(self.max - other.min)
        } else { 
            Some(self.min - other.max)
        }
    }
}

但是我觉得我可能错过了一个重要的细节,因为我读过的有关SAT的各种文章和评论都提到了面向外的多边形法线,并且MTV方向的主题得到了相对较少的关注(如如果这很简单,对我来说这是最难的部分。)

我的SAT实现的核心是这个函数,它被调用两次。第二次调用函数时,参数顺序反转,这会影响MTV方向,但我很清楚这一点。

fn find_mtv(a: &Convex, b: &Convex) -> Option<MtvComponents> {   
    let mut comps = MtvComponents::new();
    for axis in a.iter_normals().map(Vector::normalize) {
        let proj_a = Projection::new(a.iter_vertices(), axis);
        let proj_b = Projection::new(b.iter_vertices(), axis);
        if let Some(overlap) = proj_a.overlap(&proj_b) {
            comps.store_min(overlap, axis);
        } else {
            return None
        }
    }
    Some(comps)
}

0 个答案:

没有答案