多边形周边

多边形转为周边l距离多边形

在这里插入图片描述
0:多边形坐标
1:边按各边垂直方向向外平移l距离

public class PolygonVectorTranslationDemo {
private final static double IGNORE_VALUE = 0.1E-6;
//得到周边l单位距离的点集合
public List<Point> pointsProcess(List<Point> points,double l){
    clockwise(points);                                                  //未知顺时针、逆时针方向,处理为顺时针
    List<Point> vectors = pointToClockwiseVector(points);               //点转为顺时针方向向量
    List<Point> outBisector = outBisectorVector(vectors);                //得到凸角向外角平分线的向量
    return convex_concaveProcess(points,vectors,outBisector,l);         //凸凹角判断处理

}

private List<Point> convex_concaveProcess(List<Point> ps,List<Point> vs,List<Point> obs,double l){
    List<Point> ds = new ArrayList();
    for(int i=0;i<ps.size();i++){
        //得到角平分线与两边向量夹角的cos值,a*b = |a|*|b|cosα
        //double cosα = multiplication(vs.get(i),bs.get(i))/(vectorNorm(vs.get(i))*vectorNorm(bs.get(i)));
        double cosα = Math.abs(getCosAngle(vs.get(i),obs.get(i)));
        double sinβ = Math.sqrt(1-cosα*cosα);

        //凸凹角判断,顺时针的点,当左右两点一起顺时针则为凸
        if(isClockwise(ps,i)){
            //凸边形处理
            ds.addAll(convexProcess(sinβ,ps.get(i),obs.get(i),l));
        }else{
            //凹边形处理
            ds.add(concaveProcess(sinβ,ps.get(i),vs.get(i),obs.get(i),l));
        }
    }
    return ds;
}

//凸角处理
private List<Point> convexProcess(double cosα,Point p,Point v,double l){
    return calculateConvexPoint(cosα, p, v, l);
}

//凹角处理
private Point concaveProcess(double sinα,Point p,Point v,Point vb,double l){
    Point vb1 = new Point();
    double x;
    double y;
    vb = vectorReverse(vb);
    if(Math.abs(vb.getY())>IGNORE_VALUE){
        double temp = Math.sqrt((l*l/sinα/sinα)/(1+(vb.getX()*vb.getX()/vb.getY()/vb.getY())));
        y = temp + p.getY();
        x = (y-p.getY())*vb.getX()/vb.getY()+p.getX();
        vb1.setX(x-p.getX());
        vb1.setY(y-p.getY());
        if(getCosAngle(vb1,v)>0){
            y = p.getY()-temp;
            x = (y-p.getY())*vb.getX()/vb.getY()+p.getX();
        };
        vb1.setX(x);
        vb1.setY(y);
    }else{
        x = p.getX()+l/sinα;
        y = p.getY();
        vb1.setX(x-p.getX());
        vb1.setY(y-p.getY());
        if(getCosAngle(vb1,v)>0){
            x = p.getX()-l/sinα;
            y = p.getY();
        };
        vb1.setX(x);
        vb1.setY(y);
    }
    return vb1;
}

//cosα,顶角,角平分线向量,到顶点距离
//返回符合的点,顺时针
private List<Point> calculateConvexPoint(double cosα,Point p,Point v,double l){
    List<Point> points = new ArrayList();
    //a*b = |a|*|b|cosα两边平方的,未知点位(X,Y)
    //最终的到X*Vx+Y*Vy = 已知数(knownDatas),(X-Px)*(X-Px) +(Y-Py)*(Y-Py) = l*l
    double knownDatas = l*vectorNorm(v)*cosα+p.getX()*v.getX()+p.getY()*v.getY();
    //double knownDatas = l*cosα+p.getX()*v.getX()+p.getY()*v.getY();
    double a = 1+(v.getX()*v.getX())/(v.getY()*v.getY());
    double b = -2*(p.getX()+(v.getX()/v.getY())*(knownDatas/v.getY()-p.getY()));
    double c = p.getX()*p.getX()+(knownDatas/v.getY()-p.getY())*(knownDatas/v.getY()-p.getY())-l*l;

    double x1 = (-b+Math.sqrt(b*b-4*a*c))/(2*a);
    double y1 = (knownDatas-x1*v.getX())/v.getY();
    double x2 = (-b-Math.sqrt(b*b-4*a*c))/(2*a);
    double y2 = (knownDatas-x2*v.getX())/v.getY();
    points.add(new Point(zeroProcess(x1),zeroProcess(y1)));
    points.add(p);
    points.add(new Point(zeroProcess(x2),zeroProcess(y2)));

    isClockwise(points,false);
    points.remove(1);
    return points;
}

//点顺时针判断处理
private void clockwise(List<Point> points){
    if(!isClockwise(points)){
        Collections.reverse(points);
    }
}

//得到凸角向外的角平分线向量
private List<Point> outBisectorVector(List<Point> vs){
    List<Point> ds = new ArrayList();
    for(int i=0;i<vs.size();i++){
        ds.add(add(unit(vs.get(i)), vectorReverse(unit(vs.get((i+1==vs.size()?0:i+1))))));
    }
    return ds;
}

//点转为各顶点向量(三点测试,用一个角测试)
private List<Point> pointToVector(List<Point> points){
    List<Point> ps = new ArrayList();
    for (int i=0;i<points.size();i++){
        ps.add(minus(points.get(i-1<0?points.size()-1:i-1),points.get(i)));
        ps.add(minus(points.get(i+1==points.size()?0:i+1),points.get(i)));
    }
    return ps;
}

private List<Point> pointToClockwiseVector(List<Point> ps){
    List<Point> ds = new ArrayList();
    for (int i=0;i<ps.size();i++)
        ds.add(minus(ps.get(i),ps.get(i-1<0?ps.size()-1:i-1)));
    return ds;
}



//true 则所有点为顺时针
private boolean isClockwise(List<Point> pList){
    //获取最值,最值相邻3点判断顺逆时针
    int index =0 ;
    int size = pList.size();
    double maxlng=pList.get(0).getX();       //设最大
    for (int i=1;i<size;i++ ){
        if(maxlng<=pList.get(i).getY()){
            maxlng = pList.get(i).getY();
            index = i;
        }
    }
    return isClockwise(pList,index);
}

//flag为true时,则list改变为顺时针排序,flag为false则list改变为逆时针排序
private void isClockwise(List<Point> ps,boolean flag){
    if(isClockwise(ps,1)!=flag){
        Collections.reverse(ps);
    }
}

//传入List,需要判断中间点为位置i
private boolean isClockwise(List<Point> ps,int index){
    return isClockwise(ps.get(index- 1 < 0 ? ps.size() - 1 :index-1),
            ps.get(index),
            ps.get(index+ 1 == ps.size() ? 0 : index+ 1));
}


//三点顺逆时针判断 true 则所有点为顺时针 (x2-x1)*(y3-y1)-(y2-y1)*(x3-x1),在顺时针的基础上,三点逆时针则为凹
private boolean isClockwise(Point p1,Point p2,Point p3){
    return (p2.getX() - p1.getX()) * (p3.getY() - p1.getY())
            - (p2.getY() - p1.getY()) * (p3.getX() - p1.getX())<0?true:false;
}


//得到cosα
private double getCosAngle(Point v1,Point v2){
    return multiplication(v1,v2)/(vectorNorm(v1)*vectorNorm(v2));
}

//向量的模
private double vectorNorm(Point v){
    return Math.sqrt(v.getX()*v.getX()+v.getY()*v.getY());
}

//-
private Point minus(Point p1, Point p2){
    return new Point(p1.getX() - p2.getX(), p1.getY() - p2.getY());
}
//+
private Point add(Point p1, Point p2){
    return new Point(p1.getX() + p2.getX(), p1.getY() + p2.getY());
}
//* 向量数量积
private double multiplication(Point p1, Point p2){
    return p1.getX()*p2.getX() + p1.getY()*p2.getY();
}

//向量转单位向量
private Point unit(Point v){
    return new Point(v.getX()/vectorNorm(v),v.getY()/vectorNorm(v));
}

//向量取反
private Point vectorReverse(Point v){
    return new Point(0-v.getX(),0-v.getY());
}

//数据接近零处理
private double zeroProcess(double a){
    return Math.abs(a)<IGNORE_VALUE?0:a;
}
}

