?? xtube.cpp
字號:
#include "Stdafx.h"
#include "XTube.h"
#include <math.h>
const 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<CString, PointF>* 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;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -