| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 4193 人关注过本帖, 6 人收藏
标题:C语言常用二维解析几何函数集源代码
取消只看楼主 加入收藏
御坂美琴
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:魔術の禁書目錄
等 级:小飞侠
威 望:9
帖 子:952
专家分:2929
注 册:2010-8-18
结帖率:96.15%
收藏(6)
已结贴  问题点数:50 回复次数:4 
C语言常用二维解析几何函数集源代码
这个代码是我今天放学后抽时间写的,选取了用于做动画或者游戏里较常用的数学函数(就是说不可能很全面)
包括简单的碰撞检测计算
函数包括:
向量加减法,向量点乘与叉乘,向量缩放,向量长度
三角形面积,点到直线(和线段)的距离,
判断直线平行,判断线段相交,求直线(和线段)的交点,
点到直线的垂足,点关于直线的对称点,线段关于直线的反射线
点绕给定点旋转
判断点在三角形(和椭圆)内
直线(和线段)与三角形碰撞,三角形与三角形碰撞
两平行矩形碰撞,平行矩形与椭圆碰撞
程序代码:
#include <math.h>

//定义点结构
typedef struct point
{
    double x;
    double y;
}point;

//定义有向线段
typedef struct segment
{
    point s;
    point e;
}segment;

//定义三角形
typedef struct triangle
{
    point p[3];
}triangle;

//定义精度误差
const double eps = 1e-6;

//两点距离
double distance(const point *p1, const point *p2)
{
    double dx = p1->x - p2->x, dy = p1->y - p2->y;
    return sqrt(dx * dx + dy * dy);
}

//线段长
double len(const segment* seg)
{
    double dx = seg->s.x - seg->e.x, dy = seg->s.y - seg->e.y;
    return sqrt(dx * dx + dy * dy);
}

//线段长的平方
double lensqr(const segment* seg)
{
    double dx = seg->s.x - seg->e.x, dy = seg->s.y - seg->e.y;
    return dx * dx + dy * dy;
}

//向量加法
point add(const point *p1, const point *p2)
{
    point ret;
    ret.x = p1->x + p2->x;
    ret.y = p1->y + p2->y;
    return ret;
}

//向量减法
point minus(const point *p1, const point *p2)
{
    point ret;
    ret.x = p1->x - p2->x;
    ret.y = p1->y - p2->y;
    return ret;
}

//向量缩放
point scale(const point *p, double s)
{
    point ret;
    ret.x = p->x * s;
    ret.y = p->y * s;
    return ret;
}

//向量缩放(以o点为基准点)
point scale2(const point *p, const point *o, double s)
{
    point v;
    v.x = (p->x - o->x) * s;
    v.y = (p->y - o->y) * s;
    return add(&v, o);
}

//向量点乘
double dotmul(const point *p1, const point *p2)
{
    return p1->x * p2->x + p1->y * p2->y;
}

//返回两点与原点组成的三角形面积的两倍(叉乘z值)
double multi(const point *p1, const point *p2)
{
    return p1->x * p2->y - p1->y * p2->x;
}

//返回三点组成的三角形面积的两倍(有次序,相当于叉乘)
double multi3(point p1, point p2, point p3)
{
    p2 = minus(&p2, &p1);
    p3 = minus(&p3, &p1);
    return multi(&p2, &p3);
}

//三角形面积
double triangleArea(point a, point b, point c)
{
    return multi3(a, b, c) / 2;
}

//计算点到直线的距离,a,b定义那个直线,p为要计算的点
double pointToLine(point a, point b, point p)
{
    a = minus(&a, &p);
    b = minus(&b, &p);
    return fabs(multi(&a, &b)) / distance(&a, &b);
}

//计算点到线段的距离,a,b定义那个线段,p为要计算的点
double pointToSeg(point a, point b, point p)
{
    point ab, o = {0};
    ab = minus(&b, &a);
    a = minus(&a, &p);
    b = minus(&b, &p);
    if (dotmul(&a, &ab) > -eps) return distance(&o, &a);
    ab.x = -ab.x; ab.y = -ab.y;
    if (dotmul(&b, &ab) > -eps) return distance(&o, &b);
    return fabs(multi(&a, &b)) / distance(&a, &b);
}