判断点是否在区域范围内
点的射线与多边形奇数焦点则在内,偶数焦点则在外

 /**
 * 判断点是否在多边形内,可以应用于复杂凹多边形
 * @return 如果在边上返回0,在内部返回1,在外部返回-1
 */
public static int isInPolygon(Pointlocation point, List<Pointlocation> lists){
    int sidesCount = lists.size();
    Pointlocation p1,p2;
    if(sidesCount < 3)
        return -1;
    //采用水平左射线计算交点个数
    int intersectionCount = 0;

    for (int i=0;i<sidesCount;i++){
        int j = (i + 1)%sidesCount;//i,j代表边的两个端点
        p1 = lists.get(i);
        p2 = lists.get(j);
        //待测点在区域当前两点右侧
        if(p1.getLng()>point.getLng()&&p2.getLng()>point.getLng())
            continue;
        //待测点纬度平行线不可能与当前两点相交
        if((point.getLat()-p1.getLat())*(point.getLat()-p2.getLat()) > 0)
            continue;

        //得到纬度与point纬度相同的点   (x-x1)/(x2-x1) = (y-y1)/(y2-y1)
        double lng = (point.getLat()-p1.getLat())*(p2.getLng()-p1.getLng())/(p2.getLat()-p1.getLat())+p1.getLng();

        //必存在焦点
        if(Math.abs(lng-p1.getLng())<IGNORE_VALUE)
            intersectionCount++;


        //该点在线段外则去掉
        if(!(lng> Math.min(p1.getLng(),p2.getLng())&&lng<Math.max(p1.getLng(),p2.getLng())))
            continue;

        //存在交点
        if(lng<point.getLng())
            intersectionCount++;
    }
    if(intersectionCount % 2 == 1)
        return 1;
    else
        return -1;
}

最后再判断点到各顶点距离是否为l,可判断在凸角处的拱形区域

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值