检查鼠标是否在C ++三角形内

时间:2014-04-02 08:38:14

标签: c++ visual-c++ math trigonometry

我正在申请学校,我必须点击特定的对象。

编辑:这是在2D中进行的

我有一个矩形,我用X旋转这个矩形。 矩形的旋转使我的矩形(x,y,宽度,高度)成为旋转矩形周围的新矩形。

http://i.stack.imgur.com/MejMA.png (请原谅我糟糕的油漆技巧)

黑线描述旋转的矩形,红线是我的新矩形。 我需要找出我的鼠标是否在黑色矩形内。无论我做什么旋转,我都有一个函数来获取黑色矩形每个角的(X,Y)。

现在我正在尝试实施此Check if point is within triangle (The same side technique)

所以我可以检查我的鼠标是否在每个三角形内,或者是否可以检查我的鼠标是否在旋转的矩形中更好。

我几乎理解三角形文档中的所有内容,但我根本没有数学技能来计算两个交叉产品的交叉积和点积。

这应该是交叉产品:

  

a×b = | a | | B | sin(θ)n

     

| A |是矢量a的大小(长度)

     

| B |是矢量b的幅度(长度)

     

θ是a和b之间的角度

     

n是与a和b

成直角的单位向量

但是如何计算a和b的单位向量? 我如何获得向量的大小?

编辑: 我忘了要求计算2个交叉产品之间的dotproduct。

function SameSide(p1,p2, a,b)
    cp1 = CrossProduct(b-a, p1-a)
    cp2 = CrossProduct(b-a, p2-a)
    if DotProduct(cp1, cp2) >= 0 then return true
    else return false

谢谢大家的帮助,我想我现在已经掌握了它,我希望我能接受多个答案。

4 个答案:

答案 0 :(得分:0)

矢量的大小是长度。在C ++中,如果有一个表示为double[3]的向量,则可以通过

计算长度
#include <math.h>

double a_length = sqrt( a[0]*a[0] + a[1]*a[1] + a[2]*a[2] );

但是,我明白你真正想要的是跨产品?在这种情况下,您可能想直接计算它。结果是矢量,即c = a×b。 你可以这样编码,例如:

double c[3];

c[0] = ( a[2]*b[3] - a[3]*b[2] );
c[1] = ( a[3]*b[1] - a[1]*b[3] );
c[2] = ( a[1]*b[2] - a[2]*b[1] );

答案 1 :(得分:0)

您可以按sqrt(x*x + y*y)计算向量的大小。您还可以更简单地计算crossproduct:a x b = a.x * b.y - a.y * b.x。通过计算所有4个三角形的面积,可以检查点是否在三角形内部。例如,a是源三角形的面积,b,c,d是其他区域。如果b + c + d = a那么该点就在里面。计算三角形的面积很简单:我们有矢量a,b是三角形的顶点。然后三角形区域为(a x b) / 2

答案 2 :(得分:0)

如果你不得不进行大量检查,我会回避使用平方根功能:它们的计算成本很高。为了进行比较,只需将所有内容相乘,就可以绕过平方根:

向量的大小=向量的长度

如果vector定义为float [3],则可以按如下方式计算长度:

double magnitude = sqrt( a[0]*a[0] + a[1]*a[1] + a[2]*a[2] );

然而,这在计算上是昂贵的,所以我会使用

double magnitudeSquared = a[0]*a[0] + a[1]*a[1] + a[2]*a[2];

然后修改任何比较计算以使用距离或幅度的平方版本,它将更具性能。

对于交叉产品,请原谅我,如果这个数学是不稳定的,自从我为此编写函数已经过了几年(代码重用很棒,但记住事情很糟糕):

double c[3];

c[0] = ( a[1]*b[2] - a[2]*b[1] );
c[1] = ( a[2]*b[0] - a[0]*b[2] );
c[2] = ( a[0]*b[1] - a[1]*b[0] );

为了简化这一切,我将vec3d放在一个自己的类中,其中一个非常简单的表示形式为:

class vec3d
{
    public:
        float x, y, z;
        vec3d crossProduct(vec3d secondVector)
        {
            vec3d retval;
            retval.x = (this.y * secondVector.z)-(secondVector.y * this.z);
            retval.y = -(this.x * secondVector.z)+(secondVector.x * this.z);
            retval.z = (this.x * secondVector.y)-(this.y * secondVector.x);
            return retval;
        }
        // to get the unit vector divide by a vectors length...
        void normalise() // this will make the vector into a 1 unit long variant of itself, or a unit vector
        {
           if(fabs(x) > 0.0001){
              x= x / this.magnitude();
           }
           if(fabs(y) > 0.0001){
              y= y / this.magnitude();
           }
           if(fabs(z) > 0.0001){
              z = / this.magnitude();
           }
        }

