XTube.cpp
上传用户:yokoluohf
上传日期:2013-02-25
资源大小:769k
文件大小:11k
源码类别:

GIS编程

开发平台:

Visual C++

  1. #include "Stdafx.h"
  2. #include "XTube.h"
  3. #include <math.h>
  4. const float pi = 3.1415926535f;
  5. XTube::XTube (REAL width, Color lColor, Color oColor)
  6. {
  7. lineWidth = width;
  8. outlineColor = oColor;
  9. lineColor = lColor;
  10. defLeftColor = lineColor;
  11. defRightColor = lineColor;
  12. defStartColor = lineColor;
  13. defEndColor = lineColor;
  14. defCircleOutlineColor = Color (255, 0, 0, 0);
  15. defCircleFillColor = Color (255, 255, 255, 255);
  16. defFontColor = Color (255, 255, 0, 0);
  17. defFontFace = "Arial";
  18. defFontHeight = 6;
  19. defFontStyle = FontStyleRegular;
  20. defFont = NULL;
  21. }
  22. XTube::~XTube ()
  23. {
  24. delete defFont;
  25. }
  26. XTube::XTube (const XTube& obj)
  27. {
  28. *this = obj;
  29. }
  30. XTube& XTube::operator = (const XTube& obj)
  31. {
  32. if (this == &obj)
  33. return *this;
  34. lineWidth = obj.lineWidth;
  35. outlineColor = obj.outlineColor;
  36. lineColor = obj.lineColor;
  37. defLeftColor = obj.defLeftColor;
  38. defRightColor = obj.defRightColor;
  39. defStartColor = obj.defStartColor;
  40. defEndColor = obj.defEndColor;
  41. defCircleOutlineColor = obj.defCircleOutlineColor;
  42. defCircleFillColor = obj.defCircleFillColor;
  43. defFontColor = obj.defFontColor;
  44. defFontFace = obj.defFontFace;
  45. defFontHeight = obj.defFontHeight;
  46. defFontStyle = obj.defFontStyle;
  47. defFont = new Font (CStringW(defFontFace).GetBuffer(), defFontHeight, defFontStyle);
  48. spots = obj.spots;
  49. for (size_t i = 0; i < spots.size (); i ++)
  50. spots[i].SetParent (this);
  51. return *this;
  52. }
  53. int XTube::Append (XSpot& spot)
  54. {
  55. spot.SetParent (this);
  56. if (spots.size () > 0 && spots[spots.size()-1].GetType () == STE_END)
  57. spots[spots.size()-1].SetType (STE_AUTO);
  58. spots.push_back(spot);
  59. return (int) spots.size ();
  60. }
  61. int XTube::Move (float x, float y)
  62. {
  63. for (size_t i = 0; i < spots.size (); i ++)
  64. spots[i].Move (x, y);
  65. return 0;
  66. }
  67. int XTube::Recalculate ()
  68. {
  69. if (spots.size () < 2) return -1;
  70. float radius = lineWidth*2; //拐弯半径
  71. //计算left, right
  72. //计算每个点的斜率,用角度表达
  73. for (size_t i = 1; i < spots.size (); i ++)
  74. {
  75. float dx = spots[i].position.X - spots[i-1].position.X;
  76. float dy = spots[i].position.Y - spots[i-1].position.Y;
  77. if (dx*dx + dy*dy < 4*radius*radius) //距离太短,不足以拐弯
  78. continue;
  79. if (fabs(dx) == 0) //垂直
  80. {
  81. spots[i-1].right = PointF (spots[i-1].position.X, dy > 0 ? spots[i-1].position.Y+radius : spots[i-1].position.Y-radius);
  82. spots[i].left = PointF (spots[i].position.X, dy > 0 ? spots[i].position.Y-radius : spots[i].position.Y+radius);
  83. }
  84. else if (fabs(dy) == 0) //水平
  85. {
  86. spots[i-1].right = PointF (dx > 0 ? spots[i-1].position.X+radius : spots[i-1].position.X-radius, spots[i-1].position.Y);
  87. spots[i].left = PointF (dx > 0 ? spots[i].position.X-radius : spots[i].position.X+radius, spots[i].position.Y);
  88. }
  89. else //斜线
  90. {
  91. float k = dy/dx;
  92. float x = sqrtf (radius*radius/(1+k*k));
  93. if (dx < 0) x = -x;
  94. float y = k*x;
  95. spots[i-1].right = PointF (spots[i-1].position.X+x, spots[i-1].position.Y+y);
  96. spots[i].left = PointF (spots[i].position.X-x, spots[i].position.Y-y);
  97. }
  98. spots[i-1].angle = atan2f (dy, dx) * 360 / (2*pi);
  99. if (spots[i-1].angle < 0) spots[i-1].angle += 360; //保证在0-360之间
  100. }
  101. spots[spots.size()-1].left = spots[spots.size()-1].position;
  102. spots[spots.size()-1].right = spots[spots.size()-1].position;
  103. spots[spots.size()-1].angle = spots[spots.size()-2].angle;
  104. //计算拐弯的中心点,半径,角度
  105. for (size_t i = 1; i < spots.size ()-1; i ++)
  106. {
  107. REAL angle1 = spots[i-1].angle + 180;
  108. REAL angle2 = spots[i].angle;
  109. if (angle1 > 360) angle1 -= 360;
  110. //<<
  111. //如果角度太小
  112. //如果长度太短
  113. //不拐弯
  114. //if (fabs(180 - fabs(angle2 - angle1)) < 15)
  115. // continue;
  116. if (spots[i].left.X == spots[i].position.X && spots[i].left.Y == spots[i].position.Y)
  117. continue;
  118. if (spots[i].right.X == spots[i].position.X && spots[i].right.Y == spots[i].position.Y)
  119. continue;
  120. //>>
  121. bool clockwise = false;
  122. if (angle1 < 180)
  123. {
  124. if (angle2 > angle1 && angle2 < angle1+180) //顺时针
  125. clockwise = true;
  126. else //逆时针
  127. clockwise = false;
  128. }
  129. else //angle1 >= 180
  130. {
  131. if (angle2 > angle1-180 && angle2 < angle1) //逆时针
  132. clockwise = false;
  133. else //顺时针
  134. clockwise = true;
  135. }
  136. //<<计算拐弯的起始角,角度大小
  137. spots[i].sweepAngle = fabsf (angle2 - angle1);
  138. if (spots[i].sweepAngle > 180)
  139. spots[i].sweepAngle = 360 - spots[i].sweepAngle;
  140. spots[i].sweepAngle = 180 - spots[i].sweepAngle;
  141. if (clockwise)
  142. {
  143. spots[i].startAngle = (angle1 + 270) > 360 ?  (angle1 + 270) - 360 : (angle1 + 270);
  144. spots[i].sweepAngle = - spots[i].sweepAngle;
  145. }
  146. else
  147. {
  148. spots[i].startAngle = (angle1 + 90) > 360 ? (angle1 + 90) - 360 : (angle1 + 90);
  149. }
  150. //>>
  151. //TRACE3 ("clockWise=%d, startAngle=%d, sweepAngle=%dn", clockwise, spots[i].startAngle, spots[i].sweepAngle);
  152. //<<计算半径和中心点
  153. float dx1 = spots[i].position.X - spots[i].left.X;
  154. float dy1 = spots[i].position.Y - spots[i].left.Y;
  155. float dx2 = spots[i].position.X - spots[i].right.X;
  156. float dy2 = spots[i].position.Y - spots[i].right.Y;
  157. if (fabsf (dy1) == 0) //
  158. {
  159. //y = kx + b, k = - dx2/dy2
  160. float b2 = spots[i].right.Y + spots[i].right.X * dx2 / dy2;
  161. spots[i].center.X = spots[i].left.X;
  162. spots[i].center.Y = b2 - spots[i].center.X * dx2 / dy2;
  163. spots[i].radius = fabsf (spots[i].center.Y - spots[i].left.Y);
  164. }
  165. else if (fabsf (dy2) == 0)
  166. {
  167. float b1 = spots[i].left.Y + spots[i].left.X * dx1 / dy1;
  168. spots[i].center.X = spots[i].right.X;
  169. spots[i].center.Y = b1 - spots[i].center.X * dx1 / dy1;
  170. spots[i].radius = fabsf (spots[i].center.Y - spots[i].right.Y);
  171. }
  172. else //都是斜线
  173. {
  174. float b1 = spots[i].left.Y + spots[i].left.X * dx1 / dy1;
  175. float b2 = spots[i].right.Y + spots[i].right.X * dx2 / dy2;
  176. spots[i].center.X = (b2 - b1) / (dx2/dy2 - dx1/dy1);
  177. spots[i].center.Y = b1 - spots[i].center.X * dx1/dy1;
  178. float r1 = sqrtf ((spots[i].center.X - spots[i].right.X)*(spots[i].center.X - spots[i].right.X)
  179. + (spots[i].center.Y - spots[i].right.Y)*(spots[i].center.Y - spots[i].right.Y));
  180. float r2 = sqrtf ((spots[i].center.X - spots[i].left.X)*(spots[i].center.X - spots[i].left.X)
  181. + (spots[i].center.Y - spots[i].left.Y)*(spots[i].center.Y - spots[i].left.Y));
  182. spots[i].radius = (r1+r2)/2;
  183. }
  184. //TRACE ("i=%d, x=%f, y=%f, radius=%fn", i, spots[i].center.X, spots[i].center.Y, spots[i].radius);
  185. }
  186. spots[0].center = spots[0].position;
  187. spots[0].radius = 0;
  188. spots[0].startAngle = 0;
  189. spots[0].sweepAngle = 0;
  190. spots[spots.size()-1].center = spots[spots.size()-1].position;
  191. spots[spots.size()-1].radius = 0;
  192. spots[spots.size()-1].startAngle = 0;
  193. spots[spots.size()-1].sweepAngle = 0;
  194. //计算中心点的有关参数
  195. for (size_t i = 0; i < spots.size (); i ++)
  196. {
  197. REAL angle1 = i > 0 ? spots[i-1].angle + 180 : spots[0].angle;
  198. REAL angle2 = spots[i].angle;
  199. if (angle1 > 360) angle1 -= 360;
  200. //从拐弯中心点到曲线中心点的角度
  201. if (i == 0)
  202. spots[i].ANGLE = spots[0].angle + 270;
  203. else if (i == spots.size () -1)
  204. spots[i].ANGLE = spots[spots.size () -1].angle + 270;
  205. else
  206. spots[i].ANGLE = (angle1 + angle2)/2;
  207. //<<判断方向
  208. int kx = 1;
  209. int ky = 1;
  210. if (spots[i].center.X > spots[i].position.X) kx = -1;
  211. if (spots[i].center.Y > spots[i].position.Y) ky = -1;
  212. //>>
  213. if (spots[i].ANGLE > 360) spots[i].ANGLE -= 360;
  214. float K = fabsf (tanf (spots[i].ANGLE*2*pi/360));
  215. float dx = sqrtf (spots[i].radius*spots[i].radius/(1+K*K));
  216. float dy = dx*K;
  217. //<<计算A点
  218. if (fabs(spots[i].sweepAngle) >= 15) //判断是否拐弯,如果不拐弯,不用计算A点
  219. {
  220. spots[i].A.X = spots[i].center.X + dx*kx;
  221. spots[i].A.Y = spots[i].center.Y + dy*ky;
  222. }
  223. //>>
  224. dx = sqrtf (lineWidth*lineWidth/(1+K*K));
  225. dy = dx*K;
  226. //<<
  227. float sweep = angle2 - angle1;
  228. if (angle2 < angle1) sweep += 360;
  229. if (sweep < 180)
  230. {
  231. kx = -kx;
  232. ky = -ky;
  233. }
  234. //>>
  235. //计算B1, B2
  236. spots[i].B1.X = spots[i].A.X + dx*kx*1.5f;
  237. spots[i].B1.Y = spots[i].A.Y + dy*ky*1.5f;
  238. spots[i].B2.X = spots[i].A.X - dx*kx*1.5f;
  239. spots[i].B2.Y = spots[i].A.Y - dy*ky*1.5f;
  240. //计算C1, C2
  241. if (i == 0)
  242. {
  243. kx = spots[0].position.X > spots[1].position.X ? 1 : -1;
  244. ky = spots[0].position.Y > spots[1].position.Y ? 1 : -1;
  245. spots[i].C1.X = spots[i].A.X + 2*dy*kx;
  246. spots[i].C1.Y = spots[i].A.Y + 2*dx*ky;
  247. spots[i].C2.X = spots[i].A.X - 2*dy*kx;
  248. spots[i].C2.Y = spots[i].A.Y - 2*dx*ky;
  249. }
  250. else if (i == spots.size () -1 )
  251. {
  252. kx = spots[spots.size()-1].position.X > spots[spots.size()-2].position.X ? 1 : -1;
  253. ky = spots[spots.size()-1].position.Y > spots[spots.size()-2].position.Y ? 1 : -1;
  254. spots[i].C1.X = spots[i].A.X + 2*dy*kx;
  255. spots[i].C1.Y = spots[i].A.Y + 2*dx*ky;
  256. spots[i].C2.X = spots[i].A.X - 2*dy*kx;
  257. spots[i].C2.Y = spots[i].A.Y - 2*dx*ky;
  258. }
  259. else
  260. {
  261. spots[i].C1.X = spots[i].A.X + 3*dx*kx;
  262. spots[i].C1.Y = spots[i].A.Y + 3*dy*ky;
  263. spots[i].C2.X = spots[i].A.X - 3*dx*kx;
  264. spots[i].C2.Y = spots[i].A.Y - 3*dy*ky;
  265. }
  266. //TRACE ("i=%d, A.X=%f, A.Y=%fn", i, spots[i].A.X, spots[i].A.Y);
  267. }
  268. return 0;
  269. }
  270. int XTube::Draw (Graphics* g)
  271. {
  272. DrawLines (g);
  273. DrawSpots (g);
  274. return 0;
  275. }
  276. int XTube::DrawLines (Graphics* g)
  277. {
  278. if (spots.size () < 2) return 0;
  279. Pen linePen (lineColor, lineWidth);
  280. linePen.SetLineJoin (LineJoinRound);
  281. if (lineWidth > 2)
  282. {
  283. GraphicsPath path;
  284. PointF lastPoint = spots[0].position;
  285. for (size_t i = 1; i < spots.size (); i ++)
  286. {
  287. //如果角度基本相同,画直线
  288. if (fabs(spots[i].sweepAngle) >= 15) //角度太小
  289. {
  290. path.AddLine (lastPoint, spots[i].left);
  291. path.AddArc (spots[i].center.X - spots[i].radius, spots[i].center.Y - spots[i].radius,
  292. spots[i].radius*2, spots[i].radius*2, spots[i].startAngle, spots[i].sweepAngle);
  293. lastPoint = spots[i].right;
  294. }
  295. else
  296. {
  297. path.AddLine (lastPoint, spots[i].position);
  298. lastPoint = spots[i].position;
  299. }
  300. }
  301. path.Widen (&linePen);
  302. path.Outline ();
  303. g->SetSmoothingMode(SmoothingModeAntiAlias);
  304. SolidBrush lineBrush (lineColor);
  305. g->FillPath (&lineBrush, &path);
  306. }
  307. else
  308. {
  309. PointF lastPoint = spots[0].position;
  310. for (size_t i = 1; i < spots.size (); i ++)
  311. {
  312. /*
  313. //如果角度基本相同,画直线
  314. if (fabs(spots[i].sweepAngle) >= 15) //角度太小
  315. {
  316. g->DrawLine (&linePen, lastPoint, spots[i].left);
  317. g->DrawArc (&linePen, spots[i].center.X - spots[i].radius, spots[i].center.Y - spots[i].radius,
  318. spots[i].radius*2, spots[i].radius*2, spots[i].startAngle, spots[i].sweepAngle);
  319. lastPoint = spots[i].right;
  320. }
  321. else
  322. */
  323. {
  324. g->DrawLine (&linePen, lastPoint, spots[i].position);
  325. lastPoint = spots[i].position;
  326. }
  327. }
  328. }
  329. return 0;
  330. }
  331. int XTube::DrawSpots (Graphics* g, map<CString, PointF>* spotMap)
  332. {
  333. delete defFont;
  334. defFont = new Font (CStringW(defFontFace).GetBuffer(), defFontHeight, defFontStyle);
  335. for (size_t i = 0; i < spots.size (); i ++)
  336. spots[i].Draw (g, spotMap);
  337. return 0;
  338. }