编写程序,输入A,B,C,D四个点的坐标,假设A,B,C三点可以构成一个三角形,判断D点是否落在三角形内。

解题思路:

假设三角形的三个点按照顺时针(或者逆时针)顺序是A,B,C。对于某一点P,求出三个向量PA,PB,PC, 然后计算以下三个叉乘(^表示叉乘符号):

t1 = PA^PB,

t2 = PB^PC,

t3 = PC^PA,

如果t1,t2,t3同号(同正或同负),那么P在三角形内部,否则在外部。

(更多在代码后)

本题代码如下:

#include<stdio.h>
#include<math.h>typedef struct Point
{double x,y;
}Point;Point decPoint(Point p1,Point p2)//计算p1-p2向量
{Point ret;ret.x=p1.x-p2.x;ret.y=p1.y-p2.y;return ret;
}double multiPoint(Point p1,Point p2)//计算向量叉乘
{return(p1.x*p2.y-p1.y*p2.x);
}double crossByThreePoint(Point A,Point B,Point C)//叉乘(A
{return multiPoint(decPoint(B,A),decPoint(C,A));
}int sign(double x)//对x进行正负判断返回标志符
{double eps=1e-8;if(fabs(x)<eps) return 0;if(x>0) return 1;return -1;
}int main()
{int i,j,k;Point pts[4];double x,y;int sgn[3];for(int i=0;i<4;i++)//将A,B,C,D四个点存放在数组中 {scanf("%lf%lf",&pts[i].x,&pts[i].y);}sgn[0]=sign(crossByThreePoint(pts[0],pts[1],pts[2]));//D点都参与形成向量sgn[1]=sign(crossByThreePoint(pts[1],pts[2],pts[3]));sgn[2]=sign(crossByThreePoint(pts[2],pts[0],pts[3]));if(sgn[0]==0||sgn[1]==0||sgn[2]==0)//若D在三条边上 {printf("Point D is on the triangle!\n");}else if(sgn[0]==sgn[1]&&sgn[1]==sgn[2])//若D在三角形内部{printf("Point D is on the triangle!\n");}else{printf("Point D is out of the triangle!\n");}return 0;
}

https://blog.csdn.net/zxj1988/article/details/6260576

数学知识:

向量(Vector
在几乎所有的几何问题中,向量(有时也称矢量)是一个基本点。向量的定义包含方向和一个数(长度)。在二维空间中,一个向量可以用一对xy来表示。例如由点(1,3)到(5,1的向量可以用(4,-2)来表示。这里大家要特别注意,我这样说并不代表向量定义了起点和终点。向量仅仅定义方向和长度。

向量加法
向量也支持各种数学运算。最简单的就是加法。我们可以对两个向量相加,得到的仍然是一个向量。我们有:
    V1x1, y1+V2x2, y2=V3(x1+x2, y1+y2)
下图表示了四个向量相加。注意就像普通的加法一样,相加的次序对结果没有影响(满足交换律),减法也是一样的。

点乘(Dot Product
如果说加法是凭直觉就可以知道的,另外还有一些运算就不是那么明显的,比如点乘和叉乘。
点乘比较简单,是相应元素的乘积的和:
    V1( x1, y1)   V2(x2, y2) = x1*x2 + y1*y2
注意结果不是一个向量,而是一个标量(Scalar)。点乘有什么用呢,我们有:
    A   B = |A||B|Cos(θ)
θ
是向量A和向量B见的
夹角。这里|A|我们称为向量A的模(norm),也就是A的长度, 在二维空间中就是|A| = sqrt(x2+y2)。这样我们就和容易计算两条线的夹角
    Cos(θ) = A   B /(|A||B|)

当然你知道要用一下反余弦函数acos()啦。(回忆一下cos(90)=0 cos(0) = 1还是有好处的,希望你没有忘记。)这可以告诉我们如果点乘的结果,简称点积,为0的话就表示这两个向量垂直。当两向量平行时,点积有最大值
另外,点乘运算不仅限于2维空间,他可以推广到任意维空间。(译注:不少人对量子力学中的高维空间无法理解,其实如果你不要试图在视觉上想象高维空间,而仅仅把它看成三维空间在数学上的推广,那么就好理解了)

叉乘(cross product
相对于点乘,叉乘可能更有用吧。2维空间中的叉乘是:
    V1(x1, y1) X V2(x2, y2) = x1y2 – y1x2
看起来像个标量,事实上叉乘的结果是个向量,方向在z轴上。上述结果是它的模。在二维空间里,让我们暂时忽略它的方向,将结果看成一个向量,那么这个结果类似于上述的点积,我们有:
    A x B = |A||B|Sin(θ)
然而角度 θ和上面点乘的角度有一点点不同,他是有正负的,是指从AB的角度。下图中 θ为负。
另外还有一个有用的特征那就是叉积的绝对值就是AB为两边说形成的平行四边形的面积。也就是AB所包围三角形面积的两倍。在计算面积时,我们要经常用到叉积。
(译注:三维及以上的叉乘参看维基:http://en.wikipedia.org/wiki/Cross_product

-线距离
找出一个点和一条线间的距离是经常遇见的几何问题之一。假设给出三个点,ABC,你想找出点C到点AB定出的直线间距离。第一步是找出AB的向量ABAC的向量AC,现在我们用该两向量的叉积除以|AB|,这就是我们要找的的距离了(下图中的红线)。
    d = (AB x AC)/|AB|

如果你有基础的高中几何知识,你就知道原因了。上一节我们知道(AB X AC)/2是三角形ABC的面积,这个三角形的底是|AB|,高就是CAB的距离。有时叉积得到的是一个负值,这种情况下距离就是上述结果的绝对值。
当我们要找点到线段的距离时,情况变得稍稍复杂一些。这时线段与点的最短距离可能是点到线段的某一端点,而不是点到直线的垂线。例如上图中点C到线段AB的最短距离应该是线段BC。我们有集中不同的方法来判断这种特殊情况。第一种情况是计算点积AB Bc来判定两线段间夹角。如果点积大于等于零,那么表示ABBC是在-9090度间,也就是说CAB的垂线在AB外,那么AB上到C距离最近的点就是B。同样,如果BAAC大于等于零,那么点A就是距离C最近的点。如果两者均小于零,那么距离最近的点就在线段AB中的莫一点。

https://www.cnblogs.com/TenosDoIt/p/4024413.html

二维平面上判断点是否在三角形内

最近在项目中碰到的这个问题,在此记录一下。已知三角形的三个顶点坐标,判断某个点是否在三角形中(在三角形的边上,我们也视作在三角形中),本文给出了三种方法。

算法1

利用面积法,如上图所示,如果点P在三角形ABC的内部,则三个小三角形PAB, PBC, PAC的面积之和 = ABC的面积,反之则不相等。

已知三角形的三个顶点坐标求其面积,可以根据向量的叉乘,参考here。

该算法详见后面代码中的函数:IsPointInTriangle1

算法2

首先看一下这个问题,如何判断某两个点在某条直线的同一侧(代码中函数:IsPointAtSameSideOfLine)?

根据向量的叉乘以及右手螺旋定则,AB^AM (^表示叉乘,这里向量省略了字母上面的箭头符号)的方向为向外指出屏幕,AB^AN也是向外指出屏幕,但AB^AO的方向是向内指向屏幕,因此M,N在直线AB的同侧,M ,O在直线AB的两侧。实际计算时,只需要考虑叉积的数值正负

假设以上各点坐标为A(0,0), B(4,0), M(1,2), N(3,4), O(3,-4), 则:

AB^AM = (4,0)^(1,2) = 4*2 - 0*1 = 8

AB^AN = (4,0)^(3,4) = 4*4 – 0*3 = 16

AB^AO = (4,0)^(3,-4) = 4*-4 – 0*3 = –16

由上面的数值可知,可以根据数值的正负判断叉乘后向量的方向。即,如果叉积AB^AM 和 AB^AN的结果同号,那么M,N两点就在直线的同侧,否则不在同一侧。特殊地,如果点M在直线AB上,则AB^AM的值为0。(如果是在三维坐标系中,求出的叉积是一个向量,可以根据两个向量的点积结果正负来判断两个向量的是否指向同一侧)                                                         本文地址

以上的问题解决了,就很容易的用来判断某个点是否在三角形内,如果P在三角形ABC内部,则满足以下三个条件:P,A在BC的同侧、P,B在AC的同侧、PC在AB的同侧。某一个不满足则表示P不在三角形内部。

该算法详见后面代码中的函数:IsPointInTriangle2

算法3

该方法也用到了向量。对于三角形ABC和一点P,可以有如下的向量表示:

p点在三角形内部的充分必要条件是:1 >= u >= 0,   1 >= v >= 0,   u+v <= 1。

已知A,B,C,P四个点的坐标,可以求出u,v,把上面的式子分别点乘向量AC和向量AB

解方程得到:

解出u,v后只需要看他们是否满足“1 >= u >= 0, 1 >= v >= 0, u+v <= 1”,如满足,则,p 在三角形内。

(u = 0时,p在AB上, v = 0时,p在AC上,两者均为0时,p和A重合)

该算法详见后面代码中的函数:IsPointInTriangle3

算法4

该算法和算法2类似,可以看作是对算法2的简化,也是用到向量的叉乘。假设三角形的三个点按照顺时针(或者逆时针)顺序是A,B,C。对于某一点P,求出三个向量PA,PB,PC, 然后计算以下三个叉乘(^表示叉乘符号):

t1 = PA^PB,

t2 = PB^PC,

t3 = PC^PA,

如果t1,t2,t3同号(同正或同负),那么P在三角形内部,否则在外部。

该算法详见后面代码中的函数:IsPointInTriangle4


经过测试,算法4最快,算法3次之,接着算法2,算法1最慢。直观的从计算量上来看,也是算法4的计算量最少。

以下是代码,定义了两个类:二维向量类 和 三角形类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

#include<string>

 #include<sstream>

 #include<fstream>

 #include<cstdio>

 #include<cstring>

 #include<iostream>

 #include<vector>

 #include<stack>

 #include<queue>

 #include<list>

 #include<algorithm>

 #include<ctime>

 #include<unordered_map>

 #include<map>

 #include<typeinfo>

 #include<cmath>

 #include<ctime>

 #include<climits>

 using namespace std;

//类定义:二维向量

class Vector2d

{

public:

    double x_;

    double y_;

public:

    Vector2d(double x, double y):x_(x), y_(y){}

    Vector2d():x_(0), y_(0){}

    //二维向量叉乘, 叉乘的结果其实是向量,方向垂直于两个向量组成的平面,这里我们只需要其大小和方向

    double CrossProduct(const Vector2d vec)

    {

        return x_*vec.y_ - y_*vec.x_;

    }

    //二维向量点积

    double DotProduct(const Vector2d vec)

    {

        return x_ * vec.x_ + y_ * vec.y_;

    }

    //二维向量减法

    Vector2d Minus(const Vector2d vec) const

    {

        return Vector2d(x_ - vec.x_, y_ - vec.y_);

    }

    //判断点M,N是否在直线AB的同一侧

    static bool IsPointAtSameSideOfLine(const Vector2d &pointM, const Vector2d &pointN,

                                        const Vector2d &pointA, const Vector2d &pointB)

    {

        Vector2d AB = pointB.Minus(pointA);

        Vector2d AM = pointM.Minus(pointA);

        Vector2d AN = pointN.Minus(pointA);

        //等于0时表示某个点在直线上

        return AB.CrossProduct(AM) * AB.CrossProduct(AN) >= 0;

    }

};

//三角形类

class Triangle

{

private:

    Vector2d pointA_, pointB_, pointC_;

public:

    Triangle(Vector2d point1, Vector2d point2, Vector2d point3)

        :pointA_(point1), pointB_(point2), pointC_(point3)

    {

        //todo 判断三点是否共线

    }

    //计算三角形面积

    double ComputeTriangleArea()

    {

        //依据两个向量的叉乘来计算,可参考向量的点乘与叉乘_zxj1988的专栏-CSDN博客_向量叉乘和点乘

        Vector2d AB = pointB_.Minus(pointA_);

        Vector2d BC = pointC_.Minus(pointB_);

        return fabs(AB.CrossProduct(BC) / 2.0);

    }

    bool IsPointInTriangle1(const Vector2d pointP)

    {

        double area_ABC = ComputeTriangleArea();

        double area_PAB = Triangle(pointP, pointA_, pointB_).ComputeTriangleArea();

        double area_PAC = Triangle(pointP, pointA_, pointC_).ComputeTriangleArea();

        double area_PBC = Triangle(pointP, pointB_, pointC_).ComputeTriangleArea();

        if(fabs(area_PAB + area_PBC + area_PAC - area_ABC) < 0.000001)

            return true;

        else return false;

    }

    bool IsPointInTriangle2(const Vector2d pointP)

    {

        return Vector2d::IsPointAtSameSideOfLine(pointP, pointA_, pointB_, pointC_) &&

            Vector2d::IsPointAtSameSideOfLine(pointP, pointB_, pointA_, pointC_) &&

            Vector2d::IsPointAtSameSideOfLine(pointP, pointC_, pointA_, pointB_);

    }

    bool IsPointInTriangle3(const Vector2d pointP)

    {

        Vector2d AB = pointB_.Minus(pointA_);

        Vector2d AC = pointC_.Minus(pointA_);

        Vector2d AP = pointP.Minus(pointA_);

        double dot_ac_ac = AC.DotProduct(AC);

        double dot_ac_ab = AC.DotProduct(AB);

        double dot_ac_ap = AC.DotProduct(AP);

        double dot_ab_ab = AB.DotProduct(AB);

        double dot_ab_ap = AB.DotProduct(AP);

        double tmp = 1.0 / (dot_ac_ac * dot_ab_ab - dot_ac_ab * dot_ac_ab);

        

        double u = (dot_ab_ab * dot_ac_ap - dot_ac_ab * dot_ab_ap) * tmp;

        if(u < 0 || u > 1)

            return false;

        double v = (dot_ac_ac * dot_ab_ap - dot_ac_ab * dot_ac_ap) * tmp;

        if(v < 0 || v > 1)

            return false;

        return u + v <= 1;

    }

    bool IsPointInTriangle4(const Vector2d pointP)

    {

        Vector2d PA = pointA_.Minus(pointP);

        Vector2d PB = pointB_.Minus(pointP);

        Vector2d PC = pointC_.Minus(pointP);

        double t1 = PA.CrossProduct(PB);

        double t2 = PB.CrossProduct(PC);

        double t3 = PC.CrossProduct(PA);

        return t1*t2 >= 0 && t1*t3 >= 0;

    }

};

int main()

{

    Triangle tri(Vector2d(0,0), Vector2d(6,6), Vector2d(12,0));

    srand(time(0));

    for(int i = 0; i < 20; ++i)

    {

         Vector2d point((rand()*1.0 / RAND_MAX) * 12, (rand()*1.0 / RAND_MAX) * 6);

         cout<<point.x_<<" "<<point.y_<<":     ";

         cout<<tri.IsPointInTriangle1(point)<<" ";

         cout<<tri.IsPointInTriangle2(point)<<" ";

         cout<<tri.IsPointInTriangle3(point)<<" ";

         cout<<tri.IsPointInTriangle4(point)<<endl;

    }

}

2014软专高级程序语言T2(用向量叉乘判断点与三角形的位置关系)相关推荐

  1. 2011软专高级程序语言T4(二维数组按一维数组访问)

    排序问题,给定一个10*10的矩阵a,编一个程序,对a进行排序.要求: ·a[i1][j1]<=a[i1][j2] 若j1<j2 ·a[i1][j1]<=a[i2][j2] 若i1& ...

  2. python是高级程序语言_高级语言程序设计(Python)_中国大学MOOC(慕课)

    课程概述 "高级语言程序设计"类课程面向无编程基础的学生,培养其运用编程语言解决实际问题的编程能力,使学生掌握一门编程语言的基本语法.语句.控制结构以及结构化程序设计的基本思想和方 ...

  3. java弦截法,国家计算机软考高级程序员历年真题1996

    1996年高级程序员级上午试题 试题1 从供选择的答案中,选出应填入下面叙述中_?_内的最确切的解答,把相应编号写在答卷的对应栏内. 一棵二叉排序树可顺序存放在一组物理上相邻的存储区中, 每个节点及其 ...

  4. c是高级程序语言吗,C语言是高级编程语言吗?

    C语言是高级编程语言吗? C语言是高级编程语言,高级语言主要是相对于汇编语言而言,基本脱离了机器的硬件系统,用于更易理解的方式编写程序,C语言是仅产生少量的机器语言以及不需要任何运行环境支持便能运行的 ...

  5. 高级程序语言c 平时作业,东北大学20秋学期《高级语言程序设计基础X》在线平时作业3...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 一.单选题 共25题,100分 1 4分 设有一段程序: int *var,a: a=100:var=&a:a=*var+10: 执行上面程序段后 ...

  6. [校招 --阶段一:高级程序语言C]语言基础

    C语言的特点: C语言是面向过程地语言,抽象地通用高级语言语言.C因为更接近原生,所以大量地底层代码用C写的.C语言也是一种普适性最强地计算机程序语言,它不仅由高级语言地特点,还具有机器语言地特点.C ...

  7. 吉林大学超星慕课《高级程序语言设计》实验06 递归程序设计(2020级)

    代码仅供参考,欢迎一起交流! 1 题目名称:排列组合 2 题目名称:Hermite多项式 3 题目名称:Ackerman函数 4 题目名称:最大公因数 5 题目名称:顺序检索 6 题目名称:最大元素 ...

  8. 头歌教学实践平台(高级程序语言设计(c))

    目录 一.顺序结构程序(二) 1.输出字符的ASCII码 2.看看你的成绩 3.相反次序重新组合 4.一元二次方程的根 二.选择结构程序设计 1.排序 2.选择结构-闰年判断 3.选择结构-分段函数问 ...

  9. C 是编译类高级程序语言 对 错,C言语编译过程中的常见过错

    言语的最大特点是:功用强.使用方便灵敏.C编译的程序对语法查看并不象其它高档言语那么严厉,这就给编程人员留下"灵敏的地步",但仍是由于这个灵敏给程序的调试带来了许多不方便,特别对初 ...

最新文章

  1. 变体类的使用 package record case【转载】
  2. Javascript中的函数重载-最佳做法
  3. 【Groovy】map 集合 ( 根据 Key 获取 map 集合中对应的值 | map.Key 方式 | map.‘Key’ 方式 | map[‘Key’] 方式 | 代码示例 )
  4. mysql版本的索引类型_【mysql】索引 回表 覆盖索引 索引下推
  5. 面试题 17.12. BiNode
  6. tcp与udp的socket编程,udp代码实现客户端服务端,tcp代码实现客户端服务端(单线程、多线程、多进程分别实现),三次握手
  7. mysql乱码utfmb4_MySQL乱码问题以及utf8mb4字符集
  8. 被逼至“盗版合法化”,俄罗斯要把 RuTracker 放出来了?
  9. 使用 Hasor 从数据库查询显示到页面上
  10. win10系统eclipse中整合hadoop错误
  11. 短路主板电源针,启动电脑的办法
  12. LaTeX的字体设置
  13. 从零开始学WEB前端——VUE介绍
  14. Win10家庭中文版 如何启用组策略
  15. 机房收费系统心得总结
  16. Java调用第三方天气预报接口示范
  17. 编程日历小程序,对小程序云开发和生成分享海报的实践
  18. ffmpeg为视频添加特效
  19. 大佬,您的选房系统已上线
  20. PCL入门系列 —— StatisticalOutlierRemoval 点云统计滤波

热门文章

  1. Linux-Tacacs+ 3A
  2. java.sql.SQLException: Value ‘0000-00-00‘ can not be represented as java.sql.Timestamp
  3. 【计算机毕业设计】305银行账目账户管理系统
  4. Python中类的继承
  5. 中国汽车保值率报告:日系霸榜,保值率成汽车销售新保障
  6. C++11 学习笔记 模板的细节(右尖括号,using,函数模板默认参数)
  7. 马斯克晒出Twitter架构图
  8. vnc server
  9. 你看过8K的VR直播吗?快来高交会上体验极致版的“身临其境”
  10. BP(Burp Suite)爆破入门