免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2691 | 回复: 0
打印 上一主题 下一主题

圆和椭圆求交算法 [复制链接]

论坛徽章:
39
2017金鸡报晓
日期:2017-02-08 10:39:4219周年集字徽章-周
日期:2023-04-15 12:02:2715-16赛季CBA联赛之深圳
日期:2023-02-16 14:39:0220周年集字徽章-年
日期:2022-08-31 14:25:28黑曼巴
日期:2022-08-17 18:57:0919周年集字徽章-年
日期:2022-04-25 13:02:5920周年集字徽章-20	
日期:2022-03-29 11:10:4620周年集字徽章-年
日期:2022-03-14 22:35:1820周年集字徽章-周	
日期:2022-03-09 12:51:3220周年集字徽章-年
日期:2022-02-10 13:13:4420周年集字徽章-周	
日期:2022-02-03 12:09:4420周年集字徽章-20	
日期:2022-01-25 20:14:27
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-11-20 17:43 |只看该作者 |倒序浏览
写这个函数似乎不那么容易,需要的可以参考。



  1. UINT CGeoFunc::GetCircleIntersectEllipse(CGeoCircle &Circle, CGeoEllipse &Elli, C3DPoint pArray[])

  2. {

  3.         C3DVector OA(Elli.GetCenter(),Elli.GetCornerA());

  4.         C3DVector OB(Elli.GetCenter(),Elli.GetCornerB());

  5.         C3DVector OO(Elli.GetCenter(),Circle.GetCenter());        //椭圆心到圆心的向量

  6.         double a=OA.mod();

  7.         double b=OB.mod();

  8.         double r=Circle.GetRadius();

  9.         //检查椭圆是否是圆?如果是圆就简化处理

  10.         if(_IsEqual(a,b))

  11.         {

  12.                 CGeoCircle EC;

  13.                 EC.SetCenter(Elli.GetCenter());

  14.                 EC.SetNormal(OA^OB);

  15.                 EC.SetRadius(a);

  16.                 return GetCircleIntersectCircle(Circle,EC,pArray);

  17.         }



  18.         C3DVector EV=OA^OB;

  19.         C3DVector EVXCV=Circle.GetNormal()^EV;



  20.         double modEVXCV=EVXCV.mod()/EV.mod()/Circle.GetNormal().mod();

  21.         if(_IsEqual(modEVXCV,0.0))

  22.         {//平行或共面

  23.                 CGeoPlane CP(Circle);

  24.                 if(_IsPointOnPlane(CP,Elli.GetCenter()))

  25.                 {//共面,最难解的一个

  26.                         double C2C=PointToPointDistance(Circle.GetCenter(),Elli.GetCenter());

  27.                         if(C2C > Circle.GetRadius() + MAX(a,b))

  28.                         {

  29.                                 return 0;

  30.                         }

  31.                         else

  32.                         {//可能有交的情况,也是最复杂的情况





  33.                                 if(_IsEqual(Elli.GetCenter(),Circle.GetCenter()))

  34.                                 {

  35.                                 //特殊情况特别处理,这种情况下交点不需要求4次方程,也不能用4次方程来求

  36.                                 //1、圆心重合

  37.                                         if(_IsEqual( Circle.GetRadius() , a))

  38.                                         {

  39.                                                 pArray[0]=Elli.GetCornerA();

  40.                                                 pArray[1]=GetMirrorPointByPoint(Elli.GetCenter(),Elli.GetCornerA());

  41.                                                 return 2;

  42.                                         }

  43.                                         else if(_IsEqual( Circle.GetRadius() , b))

  44.                                         {

  45.                                                 pArray[0]=Elli.GetCornerB();

  46.                                                 pArray[1]=GetMirrorPointByPoint(Elli.GetCenter(),Elli.GetCornerB());

  47.                                                 return 2;

  48.                                         }

  49.                                         else if(Circle.GetRadius() < MIN(a,b))

  50.                                         {

  51.                                                 return 0;

  52.                                         }

  53.                                         else if(Circle.GetRadius() > MAX(a,b))

  54.                                         {

  55.                                                 return 0;

  56.                                         }

  57.                                         else

  58.                                         {

  59.                                                 //*/

  60.                                                 //2006/02/17重新计算得到x*x=a*a*(b*b-r*r)/(b*b-a*a);

  61.                                                 C3DPoint Intersect[4];

  62.                                                 double r=Circle.GetRadius();

  63.                                                 double x=sqrt(a*a*(b*b-r*r)/(b*b-a*a));

  64.                                                 double y=sqrt(r*r-x*x);

  65.                                                 Intersect[0]=C3DPoint(x,y,0);

  66.                                                 Intersect[1]=C3DPoint(-x,y,0);

  67.                                                 Intersect[2]=C3DPoint(x,-y,0);

  68.                                                 Intersect[3]=C3DPoint(-x,-y,0);



  69.                                                 CUserCoordinate ucs;

  70.                                                 ucs.SetSystem(Circle.GetCenter(),OA,OB);

  71.                                                 CCSTranslater trans;

  72.                                                 trans.SetCoordinate(ucs);



  73.                                                 for(int i=0;i<4;i++)

  74.                                                 {

  75.                                                        

  76.                                                         pArray[i]=Circle.GetCenter()+

  77.                                                                 GetFormatVector(OA,Intersect[i].GetX()) +

  78.                                                                 GetFormatVector(OB,Intersect[i].GetY()) ;

  79.                                                         C3DPoint compare=trans.ReverseTransPoint(Intersect[i]);

  80.                                                 }



  81.                                                 return 4;



  82.                                         }

  83.                                 }

  84.                                 //2、圆心在椭圆OA轴上

  85.                                 CGeoLine LOA(Elli.GetCenter(),Elli.GetCornerA());

  86.                                 LOA.SetType(GEO_LINE_INF);

  87.                                 if(_IsPointOnLine(LOA,Circle.GetCenter()))

  88.                                 {

  89.                                         double dist=OO.mod();



  90.                                         if(_IsEqual(dist,a+r))

  91.                                         {

  92.                                                 //选哪个端点呢?假设是原A点

  93.                                                 if((OA*OO)<0)

  94.                                                 {

  95.                                                         pArray[0]=Elli.GetCornerA();

  96.                                                        

  97.                                                 }

  98.                                                 else

  99.                                                 {

  100.                                                         pArray[0]=GetMirrorPointByPoint(Elli.GetCenter(),Elli.GetCornerA());

  101.                                                 }

  102.                                                 return 1;

  103.                                         }

  104.                                         else if(dist > a+r)

  105.                                         {

  106.                                                 return 0;

  107.                                         }

  108.                                         else

  109.                                         {

  110.                                                 //以圆心为原点,OA为x轴,OB为y轴建立坐标,则交点连接原点和x轴的夹角满足

  111.                                                 //(b*b-a*a)*r*r*t^2-2*ex*r*b*b*t+ex*ex*b*b+a*a*r*r-a*a*b*b=0;

  112.                                                 //其中t=cos(alhpa);

  113.                                                 //计算前保证椭圆心的横坐标大于0,处于圆的右边

  114.                                                 CGeoEllipse ElliCopy(Elli);

  115.                                                 if((OO*OA) < 0)

  116.                                                         ElliCopy.SetCornerA(GetMirrorPointByPoint(Elli.GetCenter(),Elli.GetCornerA()));

  117.                                                 if((OO*OB) < 0)

  118.                                                         ElliCopy.SetCornerB(GetMirrorPointByPoint(Elli.GetCenter(),Elli.GetCornerB()));



  119.                                                 C3DVector OA(ElliCopy.GetCenter(),ElliCopy.GetCornerA());

  120.                                                 C3DVector OB(ElliCopy.GetCenter(),ElliCopy.GetCornerB());



  121.                                                 double A=(b*b-a*a)*r*r;

  122.                                                 double B=-2*dist*r*b*b;

  123.                                                 double C=dist*dist*b*b+a*a*r*r-a*a*b*b;

  124.                                                 double delta=B*B-4*A*C;

  125.                                                 if(delta < 0) return 0;        //无解

  126.                                                 double cosalpha1=(-B+sqrt(delta))/(2*A);

  127.                                                 double cosalpha2=(-B-sqrt(delta))/(2*A);



  128.                                                 bool value1=true;

  129.                                                 bool value2=true;

  130.                                                 if(cosalpha1 < -1 || cosalpha1 > 1)

  131.                                                         value1=false;

  132.                                                 if(cosalpha2 < -1 || cosalpha2 > 1)

  133.                                                         value2=false;



  134.                                                 double sinalpha1;

  135.                                                 if(value1) sinalpha1=sqrt(1-cosalpha1*cosalpha1);

  136.                                                 double sinalpha2;

  137.                                                 if(value2) sinalpha2=sqrt(1-cosalpha2*cosalpha2);



  138.                                                 C3DPoint Intersect[4]; //最多4个交

  139.                                                 UINT valid=0;

  140.                                                 if(value1)

  141.                                                 {

  142.                                                         Intersect[valid].SetX(r*cosalpha1);

  143.                                                         Intersect[valid].SetY(r*sinalpha1);

  144.                                                         valid++;

  145.                                                         Intersect[valid].SetX(r*cosalpha1);

  146.                                                         Intersect[valid].SetY(-r*sinalpha1);

  147.                                                         valid++;

  148.                                                        

  149.                                                 }



  150.                                                 if(value2)

  151.                                                 {

  152.                                                         Intersect[valid].SetX(r*cosalpha2);

  153.                                                         Intersect[valid].SetY(r*sinalpha2);

  154.                                                         valid++;

  155.                                                         Intersect[valid].SetX(r*cosalpha2);

  156.                                                         Intersect[valid].SetY(-r*sinalpha2);

  157.                                                         valid++;

  158.                                                 }

  159.                                                

  160.                                                 //过滤相同的点

  161.                                                 valid=FillterOffSamePoint(Intersect,valid);

  162.                                                 //转换到世界坐标系

  163.                                                 for(UINT i=0;i<valid;i++)

  164.                                                 {

  165.                                                         Intersect[i]=Circle.GetCenter()+

  166.                                                                 GetFormatVector(OA,Intersect[i].GetX()) +

  167.                                                                 GetFormatVector(OB,Intersect[i].GetY()) ;

  168.                                                 }

  169.                                                 //在世界坐标系检查

  170.                                                 UINT onElli=0;

  171.                                                 for(i=0;i<valid;i++)

  172.                                                 {

  173.                                                         if(_IsPointOnEllipse(Elli,Intersect[i]))

  174.                                                         {

  175.                                                                 Intersect[onElli++]=Intersect[i];

  176.                                                         }

  177.                                                 }

  178.                                                 //返回结果

  179.                                                 for(i=0;i<onElli;i++)

  180.                                                 {

  181.                                                         pArray[i]=Intersect[i];

  182.                                                 }

  183.                                                 return onElli;



  184.                                         }

  185.                                 }

  186.                                 //3、圆心在椭圆OB轴上

  187.                                 CGeoLine LOB(Elli.GetCenter(),Elli.GetCornerB());

  188.                                 //LOB.SetType(GEO_LINE_INF);

  189.                                 if(_IsPointOnLine(LOB,Circle.GetCenter()))

  190.                                 {





  191.                                         double dist=OO.mod();

  192.                                         if(_IsEqual(dist,b+r))

  193.                                         {

  194.                                                 //选哪个端点呢?假设是原A点

  195.                                                 if((OB*OO)<0)

  196.                                                 {

  197.                                                         pArray[0]=Elli.GetCornerB();

  198.                                                        

  199.                                                 }

  200.                                                 else

  201.                                                 {

  202.                                                         pArray[0]=GetMirrorPointByPoint(Elli.GetCenter(),Elli.GetCornerB());

  203.                                                 }

  204.                                                 return 1;

  205.                                         }

  206.                                         else if(dist > b+r)

  207.                                         {

  208.                                                 return 0;

  209.                                         }

  210.                                         else

  211.                                         {

  212.                                                 //以圆心为原点,OB为x轴,OA为y轴建立坐标,则交点连接原点和x轴的夹角满足

  213.                                                 //(a*a-b*b)*r*r*t^2-2*ex*r*a*a*t+ex*ex*a*a+b*b*r*r-a*a*b*b=0;

  214.                                                 //其中t=cos(alhpa);



  215.                                                 CGeoEllipse ElliCopy(Elli);

  216.                                                 if((OO*OA) < 0)

  217.                                                         ElliCopy.SetCornerA(GetMirrorPointByPoint(Elli.GetCenter(),Elli.GetCornerA()));

  218.                                                 if((OO*OB) < 0)

  219.                                                         ElliCopy.SetCornerB(GetMirrorPointByPoint(Elli.GetCenter(),Elli.GetCornerB()));



  220.                                                 C3DVector OA(ElliCopy.GetCenter(),ElliCopy.GetCornerA());

  221.                                                 C3DVector OB(ElliCopy.GetCenter(),ElliCopy.GetCornerB());



  222.                                                 double A=(a*a-b*b)*r*r;

  223.                                                 double B=-2*dist*r*a*a;

  224.                                                 double C=dist*dist*a*a+b*b*r*r-a*a*b*b;

  225.                                                 double delta=B*B-4*A*C;

  226.                                                 if(delta < 0) return 0;        //无解

  227.                                                 double cosalpha1=(-B+sqrt(delta))/(2*A);

  228.                                                 double cosalpha2=(-B-sqrt(delta))/(2*A);



  229.                                                 bool value1=true;

  230.                                                 bool value2=true;

  231.                                                 if(cosalpha1 < -1 || cosalpha1 > 1)

  232.                                                         value1=false;

  233.                                                 if(cosalpha2 < -1 || cosalpha2 > 1)

  234.                                                         value2=false;



  235.                                                 double sinalpha1=sqrt(1-cosalpha1*cosalpha1);

  236.                                                 double sinalpha2=sqrt(1-cosalpha2*cosalpha2);



  237.                                                 C3DPoint Intersect[4]; //最多4个交

  238.                                                 UINT valid=0;

  239.                                                 if(value1)

  240.                                                 {

  241.                                                         Intersect[valid].SetX(r*cosalpha1);

  242.                                                         Intersect[valid].SetY(r*sinalpha1);

  243.                                                         valid++;

  244.                                                         Intersect[valid].SetX(r*cosalpha1);

  245.                                                         Intersect[valid].SetY(-r*sinalpha1);

  246.                                                         valid++;

  247.                                                 }



  248.                                                 if(value2)

  249.                                                 {

  250.                                                         Intersect[valid].SetX(r*cosalpha2);

  251.                                                         Intersect[valid].SetY(r*sinalpha2);

  252.                                                         valid++;

  253.                                                         Intersect[valid].SetX(r*cosalpha2);

  254.                                                         Intersect[valid].SetY(-r*sinalpha2);

  255.                                                         valid++;

  256.                                                 }

  257.                                                

  258.                                                 //过滤相同的点

  259.                                                 valid=FillterOffSamePoint(Intersect,valid);

  260.                                                 //转换到世界坐标系

  261.                                                 for(UINT i=0;i<valid;i++)

  262.                                                 {

  263.                                                         Intersect[i]=Circle.GetCenter()+

  264.                                                                 GetFormatVector(OB,Intersect[i].GetX()) +

  265.                                                                 GetFormatVector(OA,Intersect[i].GetY()) ;

  266.                                                 }

  267.                                                 //在世界坐标系检查

  268.                                                 UINT onElli=0;

  269.                                                 for(i=0;i<valid;i++)

  270.                                                 {

  271.                                                         if(_IsPointOnEllipse(Elli,Intersect[i]))

  272.                                                         {

  273.                                                                 Intersect[onElli++]=Intersect[i];

  274.                                                         }

  275.                                                 }

  276.                                                 //返回结果

  277.                                                 for(i=0;i<onElli;i++)

  278.                                                 {

  279.                                                         pArray[i]=Intersect[i];

  280.                                                 }

  281.                                                 return onElli;



  282.                                         }



  283.                                 }

  284.                                



  285.                                 //一般情况cx!=0,cy!=0

  286.                                 //建立以椭圆中心为原点,A轴方向为X方向,B轴方向为Y方向的坐标

  287.                                 //有方程组...

  288.                                 // x*x/a/a+y*y/b/b=1;        -----------------------1

  289.                                 // (x-cx)*(x-cx)+(y-cy)*(y-cy)=r*r;          -----------------2

  290.                                 // 由1得 y=b*sqrt(1-(x*x)/(a*a));        -------------------3

  291.                                 // 由2得 y-cy=sqrt(r*r-(x-cx)*(x-cx));        ---------------4

  292.                                 // 3代入4 得 b*sqrt(1-(x*x)/(a*a))-cy=sqrt(r*r-(x-cx)*(x-cx)); ---------5

  293.                                 // 5两边平方得

  294.                                 // (b*b/a/a-1)*x^2+2*cx*x+r*r-cx*cx-cy*cy-b*b=-2*b*cy*sqrt(1-x*x/a/a);        -----6

  295.                                 // 设

  296.                                 // K=b*b/a/a-1;

  297.                                 // L=2*cx;

  298.                                 // M=r*r-cx*cx-cy*cy-b*b;

  299.                                 // N=-2*b*cy;

  300.                                 // 则6可以写成

  301.                                 // K*x^2+L*x+M=N*sqrt(1-x*x/a/a);        -----------7

  302.                                 // 7两边平方

  303.                                 // K*K*x^4 + 2*K*L*x^3 + (2*K*M+L*L+N*N/a/a)*x^2 + 2*L*M*x + M*M-N*N=0; -------8

  304.                                 // 设

  305.                                 // A=K*K;

  306.                                 // B=2*K*L;

  307.                                 // C=2*K*M+L*L+N*N/a/a;

  308.                                 // D=2*L*M;

  309.                                 // E=M*M-N*N;

  310.                                 // 8式可写成

  311.                                 // A*x^4+B*x^3+C*x^2+D*x+E=0;        ------------9

  312.                                 // 直接解方程9就得到x





  313.                                 double r=Circle.GetRadius();

  314.                                 double cx,cy;



  315.                                 //圆中心的坐标

  316.                                 //利用OO向OA,OB投影求坐标



  317.                                 cx=OO*OA/OA.mod();

  318.                                 cy=OO*OB/OB.mod();



  319.                                 double K=b*b/a/a-1;

  320.                                 double L=2*cx;       

  321.                                 double M=r*r-cx*cx-cy*cy-b*b;

  322.                                 double N=-2*b*cy;



  323.                                 double A=K*K;

  324.                                 double B=2*K*L;

  325.                                 double C=2*K*M+L*L+N*N/a/a;

  326.                                 double D=2*L*M;

  327.                                 double E=M*M-N*N;



  328.                                 double root[4];        //所有可能的根



  329.                                 int rootcount=CGeoFuncMathLib::SoluteFunction(A,B,C,D,E,root);



  330.                                 if(rootcount==0) return 0;        //没有根



  331.                                 //检验所有可能的解共8个

  332.                                 C3DPoint Intersect[4];

  333.                                 int pc=0;

  334.                                 for(int i=0;i<rootcount;i++)

  335.                                 {

  336.                                         //在第一个方程求出y;

  337.                                         double y1=+b*sqrt(1-root[i]*root[i]/a/a);

  338.                                         double y2=-b*sqrt(1-root[i]*root[i]/a/a);

  339.                                         //代进第2方程检查误差

  340.                                         double c1=(root[i]-cx)*(root[i]-cx)+(y1-cy)*(y1-cy)-r*r;

  341.                                         double c2=(root[i]-cx)*(root[i]-cx)+(y2-cy)*(y2-cy)-r*r;

  342.                                         if(IsEqual(c1,0.0))

  343.                                         {

  344.                                                 Intersect[pc].x=root[i];

  345.                                                 Intersect[pc].y=y1;

  346.                                                 Intersect[pc].z=0;

  347.                                                 pc++;

  348.                                         }

  349.                                         else if(IsEqual(c2,0.0))

  350.                                         {

  351.                                                 Intersect[pc].x=root[i];

  352.                                                 Intersect[pc].y=y2;

  353.                                                 Intersect[pc].z=0;

  354.                                                 pc++;

  355.                                         }

  356.                                         else continue;

  357.                                 }



  358.                                 //现在这些点都是以椭圆圆心为原点的局部坐标,

  359.                                 //下面转换这些坐标到世界坐标系返回

  360.                                 //这个转换和采用正规坐标系转换相同

  361.                                 OA.Normalize();OB.Normalize();

  362.                                 for(i=0;i<pc;i++)

  363.                                 {

  364.                                         pArray[i]=

  365.                                                 Elli.GetCenter() +

  366.                                                 OA*Intersect[i].x +

  367.                                                 OB*Intersect[i].y ;

  368.                                 }



  369.                                 return pc;



  370.                         }

  371.                 }

  372.                 else

  373.                 {//平行不共面

  374.                         return 0;

  375.                 }

  376.         }

  377.         else

  378.         {//不平行

  379.                 CGeoPlane PC(Circle);



  380.                 C3DVector Normal=OA^OB;

  381.                 CGeoPlane PE(Normal,Elli.GetCenter());

  382.                 CGeoLine L;

  383.                 UINT nret=GetPlaneIntersectPlane(PC,PE,L);

  384.                 //ASSERT(nret==1);

  385.                 //C3DPoint P1,P2;

  386.                 C3DPoint kArray[2];

  387.                 nret=GetLineIntersectCircle(Circle,L,kArray);

  388.                

  389.                 UINT Counter=0;

  390.                 for(UINT i=0;i<nret;i++)

  391.                 {

  392.                         if(_IsPointOnEllipse(Elli,kArray[i]))

  393.                         {

  394.                                 pArray[Counter++]=kArray[i];

  395.                         }

  396.                 }

  397.                 return Counter;

  398.         }



  399.         return 0;

  400. }
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP