POJ1584 几何 凸包判断 点和多边形的位置关系

0

题目:

询问给出的多边形是凸多边形还是凹多边形(两者区别: if there exist any two interior points in the hole that, if connected by a line segment, that segment would cross one or more edges of the hole,如果存在有任意两个顶点的连线会经过边的情况则是凹多边形,凸多边形任意两个顶点连线都是在多边形内部

给出一个peg,去填补给出的多边形,要求peg的坐标在多边形内且半径小于等于到多边形任意边的距离。

1

分析:

凸包判断,求连续两个边的向量的叉乘,如果方向(正负)出现不同,说明不是凸包。

点和多边形位置关系判断,用点和连续的两个多边形的顶点相连得到的向量叉乘,如果出现方向(正负)改变说明点在多边形外面。

(其他作法,大同小异,原理是一样的,如这里

优势:代码要规范简洁,如果给出的顺序是顺时针则调用reserve函数翻转点的顺序使按顺序叉乘符号>0使后面程序书写更方便,dblcmp函数减少精度问题,struct的使用以及重载符号,xmult叉乘函数拿出。

2

#include <iostream>
#include <stdio.h>
#include <cmath>
#include <string>
#include <math.h>
#include <algorithm>
//是否是凸多边形,钉子位置是否在多边形内,钉子的半径是否大于到每一条边的距离
//如果是bool 函数,return false ,return true.那么主函数里一定要是 if(!函数名),而不是if(函数名==-1),因为false==0!!!
using namespace std;
const double eps=1e-8;
const int maxn=110;
struct points{
    double x;
    double y;
    double len(){
        return sqrt(x*x+y*y+eps);
    }
    points operator - (const points & a){
        points next;
        next.x=x-a.x;
        next.y=y-a.y;
        return next;
    }
}point[maxn],peg;
int n;double pr;double px,py;
double xmult(points vec1,points vec2){
    return vec1.x*vec2.y-vec1.y*vec2.x;
}
int dblcmp(double x){
    if(fabs(x)<eps) return 0;
    else{
        return x>0?1:-1;
    }
}
bool Convex(){///判断是否是凸包
    for(int i=0;i<n;i++){
        if(dblcmp(xmult(point[(i+1)%n]-point[i],point[(i+2)%n]-point[(i+1)%n]))<0){//==0就是点共线不能说明不是凸多边形所以不判
            return false;
        }
    }
    return true;
}
double lenth(points p){
    return p.len();
}
bool Inconvex_Infit(){///对于点和多边形的位置关系:double pos=xmult(point[i%n]-peg,point[(i+1)%n]-peg);只要出现一次pos<0:点在多边形外部;只要出现一次pos==0,点在多边形的边上;如果pos>0总是成立,点在多边形外部
    for(int i=0;i<n;i++){
        if(xmult(point[i%n]-peg,point[(i+1)%n]-peg)<=0){//点是否在多边形内
            if(xmult(point[i%n]-peg,point[(i+1)%n]-peg)==0&&pr==0){//如果钉子在多边形的边上且钉子的面积近乎为0也是可以插入的,不过实际情况中几乎不存在,题目中也没有考到这个数据
                return true;
            }
            return false;
        }
        
        if(dblcmp(xmult(point[i%n]-peg,point[(i+1)%n]-peg)/fabs(lenth(point[(i+1)%n]-point[i%n]))-pr)<0){//大小是否能覆盖
            return false;
        }
    }
    return true;
}

int main(){
   while(~scanf("%d",&n)&&n>=3){
        ///ini
        scanf("%lf%lf%lf",&pr,&peg.x,&peg.y);
        for(int i=0;i<n;i++){
            scanf("%lf%lf",&point[i].x,&point[i].y);
        }

        ///reverse
        double temparea=0;
        int u=0;
        while(temparea==0&&u<n){
            temparea=dblcmp(xmult(point[(u+1)%n]-point[u],point[(u+2)%n]-point[u]));
            u++;
        }
        if(temparea<0){
            reverse(point,point+n);
        }

        ///judge
        if(Convex()==0){
            cout<<"HOLE IS ILL-FORMED"<<endl;
            continue;
        }
        if(!Inconvex_Infit()){
            cout<<"PEG WILL NOT FIT"<<endl;
        }
        else{
            cout<<"PEG WILL FIT"<<endl;
        }
   }
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值