//判断两直线平行(重载1)
int isParallelP(const point* as, const point* ae, const point* bs, const point* be)
{
    double d1, d2;
    d1 = multi3(*as, *bs, *ae); d2 = multi3(*as, *ae, *be);
    return fabs(d1 + d2) < eps;
}

//判断两直线平行(重载2)
int isParallelS(const segment* a, const segment* b)
{
    double d1, d2;
    d1 = multi3(a->s, b->s, a->e); d2 = multi3(a->s, a->e, b->e);
    return fabs(d1 + d2) < eps;
}

//直线求交点(重载1)
point linesIntersectP(const point* as, const point* ae, const point* bs, const point* be)
{
    point ret;
    double d1, d2;
    d1 = multi3(*as, *bs, *ae); d2 = multi3(*as, *ae, *be);
    ret.x = (bs->x * d2 + be->x * d1) / (d1 + d2);
    ret.y = (bs->y * d2 + be->y * d1) / (d1 + d2);
    return ret;
}

//直线求交点(重载2)
point linesIntersectS(const segment* a, const segment* b)
{
    point ret;
    double d1, d2;
    d1 = multi3(a->s, b->s, a->e); d2 = multi3(a->s, a->e, b->e);
    ret.x = (b->s.x * d2 + b->e.x * d1) / (d1 + d2);
    ret.y = (b->s.y * d2 + b->e.y * d1) / (d1 + d2);
    return ret;
}

//点到直线的垂足
point pointToLineFoot(point a, point b, point p)
{
    point t;
    t = p;
    t.x += a.y - b.y;
    t.y += b.x - a.x;
    return linesIntersectP(&a, &b, &t, &p);
}

//点关于直线的对称点
point mirrorPoint(point a, point b, point p)
{
    point f;
    double dis;
    dis = pointToSeg(a, b, p);
    if (dis < eps) return p;
    f = pointToLineFoot(a, b, p);
    f.x += f.x - p.x;
    f.y += f.y - p.y;
    return f;
}

//求对称线段或者反射线(返回点放回p,q)
void mirrorSeg(const point* a, const point* b, point* p, point* q)
{
    *p = mirrorPoint(*a, *b, *p);
    *q = mirrorPoint(*a, *b, *q);
}

//对p点以o点为中心逆时针旋转r弧度,计算结果返回p中(参数返回方式的重载)
void rotate(point* p, point o, double r)
{
    point q;
    double sr, cr;
    q = minus(p, &o);
    sr = sin(r); cr = cos(r);
    p->x = o.x + (cr * q.x - sr * q.y);
    p->y = o.y + (sr * q.x + cr * q.y);
}

//对p点以o点为中心逆时针旋转r弧度(直接返回点的重载)
point rotateR(point p, point o, double r)
{
    point q;
    double sr, cr;
    q = minus(&p, &o);
    sr = sin(r); cr = cos(r);
    p.x = o.x + (cr * q.x - sr * q.y);
    p.y = o.y + (sr * q.x + cr * q.y);
    return p;
}

//判断两线段相交(相交返回1,不相交返回0)
int segCrashSegP(const point* as, const point* ae, const point* bs, const point* be)
{
    double s, t;
    s = multi3(*as, *bs, *be);
    t = multi3(*ae, *bs, *be);
    if (s * t > eps) return 0;
    s = multi3(*bs, *as, *ae);
    t = multi3(*be, *as, *ae);
    if (s * t > eps) return 0;
    return 1;
}

//判断两线段相交(相交返回1,不相交返回0)
int segCrashSegS(const segment* a, const segment* b)
{
    double s, t;
    s = multi3(a->s, b->s, b->e);
    t = multi3(a->e, b->s, b->e);
    if (s * t > eps) return 0;
    s = multi3(b->s, a->s, a->e);
    t = multi3(b->e, a->s, a->e);
    if (s * t > eps) return 0;
    return 1;
}

