/*
http://acm.hdu.edu.cn/showproblem.php?pid=3644
枚举,如果一个圆能放在多边形里面,你将这个圆移动,
直到跟多边形“相切",这个相切也不能算是标准的相切定义,
反正有三种情况:一、圆碰到了多边形的两个点;二、圆碰到
了多边形的一边一点;三、圆碰到了多边形的两边。以至于圆
不能在移动了,如此,你可以枚举这些情况,再判断圆是否放
得下。
*/
const double eps = 1e-8;
const double max = 1000000000.0;
int sign(double d){ return d < -eps ? -1 : d > eps; }
struct point{
double x, y;
point(double x=0, double y=0) : x(x), y(y) {}
void read(){ scanf("%lf%lf", &x, &y);}
point operator-(point tp){ return point(x-tp.x, y-tp.y); }
point operator+(point tp){ return point(x+tp.x, y+tp.y); }
};
inline double inter_pro(point st1, point ed1, point st2, point ed2){
return (ed1.x-st1.x)*(ed2.y-st2.y) - (ed1.y-st1.y)*(ed2.x-st2.x);
}
inline double dist(point st, point ed){ return sqrt(pow(st.x-ed.x, 2.0) + pow(st.y-ed.y, 2.0)); }
inline bool isIntersect(point st1, point ed1, point st2, point ed2){ //判断线段是否相交,在端点处相交不算 ??
if(inter_pro(st1, st2, st1, ed1) * inter_pro(st1, ed2, st1, ed1) >= 0) return false;
if(inter_pro(st2, st1, st2, ed2) * inter_pro(st2, ed1, st2, ed2) >= 0) return false;
return true;
}
inline bool isOnSegment(point st, point ed, point tp){ //判断点是否在线段上
if(inter_pro(st, tp, st, ed) != 0) return false;
if(fabs(dist(st, tp) + dist(ed, tp) - dist(st, ed)) < eps) return true;
return false;
}
inline double distPtoL(point st, point ed, point tp){//点到线段的最近距离
double d1, d2, d3;
d1 = dist(st, ed); d2 = dist(st, tp); d3 = dist(ed, tp);
if((d1*d1 + d3*d3 - d2*d2 < 0) || (d1*d1+d2*d2-d3*d3 < 0)) return min(d2, d3);
return fabs(inter_pro(st, ed, st, tp)) / d1;
}
inline point getMid(point st, point ed){ //求线段的中点
return point((st.x + ed.x) / 2.0, (st.y + ed.y) / 2.0);
}
inline point goLen(point st, point dir, double len){ //st沿着dir方向走len之后的点
double tl = sqrt(dir.x * dir.x + dir.y * dir.y);
if(sign(tl) == 0) return st;
return point(st.x + len * dir.x / tl, st.y + len * dir.y / tl);
}
// (st->ed)的左侧为多边形的内侧
point change(point st, point ed, point next, double l){ //l为线段移动的长度
//next为和返回的点相对应的点
point dd;
dd.x = -(ed - st).y;
dd.y = (ed - st).x;
double len = sqrt(dd.x * dd.x + dd.y * dd.y);
dd.x /= len, dd.y /= len;
dd.x *= l, dd.y *= l;
dd = dd + next;
return dd;
}
point intersectPoint(point st1, point ed1, point st2, point ed2){ //求相交直线的交点
double t = inter_pro(st2, st1, st2, ed2) / ((ed1.y-st1.y) * (ed2.x-st2.x) - (ed1.x-st1.x) * (ed2.y-st2.y));
return point(st1.x+(ed1.x-st1.x)*t, st1.y+(ed1.y-st1.y)*t);
}
point get_point(point st, point ed, point p){ //求p在直线(st,ed)上的垂点
point ans;
if(fabs(st.x-ed.x) < eps){
ans.x = st.x;
ans.y = p.y;
}else if(fabs(st.y-ed.y) < eps){
ans.x = p.x;
ans.y = st.y;
}else{
double k1, d1, k2, d2;
k1 = (ed.y - st.y) / (ed.x - st.x);
d1 = st.y - st.x*(ed.y - st.y) / (ed.x - st.x);
k2 = -1 / k1;
d2 = p.y + p.x / k1;
ans.x = (d2 - d1) * k1 / (k1*k1 + 1);
ans.y = k1 * ans.x + d1;
}
return ans;
}
struct poly{
static const int N = 10005; //点数目的最大值
point ps[N];
int pn;
poly(){ pn = 0; }
void push(point tp){ ps[pn++] = tp; }
point& operator[](int k){ return ps[k]; }
bool inPoly(point tp){ //判断点是否在多边形内
int i;
for(i = 0; i < 3; i++) ps[pn+i] = ps[i];
for(i = 0; i < pn; i++){
if(isOnSegment(ps[i], ps[i+1], tp)) return true;
}
int c = 0; //c表示交点的个数
point d1 = tp, d2;
d2.y = d1.y;
d2.x = maxx; //构造一条足够长的线段,d2.x要根据数据的范围而定
for(i = 0; i < pn; i++){
if(isIntersect(d1, d2, ps[i], ps[i+1])
||(isOnSegment(d1, d2, ps[i+1]) && (inter_pro(d1, d2, d1, ps[i]) * inter_pro(d1, d2, d1, ps[i+2]) < 0))
||(isOnSegment(d1, d2, ps[i+1]) && isOnSegment(d1, d2, ps[i+2]) && (inter_pro(d1, d2, d1, ps[i]) * inter_pro(d1, d2, d1, ps[i+3]) < 0)))
c++;
}
return c % 2;
}
double getArea(){ //求面积
ps[pn] = ps[0];
int i;
double ans;
for(ans = i = 0; i < pn; i++) ans += ps[i].x * ps[i+1].y - ps[i].y * ps[i+1].x;
return ans;
}
void reverse(){ //翻转
int l = 0, r = pn - 1;
point tp;
while(l < r){ tp = ps[l]; ps[l] = ps[r]; ps[r] = tp; l++, r--; }
}
bool isInnerCir(double R, point cen){ //判断半径为R,圆心为cen的圆是否在多边形内
if(!inPoly(cen)) return false;
ps[pn] = ps[0];
int i;
double dd;
for(i = 0; i < pn; i++){ if(sign(distPtoL(ps[i], ps[i+1], cen) - R) < 0) return false; }
return true; //圆在多边形内返回true
}
bool canHold(double R){ //判断该多边形是否可以容纳半径为R的圆
if(sign(getArea()) < 0) reverse();
ps[pn] = ps[0];
int i, j;
double d;
point p1, p2, p3, p4, cen;
for(i = 0; i < pn; i++){ //每举两个点
for(j = i + 1; j < pn; j++){
if(sign((d = dist(ps[i], ps[j])) - 2*R) <= 0){
p1 = getMid(ps[i], ps[j]);
p2 = ps[j] - ps[i];
swap(p2.x, p2.y); p2.x *= -1; //向量逆时针旋转90度
d = sqrt(R * R - d * d / 4.0);
cen = goLen(p1, p2,d);
if(isInnerCir(R, cen)) return true;
p2.x *= -1; p2.y *= -1; //反向
cen = goLen(p1, p2,d);
if(isInnerCir(R, cen)) return true;
}
//枚举线段和线段卡住圆的情况,把两条线段内移R的距离,将两条新的线段的交点作为圆心
p1 = change(ps[i], ps[i+1], ps[i], R);
p2 = change(ps[i], ps[i+1], ps[i+1], R);
p3 = change(ps[j], ps[j+1], ps[j], R);
p4 = change(ps[j], ps[j+1], ps[j+1], R);
if(isIntersect(p1, p2, p3, p4)){
cen = intersectPoint(p1, p2, p3, p4);
if(isInnerCir(R, cen)) return true;
}
//枚举点和线段卡住圆的情况
p1 = get_point(ps[i], ps[i+1], ps[j]);
p2 = ps[i+1] - ps[i];
if(sign(2 * R - dist(p1, ps[j])) < 0) continue;
d = sqrt(R * R - (ps[j].x - p1.x) * (ps[j].y - p1.y));
cen = goLen(p1, p2, d);
if(isInnerCir(R, cen)) return true;
p2.x *= -1; p2.y *= -1;
cen = goLen(p1, p2, d);
if(isInnerCir(R, cen)) return true;
}
int k;
}
return false;
}
double getMax(){ //计算多边形可以容纳的最大半径的圆
double low, high, mid, step;
low = 0;
high = 10000;
step = 0.001;
while(low <= high){
mid = (low + high) * 0.5;
if(canHold(mid)) low = mid + step;
else high = mid - step;
}
return low - step;
}
};
分享到:
相关推荐
给定点集组成任意多边形,使用MATLAB编写求出多边形内的最大内切圆(最大圆更准确)。得到的是局部最优解,可以通过改变初始点得到全局最优解。
这里给出一种利用计算参考点确定圆心的搜索方向,采用步长因子自动控制搜索精度的 计算任意多边形最大内圆的算法。并在FG82.FK 中利用FG82H(*W 程序模拟了算法的动态搜索过程,验 证了该算法的正确性和可操作性。
本功能实现任意多边形的最小外接圆,先实现任意多边形的绘制,在通过一个菜单实现绘制这个多边形的最小外接圆。
将网上计算多边形内最大矩形的java源码翻译成为c++/qt源.
cpp代码-任意多边形的最大内切圆算法
一个自己写的画图程序:可以画线、直线、举行、多边形、圆、椭圆,并可以对选中的图形进行移动,扩大,缩小,删除等操作
给定点集组成任意多边形,使用matlab求出包含所有点的最小外接圆。
一个简单的matlab多边形逼近于圆的演示程序,内有注释
多边形多彩折纸构图动态圆球js特效动画代码下载。
这个算法是用于求多边形、或者多边形连通域或者区域的最大内切圆,想要达到的目的是类似于halcon连通域,求区域特征中的最大内切圆。采用的算法是通过距离变换、求局部最值,判断最值是否属于连通域里面、通过以上...
计算多边形内最大矩形的c++代码,只有一个头文件,要用到OpenCV+STL,有例程,根据网上代码(QT版C++代码)修改而成,修改内容包括: 1. 把QT的东西用OpenCV和STL替换 2. 去掉了部分bug 3. 注释掉了部分代码 4. ...
使用qt计算地理平面下椭圆坐标的 不规则、不封闭 多边形面积。
WPF 实现的画图程序,支持线、矩形、圆、多边形橡皮筋。用WPF做绘图很好的Demo。原始积分只需要5,CSDN自动修改所需积分,太恶心了,我会定期改回来。
一个VC 6.0个性化窗体设计实例,绘制矩形、多边形、圆角或椭圆形的窗体,没有了窗口的标题栏和任务栏,以及最大化、最小化按钮,一切看似很简洁,虽然是规则窗口吧,但不属于常规窗口,以后会与大家分享不规则的异型...
采用多重迭代法实现任意多边形(而不仅是凸多边形)的最大内圆,如果是凸多边形,采用严格的数学公式,若凹,迭代法,多中心开始迭代,MFC界面,鼠标点击加点,backspace退格键删除点,建议顺时针点击。内有word原理...
基于正多边形搜索算法的圆度误差评定.pdf
ArcEngine中绘制圆、矩形、多边形,并测量其面积。圆、矩形、多边形随地图缩放平移而缩放平移