www.pudn.com > 20065291434354190.rar > XTube.cpp
#include "Stdafx.h" #include "XTube.h" #includeconst float pi = 3.1415926535f; XTube::XTube (REAL width, Color lColor, Color oColor) { lineWidth = width; outlineColor = oColor; lineColor = lColor; defLeftColor = lineColor; defRightColor = lineColor; defStartColor = lineColor; defEndColor = lineColor; defCircleOutlineColor = Color (255, 0, 0, 0); defCircleFillColor = Color (255, 255, 255, 255); defFontColor = Color (255, 255, 0, 0); defFontFace = "Arial"; defFontHeight = 6; defFontStyle = FontStyleRegular; defFont = NULL; } XTube::~XTube () { delete defFont; } XTube::XTube (const XTube& obj) { *this = obj; } XTube& XTube::operator = (const XTube& obj) { if (this == &obj) return *this; lineWidth = obj.lineWidth; outlineColor = obj.outlineColor; lineColor = obj.lineColor; defLeftColor = obj.defLeftColor; defRightColor = obj.defRightColor; defStartColor = obj.defStartColor; defEndColor = obj.defEndColor; defCircleOutlineColor = obj.defCircleOutlineColor; defCircleFillColor = obj.defCircleFillColor; defFontColor = obj.defFontColor; defFontFace = obj.defFontFace; defFontHeight = obj.defFontHeight; defFontStyle = obj.defFontStyle; defFont = new Font (CStringW(defFontFace).GetBuffer(), defFontHeight, defFontStyle); spots = obj.spots; for (size_t i = 0; i < spots.size (); i ++) spots[i].SetParent (this); return *this; } int XTube::Append (XSpot& spot) { spot.SetParent (this); if (spots.size () > 0 && spots[spots.size()-1].GetType () == STE_END) spots[spots.size()-1].SetType (STE_AUTO); spots.push_back(spot); return (int) spots.size (); } int XTube::Move (float x, float y) { for (size_t i = 0; i < spots.size (); i ++) spots[i].Move (x, y); return 0; } int XTube::Recalculate () { if (spots.size () < 2) return -1; float radius = lineWidth*2; //拐弯半径 //计算left, right //计算每个点的斜率,用角度表达 for (size_t i = 1; i < spots.size (); i ++) { float dx = spots[i].position.X - spots[i-1].position.X; float dy = spots[i].position.Y - spots[i-1].position.Y; if (dx*dx + dy*dy < 4*radius*radius) //距离太短,不足以拐弯 continue; if (fabs(dx) == 0) //垂直 { spots[i-1].right = PointF (spots[i-1].position.X, dy > 0 ? spots[i-1].position.Y+radius : spots[i-1].position.Y-radius); spots[i].left = PointF (spots[i].position.X, dy > 0 ? spots[i].position.Y-radius : spots[i].position.Y+radius); } else if (fabs(dy) == 0) //水平 { spots[i-1].right = PointF (dx > 0 ? spots[i-1].position.X+radius : spots[i-1].position.X-radius, spots[i-1].position.Y); spots[i].left = PointF (dx > 0 ? spots[i].position.X-radius : spots[i].position.X+radius, spots[i].position.Y); } else //斜线 { float k = dy/dx; float x = sqrtf (radius*radius/(1+k*k)); if (dx < 0) x = -x; float y = k*x; spots[i-1].right = PointF (spots[i-1].position.X+x, spots[i-1].position.Y+y); spots[i].left = PointF (spots[i].position.X-x, spots[i].position.Y-y); } spots[i-1].angle = atan2f (dy, dx) * 360 / (2*pi); if (spots[i-1].angle < 0) spots[i-1].angle += 360; //保证在0-360之间 } spots[spots.size()-1].left = spots[spots.size()-1].position; spots[spots.size()-1].right = spots[spots.size()-1].position; spots[spots.size()-1].angle = spots[spots.size()-2].angle; //计算拐弯的中心点,半径,角度 for (size_t i = 1; i < spots.size ()-1; i ++) { REAL angle1 = spots[i-1].angle + 180; REAL angle2 = spots[i].angle; if (angle1 > 360) angle1 -= 360; //<< //如果角度太小 //如果长度太短 //不拐弯 //if (fabs(180 - fabs(angle2 - angle1)) < 15) // continue; if (spots[i].left.X == spots[i].position.X && spots[i].left.Y == spots[i].position.Y) continue; if (spots[i].right.X == spots[i].position.X && spots[i].right.Y == spots[i].position.Y) continue; //>> bool clockwise = false; if (angle1 < 180) { if (angle2 > angle1 && angle2 < angle1+180) //顺时针 clockwise = true; else //逆时针 clockwise = false; } else //angle1 >= 180 { if (angle2 > angle1-180 && angle2 < angle1) //逆时针 clockwise = false; else //顺时针 clockwise = true; } //<<计算拐弯的起始角,角度大小 spots[i].sweepAngle = fabsf (angle2 - angle1); if (spots[i].sweepAngle > 180) spots[i].sweepAngle = 360 - spots[i].sweepAngle; spots[i].sweepAngle = 180 - spots[i].sweepAngle; if (clockwise) { spots[i].startAngle = (angle1 + 270) > 360 ? (angle1 + 270) - 360 : (angle1 + 270); spots[i].sweepAngle = - spots[i].sweepAngle; } else { spots[i].startAngle = (angle1 + 90) > 360 ? (angle1 + 90) - 360 : (angle1 + 90); } //>> //TRACE3 ("clockWise=%d, startAngle=%d, sweepAngle=%d\n", clockwise, spots[i].startAngle, spots[i].sweepAngle); //<<计算半径和中心点 float dx1 = spots[i].position.X - spots[i].left.X; float dy1 = spots[i].position.Y - spots[i].left.Y; float dx2 = spots[i].position.X - spots[i].right.X; float dy2 = spots[i].position.Y - spots[i].right.Y; if (fabsf (dy1) == 0) // { //y = kx + b, k = - dx2/dy2 float b2 = spots[i].right.Y + spots[i].right.X * dx2 / dy2; spots[i].center.X = spots[i].left.X; spots[i].center.Y = b2 - spots[i].center.X * dx2 / dy2; spots[i].radius = fabsf (spots[i].center.Y - spots[i].left.Y); } else if (fabsf (dy2) == 0) { float b1 = spots[i].left.Y + spots[i].left.X * dx1 / dy1; spots[i].center.X = spots[i].right.X; spots[i].center.Y = b1 - spots[i].center.X * dx1 / dy1; spots[i].radius = fabsf (spots[i].center.Y - spots[i].right.Y); } else //都是斜线 { float b1 = spots[i].left.Y + spots[i].left.X * dx1 / dy1; float b2 = spots[i].right.Y + spots[i].right.X * dx2 / dy2; spots[i].center.X = (b2 - b1) / (dx2/dy2 - dx1/dy1); spots[i].center.Y = b1 - spots[i].center.X * dx1/dy1; float r1 = sqrtf ((spots[i].center.X - spots[i].right.X)*(spots[i].center.X - spots[i].right.X) + (spots[i].center.Y - spots[i].right.Y)*(spots[i].center.Y - spots[i].right.Y)); float r2 = sqrtf ((spots[i].center.X - spots[i].left.X)*(spots[i].center.X - spots[i].left.X) + (spots[i].center.Y - spots[i].left.Y)*(spots[i].center.Y - spots[i].left.Y)); spots[i].radius = (r1+r2)/2; } //TRACE ("i=%d, x=%f, y=%f, radius=%f\n", i, spots[i].center.X, spots[i].center.Y, spots[i].radius); } spots[0].center = spots[0].position; spots[0].radius = 0; spots[0].startAngle = 0; spots[0].sweepAngle = 0; spots[spots.size()-1].center = spots[spots.size()-1].position; spots[spots.size()-1].radius = 0; spots[spots.size()-1].startAngle = 0; spots[spots.size()-1].sweepAngle = 0; //计算中心点的有关参数 for (size_t i = 0; i < spots.size (); i ++) { REAL angle1 = i > 0 ? spots[i-1].angle + 180 : spots[0].angle; REAL angle2 = spots[i].angle; if (angle1 > 360) angle1 -= 360; //从拐弯中心点到曲线中心点的角度 if (i == 0) spots[i].ANGLE = spots[0].angle + 270; else if (i == spots.size () -1) spots[i].ANGLE = spots[spots.size () -1].angle + 270; else spots[i].ANGLE = (angle1 + angle2)/2; //<<判断方向 int kx = 1; int ky = 1; if (spots[i].center.X > spots[i].position.X) kx = -1; if (spots[i].center.Y > spots[i].position.Y) ky = -1; //>> if (spots[i].ANGLE > 360) spots[i].ANGLE -= 360; float K = fabsf (tanf (spots[i].ANGLE*2*pi/360)); float dx = sqrtf (spots[i].radius*spots[i].radius/(1+K*K)); float dy = dx*K; //<<计算A点 if (fabs(spots[i].sweepAngle) >= 15) //判断是否拐弯,如果不拐弯,不用计算A点 { spots[i].A.X = spots[i].center.X + dx*kx; spots[i].A.Y = spots[i].center.Y + dy*ky; } //>> dx = sqrtf (lineWidth*lineWidth/(1+K*K)); dy = dx*K; //<< float sweep = angle2 - angle1; if (angle2 < angle1) sweep += 360; if (sweep < 180) { kx = -kx; ky = -ky; } //>> //计算B1, B2 spots[i].B1.X = spots[i].A.X + dx*kx*1.5f; spots[i].B1.Y = spots[i].A.Y + dy*ky*1.5f; spots[i].B2.X = spots[i].A.X - dx*kx*1.5f; spots[i].B2.Y = spots[i].A.Y - dy*ky*1.5f; //计算C1, C2 if (i == 0) { kx = spots[0].position.X > spots[1].position.X ? 1 : -1; ky = spots[0].position.Y > spots[1].position.Y ? 1 : -1; spots[i].C1.X = spots[i].A.X + 2*dy*kx; spots[i].C1.Y = spots[i].A.Y + 2*dx*ky; spots[i].C2.X = spots[i].A.X - 2*dy*kx; spots[i].C2.Y = spots[i].A.Y - 2*dx*ky; } else if (i == spots.size () -1 ) { kx = spots[spots.size()-1].position.X > spots[spots.size()-2].position.X ? 1 : -1; ky = spots[spots.size()-1].position.Y > spots[spots.size()-2].position.Y ? 1 : -1; spots[i].C1.X = spots[i].A.X + 2*dy*kx; spots[i].C1.Y = spots[i].A.Y + 2*dx*ky; spots[i].C2.X = spots[i].A.X - 2*dy*kx; spots[i].C2.Y = spots[i].A.Y - 2*dx*ky; } else { spots[i].C1.X = spots[i].A.X + 3*dx*kx; spots[i].C1.Y = spots[i].A.Y + 3*dy*ky; spots[i].C2.X = spots[i].A.X - 3*dx*kx; spots[i].C2.Y = spots[i].A.Y - 3*dy*ky; } //TRACE ("i=%d, A.X=%f, A.Y=%f\n", i, spots[i].A.X, spots[i].A.Y); } return 0; } int XTube::Draw (Graphics* g) { DrawLines (g); DrawSpots (g); return 0; } int XTube::DrawLines (Graphics* g) { if (spots.size () < 2) return 0; Pen linePen (lineColor, lineWidth); linePen.SetLineJoin (LineJoinRound); if (lineWidth > 2) { GraphicsPath path; PointF lastPoint = spots[0].position; for (size_t i = 1; i < spots.size (); i ++) { //如果角度基本相同,画直线 if (fabs(spots[i].sweepAngle) >= 15) //角度太小 { path.AddLine (lastPoint, spots[i].left); path.AddArc (spots[i].center.X - spots[i].radius, spots[i].center.Y - spots[i].radius, spots[i].radius*2, spots[i].radius*2, spots[i].startAngle, spots[i].sweepAngle); lastPoint = spots[i].right; } else { path.AddLine (lastPoint, spots[i].position); lastPoint = spots[i].position; } } path.Widen (&linePen); path.Outline (); g->SetSmoothingMode(SmoothingModeAntiAlias); SolidBrush lineBrush (lineColor); g->FillPath (&lineBrush, &path); } else { PointF lastPoint = spots[0].position; for (size_t i = 1; i < spots.size (); i ++) { /* //如果角度基本相同,画直线 if (fabs(spots[i].sweepAngle) >= 15) //角度太小 { g->DrawLine (&linePen, lastPoint, spots[i].left); g->DrawArc (&linePen, spots[i].center.X - spots[i].radius, spots[i].center.Y - spots[i].radius, spots[i].radius*2, spots[i].radius*2, spots[i].startAngle, spots[i].sweepAngle); lastPoint = spots[i].right; } else */ { g->DrawLine (&linePen, lastPoint, spots[i].position); lastPoint = spots[i].position; } } } return 0; } int XTube::DrawSpots (Graphics* g, map * spotMap) { delete defFont; defFont = new Font (CStringW(defFontFace).GetBuffer(), defFontHeight, defFontStyle); for (size_t i = 0; i < spots.size (); i ++) spots[i].Draw (g, spotMap); return 0; }