//判断点在三角形内(返回1:内;返回0:边上;返回-1:外)
int pointInTriangle(const triangle* tri, const point* p)
{
    double s, t;
    s = multi3(*p, tri->p[0], tri->p[1]);
    if (fabs(s) < eps) return 0;
    t = multi3(*p, tri->p[1], tri->p[2]);
    if (fabs(t) < eps) return 0;
    if ((s < 0) ^ (t < 0)) return -1;
    s = multi3(*p, tri->p[2], tri->p[0]);
    if (fabs(s) < eps) return 0;
    if ((s < 0) ^ (t < 0)) return -1;
    return 1;
}

//三角形与直线碰撞检测(碰撞返回1,不碰撞返回0)
int triangleCrashLine(const triangle* tri, const segment* seg)
{
    double s, t;
    s = multi3(tri->p[0], seg->s, seg->e);
    t = multi3(tri->p[1], seg->s, seg->e);
    if ((s < 0) ^ (t < 0)) return 1;
    s = multi3(tri->p[2], seg->s, seg->e);
    if ((s < 0) ^ (t < 0)) return 1;
    return 0;
}

//三角形与线段碰撞检测(碰撞返回1,不碰撞返回0)
int triangleCrashSeg(const triangle* tri, const segment* seg)
{
    if (pointInTriangle(tri, &seg->s) > 0) return 1;
    if (segCrashSegP(&tri->p[0], &tri->p[1], &seg->s, &seg->e)) return 1;
    if (segCrashSegP(&tri->p[0], &tri->p[2], &seg->s, &seg->e)) return 1;
    if (segCrashSegP(&tri->p[2], &tri->p[1], &seg->s, &seg->e)) return 1;
    return 0;
}

//三角形与三角形碰撞检测(碰撞返回1,不碰撞返回0)
int triangleCrashTriangle(const triangle* tri1, const triangle* tri2)
{
    segment seg;
    seg.s = tri2->p[0]; seg.e = tri2->p[1];
    if (triangleCrashSeg(tri1, &seg)) return 1;
    seg.s = tri2->p[0]; seg.e = tri2->p[2];
    if (triangleCrashSeg(tri1, &seg)) return 1;
    seg.s = tri2->p[2]; seg.e = tri2->p[1];
    if (triangleCrashSeg(tri1, &seg)) return 1;
    return 0;
}

//两平行于坐标轴的矩形碰撞检测(碰撞返回1,不碰撞返回0)
int rectCrashRect(const point* rect1lt, const point* rect1rb, const point* rect2lt, const point* rect2rb)
{
    if (rect1lt->x > rect2rb->x || rect1lt->y > rect2rb->y) return 0;
    if (rect2lt->x > rect1rb->x || rect2lt->y > rect1rb->y) return 0;
    return 1;
}

//判断点在椭圆内(返回1:内;返回0:边上;返回-1:外)
int pointInEllipse(const point* elplt, const point* elprb, const point* pt)
{
    point center, p;
    double a, b, s;
    center.x = (elplt->x + elprb->x) / 2; center.y = (elplt->y + elprb->y) / 2;
    a = center.x - elplt->x; b = center.y - elplt->y;
    a *= a; b *= b;
    p = minus(pt, &center);
    s = p.x * p.x / a + p.y * p.y / b;
    if (fabs(s) < eps) return 0;
    if (s > 1) return -1;
    return 1;
}

//判断平行矩形与椭圆碰撞(碰撞返回1,不碰撞返回0)
int rectCrashEllipse(const point* rectlt, const point* rectrb, const point* elplt, const point* elprb)
{
    if (rectCrashRect(rectlt, rectrb, elplt, elprb))
    {
        point p;
        int xs, ys;
        p.x = (elplt->x + elprb->x) / 2; p.y = (elplt->y + elprb->y) / 2;
        if (p.x < rectlt->x) xs = -1;
        else if (p.x < rectrb->x) xs = 0;
        else xs = 1;
        if (p.y < rectlt->y) ys = -1;
        else if (p.y < rectrb->y) ys = 0;
        else ys = 1;
        if (xs * ys == 0) return 1;
        if (xs < 0)
        {
            if (ys < 0) p = *elplt;
            else p.x = elplt->x, p.y = elprb->y;
        }
        else
        {
            if (ys > 0) p = *elprb;
            else p.x = elprb->x, p.y = elplt->y;
        }
        return pointInEllipse(elplt, elprb, &p) > 0;
    }
    return 0;
}