        double magnitude() 
        {
            return sqrt((x*x) + (y*y) + (z*z));
        }
        double magnitudeSquared() 
        {
            return ((x*x) + (y*y) + (z*z));
        }
};

我可以从旧的第二年编码练习中获得更全面的vec3d课程:.h file.cpp file

这是一个极简主义的2d实现(做到这一点,请原谅我们的简洁代码,并告诉我是否有错误):

vec2d.h

#ifndef VEC2D_H
#define VEC2D_H

#include <iostream>
using namespace std;

class Vec2D {
 private:
  double x, y;
 public:

  Vec2D();                   // default, takes no args
  Vec2D(double, double);     // user can specify init values

  void setX(double);
  void setY(double);

  double getX() const;
  double getY() const;

  double getMagnitude() const;
  double getMagnitudeSquared() const;
  double getMagnitude2() const;
  Vec2D normalize() const;
  double crossProduct(Vec2D secondVector);
  Vec2D crossProduct(Vec2D secondVector);

  friend Vec2D operator+(const Vec2D&, const Vec2D&);
  friend ostream &operator<<(ostream&, const Vec2D&);
};

double dotProduct(const Vec2D, const Vec2D);

#endif

vec2d.cpp

#include <iostream>
#include <cmath>
using namespace std;

#include "Vec2D.h"  

// Constructors
Vec2D::Vec2D() { x = y = 0.0; }
Vec2D::Vec2D(double a, double b) { x = a; y = b; }

// Mutators
void Vec2D::setX(double a) { x = a; }
void Vec2D::setY(double a) { y = a; }

// Accessors
double Vec2D::getX() const { return x; }
double Vec2D::getY() const { return y; }
double Vec2D::getMagnitude() const { return sqrt((x*x) + (y*y)); }
double Vec2D::getMagnitudeSquared() const { return ((x*x) + (y*y)); }
double Vec2D::getMagnitude2 const { return getMagnitudeSquared(); }
double Vec2d::crossProduct(Vec2D secondVector) { return ((this.x * secondVector.getY())-(this.y * secondVector.getX()));}
Vec2D crossProduct(Vec2D secondVector) {return new Vec2D(this.y,-(this.x));}

Vec2D Vec2D::normalize() const {   return Vec2D(x/getMagnitude(), y/getMagnitude());}

Vec2D operator+(const Vec2D& a, const Vec2D& b) {  return Vec2D(a.x + b.x, a.y + b.y);}

ostream& operator<<(ostream& output, const Vec2D& a) {  output << "(" << a.x << ", " << a.y << ")" << endl;  return output;}

double dotProduct(const Vec2D a, const Vec2D b) {  return a.getX() * b.getX() + a.getY() * b.getY();}

检查点是否在由三个向量描述的三角形内:

float calculateSign(Vec2D v1, Vec2D v2, Vec2D v3)
{
  return (v1.getX() - v3.getX()) * (v2.getY() - v3.getY()) - (v2.getX() - v3.getX()) * (v1.getY() - v3.getY());
}

bool isPointInsideTriangle(Vec2D point2d, Vec2D v1, Vec2D v2, Vec2D v3)
{
  bool b1, b2, b3;
  // the < 0.0f is arbitrary, could have just as easily been > (would have flipped the results but would compare the same)
  b1 = calculateSign(point2d, v1, v2) < 0.0f;
  b2 = calculateSign(point2d, v2, v3) < 0.0f;
  b3 = calculateSign(point2d, v3, v1) < 0.0f;

  return ((b1 == b2) && (b2 == b3));
}

在上面的代码中,如果calculateSign位于三角形中,您将获得true返回:)

希望这会有所帮助,如果您需要更多信息或更全面的vec3d或2d课程,请告知我们,我可以发布:)

附录

我添加了一个小的2d-vector类,以显示2d和3d中的差异。

答案 3 :(得分:0)

没有进入矢量的一个简单方法是检查区域。 例如,假设您有一个带角A,B,C,D的矩形。并指出P.

首先计算矩形的面积,只需找到矩形的高度和宽度并乘以。

B   D
|  /
| /
|/____ C
A

为了计算高度,宽度取一个点让我们说A,找到它与所有其他三个点的距离,即AB,AC,AD第1和第2最小值将是宽度,而height,max将是对角线长度。 现在存储从中获得高度,宽度的点,让我们说这些点是B,C。

现在你知道矩形看起来如何,即

B _____ D
 |     |
 |_____|
A       C

然后计算三角形ACP,ABP,BDP,CDP的面积之和(使用heros公式计算矩形区域),如果它等于矩形区域,则点P位于矩形外的其他位置。