在我们人类抽象世界里,随处都是直线和圆的影子。就拿最近的视觉世界镜头的标定板,有两种,方格子和圆,方格子是直线形成的,再譬如,手机板上用来定位的,很多使用“十”字,这也是两条交叉的直线。这或许是“无以规矩,不成方圆”的暗示吧。
现在,我们的金箍棒又要增加新功能了,那就是变形,把找线工具(通格本)变形成一段弧线,这个描述不准确,应该称为文人墨客纸扇的扇面更恰当。更多的扇面,就可以围成一个圆。当你把这个圆形的扇面拖动到图像中有近似圆的东西上,穿越点便把这个圆show给了眼睛,这是计算与视觉的心照不宣。譬如说,晶圆上的电极就很像一个圆。这种找圆工具的设计思想,来源于“点线圆”逻辑的顺理成章。这只不过是线图像威力的继续发酵。
近期因为对找圆工具又有了新发现。所以对找圆工具又复习了一遍,趁热打铁,顺便把他贴出来,再加强记忆,要不我的记忆曲线快把他忘完了。界面上画圆使用的是计算机图形学基础上中点画圆算法。找线工具中使用的操作小矩形在此也更新为小圆圈。
为了区别找线工具的roibase类,我们设计了找圆工具的roibase2类。如下:
public class RoiBase2//SelfCirleRoi
{ public PointF m_Center;//圆心
public float m_Radius;//半径
public PointF another;//arc center point;介于 arcStart和arcEnd 之间(1/2弧处),此处会有一个操作小圆,用来操作圆的弹性
public PointF arcEnd;//arc End point;弧结束点
public float m_tolerance;//弹性
// arcC
// arcD arcB
// arcE O arcA //圆示意,圆弧上八个点和中心
// arcF arcEnd
// arcStart //弧开始点
public PointF O;//中心,圆心,用来拖动整个圆。
public PointF[] arcPoint; //
public List<Point>[] onRadpointOut;//半径+弹性处圆弧上点集合
public List<Point>[] onRadpointIn;//半径-弹性处圆弧上点集合
public RoiBase2()//构造函数
{
m_Center = new PointF();
m_Radius = 0;
m_tolerance = 0;
another = new PointF();
arcEnd = new PointF();
O = new PointF();
arcPoint = new PointF[8];
onRadpointOut = new List<Point>[8];//初始化圆弧,分为八段
onRadpointIn = new List<Point>[8];
for (int i = 0; i < 8; i++)//每段弧初始化
{
onRadpointOut[i] = new List<Point>();//半径+弹性处
onRadpointIn[i] = new List<Point>();//半径-弹性处
}
}
public bool Init(float x, float y, float r)//初始化函数
{
m_Center = new PointF(x, y);
m_Radius = r;
return true;
}
public void Draw(Graphics g, Pen p, int Dir)//画找圆工具
{
if (m_Radius == 0)
{
MessageBox.Show("please init Circle!Radius is zero!");//半径不能为零
}
else
{
// m_Radius=m_Radius+m_tolerance;
g.DrawRectangle(p, (int)m_Center.X - 5, (int)m_Center.Y - 5, 10, 10);//圆心小矩形,移动操作
//base cirle
Circle_MidPoint((int)m_Center.X, (int)m_Center.Y, (int)m_Radius, p, g);//基本圆,中点画圆算法
//in and out circle
DrawFollowing(g, p);//内外跟随圆,中点画圆算法
// start line
g.DrawLine(p, (int)m_Center.X, (int)m_Center.Y, (int)m_Center.X, (int)(m_Center.Y + m_Radius + m_tolerance + 15));
//arc end point and arccentrepoint;
PointF wuyong = new PointF();
for (int ii = 0; ii < 8; ii++)
{
onRadpointIn[ii].Clear();
onRadpointOut[ii].Clear();
}//内外弧间隔30,m_tolerance初始为0
FindArcCenterAndEnd((int)m_Center.X, (int)m_Center.Y, (int)(m_Radius - m_tolerance - 15), ref wuyong, ref onRadpointIn[0]);//求出第一段内弧onRadpointIn[0],wuyong无用
arcEnd = FindArcCenterAndEnd((int)m_Center.X, (int)m_Center.Y, (int)(m_Radius + m_tolerance + 15), ref another, ref onRadpointOut[0]);//求出第一段外弧onRadpointOut[0],求出another点
for (int mm = 0; mm < onRadpointIn[0].Count; mm++)
{//求出另外七段内弧
int yy = onRadpointIn[0][mm].Y - (int)m_Center.Y;
int xx = onRadpointIn[0][mm].X - (int)m_Center.X;
Point temppt = new Point();
temppt.X = yy + (int)m_Center.X;
temppt.Y = xx + (int)m_Center.Y;
onRadpointIn[1].Add(temppt);//1
temppt.X = yy + (int)m_Center.X;
temppt.Y = -xx + (int)m_Center.Y;
onRadpointIn[2].Add(temppt);//2
temppt.X = xx + (int)m_Center.X;
temppt.Y = -yy + (int)m_Center.Y;
onRadpointIn[3].Add(temppt);//3
temppt.X = -xx + (int)m_Center.X;
temppt.Y = -yy + (int)m_Center.Y;
onRadpointIn[4].Add(temppt);//4
temppt.X = -yy + (int)m_Center.X;
temppt.Y = -xx + (int)m_Center.Y;
onRadpointIn[5].Add(temppt);//5
temppt.X = -yy + (int)m_Center.X;
temppt.Y = xx + (int)m_Center.Y;
onRadpointIn[6].Add(temppt);//6
temppt.X = -xx + (int)m_Center.X;
temppt.Y = yy + (int)m_Center.Y;
onRadpointIn[7].Add(temppt);//7
}
for (int mm = 0; mm < onRadpointOut[0].Count; mm++)
{//求出另外七段外弧
int yy = onRadpointOut[0][mm].Y - (int)m_Center.Y;
int xx = onRadpointOut[0][mm].X - (int)m_Center.X;
Point temppt = new Point();
temppt.X = yy + (int)m_Center.X;
temppt.Y = xx + (int)m_Center.Y;
onRadpointOut[1].Add(temppt);//1
temppt.X = yy + (int)m_Center.X;
temppt.Y = -xx + (int)m_Center.Y;
onRadpointOut[2].Add(temppt);//2
temppt.X = xx + (int)m_Center.X;
temppt.Y = -yy + (int)m_Center.Y;
onRadpointOut[3].Add(temppt);//3
temppt.X = -xx + (int)m_Center.X;
temppt.Y = -yy + (int)m_Center.Y;
onRadpointOut[4].Add(temppt);//4
temppt.X = -yy + (int)m_Center.X;
temppt.Y = -xx + (int)m_Center.Y;
onRadpointOut[5].Add(temppt);//5
temppt.X = -yy + (int)m_Center.X;
temppt.Y = xx + (int)m_Center.Y;
onRadpointOut[6].Add(temppt);//6
temppt.X = -xx + (int)m_Center.X;
temppt.Y = yy + (int)m_Center.Y;
onRadpointOut[7].Add(temppt);//7
}
// end line
g.DrawLine(p, (int)m_Center.X, (int)m_Center.Y, (int)(m_Center.X + arcEnd.X), (int)(m_Center.Y + arcEnd.Y));
//little circle//画两个操作小圆
Circle_MidPoint((int)(m_Center.X + another.X), (int)(m_Center.Y + another.Y), 4, p, g);
Circle_MidPoint((int)(m_Center.X), (int)(m_Center.Y + m_Radius), 4, p, g);
//白到黑 CentreToDown
if (Dir == 0)
{
string str1 = "白";
Font drawfont = new Font("Arial", 9);
g.DrawString(str1, drawfont, Brushes.Brown, m_Center.X - 5, m_Center.Y + 5);
str1 = "黑";
g.DrawString(str1, drawfont, Brushes.Blue, (m_Center.X) - 5,
(m_Center.Y + m_Radius) + 5);
}
//黑到白 DownToCentre
if (Dir == 1)
{
string str1 = "黑";
Font drawfont = new Font("Arial", 9);
g.DrawString(str1, drawfont, Brushes.Blue, m_Center.X - 5, m_Center.Y + 5);
str1 = "白";
g.DrawString(str1, drawfont, Brushes.Brown, m_Center.X - 5,
(m_Center.Y + m_Radius) + 5);
}
O = m_Center;//"o"
arcPoint[0].X = (m_Center.X);
arcPoint[0].Y = (m_Center.Y + m_Radius + m_tolerance + 15);//start
arcPoint[1].X = (m_Center.X + arcEnd.X);
arcPoint[1].Y = (m_Center.Y + arcEnd.Y);//end
arcPoint[2].X = (m_Center.X + m_Radius + m_tolerance + 15);
arcPoint[2].Y = m_Center.Y;//"a"
arcPoint[3].X = m_Center.X + arcEnd.X;
arcPoint[3].Y = m_Center.Y - arcEnd.Y;//"b"
arcPoint[4].X = m_Center.X;//"c"
arcPoint[4].Y = (m_Center.Y - m_Radius - m_tolerance - 15);
arcPoint[5].X = (m_Center.X - arcEnd.X);//"d"
arcPoint[5].Y = (m_Center.Y - arcEnd.Y);
arcPoint[6].X = (m_Center.X - m_Radius - m_tolerance - 15);//"e"
arcPoint[6].Y = m_Center.Y;
arcPoint[7].X = (m_Center.X - arcEnd.X);//"f"
arcPoint[7].Y = (m_Center.Y + arcEnd.Y);
}
}
public void Circle_MidPoint(int x, int y, int r, Pen p, Graphics g)//中点画圆算法
{
int tx = 0, ty = r, d = (int)(1.25 - r);
while (tx < ty)
{
PointF tempPt = new PointF(x + tx, y + ty);
PointF tempPt1 = new PointF(tempPt.X + 1, tempPt.Y);
g.DrawLine(p, tempPt, tempPt1);
// pDC->SetPixel(x + tx, y + ty, color);//1
tempPt = new PointF(x + tx, y - ty);
tempPt1 = new PointF(tempPt.X + 1, tempPt.Y);
g.DrawLine(p, tempPt, tempPt1);
//pDC->SetPixel(x + tx, y - ty, color); //2
//pDC->SetPixel(x - tx, y + ty, color);
tempPt = new PointF(x - tx, y + ty);
tempPt1 = new PointF(tempPt.X + 1, tempPt.Y);
g.DrawLine(p, tempPt, tempPt1);
//pDC->SetPixel(x - tx, y - ty, color);//3
tempPt = new PointF(x - tx, y - ty);
tempPt1 = new PointF(tempPt.X + 1, tempPt.Y);
g.DrawLine(p, tempPt, tempPt1);
//pDC->SetPixel(x + ty, y + tx, color);//4
tempPt = new PointF(x + ty, y + tx);
tempPt1 = new PointF(tempPt.X + 1, tempPt.Y);
g.DrawLine(p, tempPt, tempPt1);
//pDC->SetPixel(x + ty, y - tx, color);//5
tempPt = new PointF(x + ty, y - tx);
tempPt1 = new PointF(tempPt.X + 1, tempPt.Y);
g.DrawLine(p, tempPt, tempPt1);
//pDC->SetPixel(x - ty, y + tx, color);//6
tempPt = new PointF(x - ty, y + tx);
tempPt1 = new PointF(tempPt.X + 1, tempPt.Y);
g.DrawLine(p, tempPt, tempPt1);
//pDC->SetPixel(x - ty, y - tx, color);//7
tempPt = new PointF(x - ty, y - tx);
tempPt1 = new PointF(tempPt.X + 1, tempPt.Y);
g.DrawLine(p, tempPt, tempPt1);
if (d < 0)
d += 2 * tx + 3;
else
{
d += 2 * (tx - ty) + 5;
ty--;
}
tx++;
}
}
public void DrawFollowing(Graphics g, Pen p)//中点画圆算法
{
Circle_MidPoint((int)m_Center.X, (int)m_Center.Y, (int)(m_Radius - m_tolerance - 15), p, g);
Circle_MidPoint((int)m_Center.X, (int)m_Center.Y, (int)(m_Radius + m_tolerance + 15), p, g);
}
public PointF FindArcCenterAndEnd(int x, int y, int r, ref PointF another, ref List<Point> onRadpoints)
{//找出第一段弧,another是第一段外弧的1/2弧处点,//中点画圆算法
// List<Point> hushangdian = new List<Point>();//1/8弧20150805
int tx = 0, ty = r, d = (int)(1.25 - r);
int count = 0;
while (tx < ty)
{
// pDC->SetPixel(x+tx,y+ty,color);
Point temp = new Point(x + tx, y + ty);
onRadpoints.Add(temp);
if (d < 0)
d += 2 * tx + 3;
else
{
d += 2 * (tx - ty) + 5;
ty--;
count++;
}
tx++;
count++;
}
Point pt = new Point(tx - 1, ty);
tx = 0; ty = r; d = (int)(1.25 - r);
int k = 0;
while (tx < ty)
{
if (d < 0)
d += 2 * tx + 3;
else
{
d += 2 * (tx - ty) + 5;
if (k == count / 2)
break;///////////////////////////////////important
ty--;
k++;
}
if (k == count / 2)
break;
tx++;
k++;
}
another.X = tx;//center
another.Y = ty;
return pt;//end
}
///////////////////////operate
public int IsPointInRect(PointF point)
{
if (point.X <= (int)m_Center.X + 5 && point.X >= (int)m_Center.X - 5
&& point.Y >= (int)m_Center.Y - 5 && point.Y <= (int)m_Center.Y + 5)
{
return 1; //E_HANDLE_INSIDE,//操作圆心移动
}
else if (point.X <= (int)(m_Center.X + another.X + 1.4) && point.X >= (int)(m_Center.X + another.X - 1.4)
&& point.Y >= (int)(m_Center.Y + another.Y - 1.4) && point.Y <= (int)(m_Center.Y + another.Y + 1.4))
{
return 9;//E_HANDLE_SOUTH_EAST,//操作弹性范围,改变内外圆
}
else if (point.X <= (int)(m_Center.X + 1.4) && point.X >= (int)(m_Center.X - 1.4)
&& point.Y >= (int)(m_Center.Y + m_Radius - 1.4) && point.Y <= (int)(m_Center.Y + m_Radius + 1.4))
{
return 4;// E_HANDLE_SOUTH,//操作半径大小
}
else
{
return -1;
}
}
public void Drag(PointF point)//中心改变
{
m_Center = (point);
}
public void DragTolerance(PointF point)//弹性改变
{
m_tolerance = (float)Math.Sqrt((point.X - m_Center.X) * (point.X - m_Center.X) + (point.Y - m_Center.Y) * (point.Y - m_Center.Y)) - m_Radius - 15;
// m_Radius = m_Radius + m_tolerance;
}
public void DragRadius(PointF point)//半径改变
{
m_Radius = (float)Math.Sqrt((point.X - m_Center.X) * (point.X - m_Center.X) + (point.Y - m_Center.Y) * (point.Y - m_Center.Y));
}
}
(未完待续....................)