因为代码是我匆忙编写的,所以代码很可能还存在问题,如果发现请告诉我
但有一些函数,要你自己注意调用场合,比如求两直线的交点,最好先判断是否平行
求两线段的交点,先判断是否相交等等

另外,代码是未经优化的,在效率要求较高的场合可能不适用,但多数场合下的应用不会有什么问题

要注意的是,里面的旋转函数的坐标,用的是数学坐标,逆时针是指从x轴的正方向,向y轴的正方向旋转构成的角,这个角度可正可负
收到的鲜花
  • Devil_W2010-12-26 23:55 送鲜花  -1朵   附言:我想跟你切磋code,不知道你还肯赏脸。
  • 你们都要疼我哦2011-01-10 01:09 送鲜花  -5朵   附言:简单
  • 你们都要疼我哦2011-01-10 01:09 送鲜花  -5朵   附言:简单
  • 你们都要疼我哦2011-01-10 01:10 送鲜花  -5朵   附言:简单
  • 你们都要疼我哦2011-01-10 01:10 送鲜花  -5朵   附言:简单
  • 瓦药墙2011-01-10 13:16 送鲜花  5朵   附言:我很赞同
  • 瓦药墙2011-01-10 13:17 送鲜花  5朵   附言:好文章
  • 瓦药墙2011-01-10 13:17 送鲜花  5朵   附言:原创内容
  • 瓦药墙2011-01-10 13:17 送鲜花  5朵   附言:广告/枪文
  • 瓦药墙2011-01-10 13:19 送鲜花  5朵   附言:想想看
  • 瓦药墙2011-01-10 13:19 送鲜花  5朵   附言:强大
搜索更多相关主题的帖子: C语言 源代码 加减法 三角形 游戏 
2010-12-24 21:12
御坂美琴
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:魔術の禁書目錄
等 级:小飞侠
威 望:9
帖 子:952
专家分:2929
注 册:2010-8-18
收藏
得分:0 
up一下,代码有一些小地方有点问题(比如求三角形面积可能会是负数,由次序决定),另外差一个判断点在任意多边形内的函数,这两天看看时间够不够我补写个,这个函数也挺常用,只是特殊情况多,不太好写

永远为正义而奋斗,锄强扶弱的Level 5 超能力者
とある魔術の禁書目錄インデックス__御み坂さか美み琴こと
http://bbs.bccn.net/space.php?action=threads&uid=483997
2010-12-26 23:48
御坂美琴
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:魔術の禁書目錄
等 级:小飞侠
威 望:9
帖 子:952
专家分:2929
注 册:2010-8-18
收藏
得分:0 
奴家只对象棋切磋有兴趣,你希望是我的程序和你下还是我本人和你下?反正都是垃圾水平,难登大雅之堂,你选吧,让你爽爽意下如何?

永远为正义而奋斗,锄强扶弱的Level 5 超能力者
とある魔術の禁書目錄インデックス__御み坂さか美み琴こと
http://bbs.bccn.net/space.php?action=threads&uid=483997
2010-12-27 17:33
御坂美琴
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:魔術の禁書目錄
等 级:小飞侠
威 望:9
帖 子:952
专家分:2929
注 册:2010-8-18
收藏
得分:0 
那,请提供一个你也在的QQ群群号

永远为正义而奋斗,锄强扶弱的Level 5 超能力者
とある魔術の禁書目錄インデックス__御み坂さか美み琴こと
http://bbs.bccn.net/space.php?action=threads&uid=483997
2010-12-27 18:42
御坂美琴
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:魔術の禁書目錄
等 级:小飞侠
威 望:9
帖 子:952
专家分:2929
注 册:2010-8-18
收藏
得分:0 
以下是引用Dripel在2010-12-28 12:41:24的发言:

楼主想做什么?教菜菜做图形库?如果是这样真不错
可以,如果你愿意的话,不过我得花时间准备

永远为正义而奋斗,锄强扶弱的Level 5 超能力者
とある魔術の禁書目錄インデックス__御み坂さか美み琴こと
http://bbs.bccn.net/space.php?action=threads&uid=483997
2010-12-28 14:13
快速回复:C语言常用二维解析几何函数集源代码
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.018298 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved