WindowAppItemIsometricLine.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. #include "WindowAppItemIsometricLine.h"
  2. WindowAppItemIsometricLine::WindowAppItemIsometricLine(const UI_ISOLINE_INFO& lineInfo) :
  3. m_isoLineInfo(lineInfo)
  4. {
  5. }
  6. /// <summary>
  7. /// 绘制线条
  8. /// </summary>
  9. /// <param name="painter"></param>
  10. /// <param name="option"></param>
  11. /// <param name="widget"></param>
  12. void WindowAppItemIsometricLine::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget /*= nullptr*/)
  13. {
  14. Q_UNUSED(option);
  15. Q_UNUSED(widget);
  16. painter->setRenderHint(QPainter::Antialiasing, true);
  17. painter->save();
  18. // 绘制等宽线条
  19. this->drawIsoLines(painter);
  20. painter->restore();
  21. }
  22. /// <summary>
  23. /// 绘制两个端点
  24. /// </summary>
  25. /// <param name="painter"></param>
  26. void WindowAppItemIsometricLine::drawIsoLines(QPainter* painter)
  27. {
  28. // 如果stretchDir参数是None,那么绘制的就是目标控件的等宽线
  29. // 因为目标控件的等宽线永远都只出现在右侧和下侧
  30. if (m_isoLineInfo.stretchDir == STRETCH_DIRECTION::DIR_NONE)
  31. {
  32. // 右侧的等高线
  33. if (m_isoLineInfo.sideDir == SIDE_DIRECTION::SIDE_RIGHT)
  34. {
  35. QLine rightLine = Utility::getSideLineByID(m_isoLineInfo.pWidget, (short)SIDE_DIRECTION::SIDE_RIGHT);
  36. this->drawIsoLines(painter, rightLine, SIDE_DIRECTION::SIDE_RIGHT);
  37. }
  38. // 下侧的等宽线
  39. else if (m_isoLineInfo.sideDir == SIDE_DIRECTION::SIDE_BOTTOM)
  40. {
  41. QLine bottomLine = Utility::getSideLineByID(m_isoLineInfo.pWidget, (short)SIDE_DIRECTION::SIDE_BOTTOM);
  42. this->drawIsoLines(painter, bottomLine, SIDE_DIRECTION::SIDE_BOTTOM);
  43. }
  44. // 错误,不应该走到这里
  45. else
  46. {
  47. vDebug() << "[Error] Invalid SideDirection:" << (short) m_isoLineInfo.sideDir;
  48. }
  49. }
  50. // 如果stretchDir参数是有值的,那么绘制的就是源控件的等宽线
  51. // 源控件的等宽线就需要根据拖拽方向来绘制在不同的位置了,需要额外解析一下
  52. else
  53. {
  54. STRETCH_DIRECTION sDir = m_isoLineInfo.stretchDir;
  55. // 如果是等高线
  56. if (m_isoLineInfo.sideDir == SIDE_DIRECTION::SIDE_RIGHT)
  57. {
  58. // 如果拖拽的是上、下、左上、左下,等高线在右侧
  59. if (sDir == STRETCH_DIRECTION::DIR_TOP
  60. || sDir == STRETCH_DIRECTION::DIR_BOTTOM
  61. || sDir == STRETCH_DIRECTION::DIR_LEFTTOP
  62. || sDir == STRETCH_DIRECTION::DIR_LEFTBOTTOM
  63. )
  64. {
  65. // 获取右侧的边,然后在右侧边的右侧绘制等高线
  66. QLine rightLine = Utility::getSideLineByID(m_isoLineInfo.pWidget, (short)SIDE_DIRECTION::SIDE_RIGHT);
  67. this->drawIsoLines(painter, rightLine, SIDE_DIRECTION::SIDE_RIGHT);
  68. }
  69. // 如果拖拽的是右上、右下,等高线在左侧
  70. else if (sDir == STRETCH_DIRECTION::DIR_RIGHTTOP
  71. || sDir == STRETCH_DIRECTION::DIR_RIGHTBOTTOM
  72. )
  73. {
  74. // 获取左侧的边,然后在左侧边的左侧绘制等高线
  75. QLine leftLine = Utility::getSideLineByID(m_isoLineInfo.pWidget, (short)SIDE_DIRECTION::SIDE_LEFT);
  76. this->drawIsoLines(painter, leftLine, SIDE_DIRECTION::SIDE_LEFT);
  77. }
  78. }
  79. // 如果是等宽线
  80. else if (m_isoLineInfo.sideDir == SIDE_DIRECTION::SIDE_BOTTOM)
  81. {
  82. // 如果拖拽的是左、右、左上、右上,等宽线在下侧
  83. if (sDir == STRETCH_DIRECTION::DIR_LEFT
  84. || sDir == STRETCH_DIRECTION::DIR_RIGHT
  85. || sDir == STRETCH_DIRECTION::DIR_LEFTTOP
  86. || sDir == STRETCH_DIRECTION::DIR_RIGHTTOP
  87. )
  88. {
  89. // 获取底部的边,然后在底部边下侧绘制等宽线
  90. QLine bottomLine = Utility::getSideLineByID(m_isoLineInfo.pWidget, (short)SIDE_DIRECTION::SIDE_BOTTOM);
  91. this->drawIsoLines(painter, bottomLine, SIDE_DIRECTION::SIDE_BOTTOM);
  92. }
  93. // 如果拖拽的是右下、左下,等宽线在上侧
  94. else if (sDir == STRETCH_DIRECTION::DIR_LEFTBOTTOM
  95. || sDir == STRETCH_DIRECTION::DIR_RIGHTBOTTOM
  96. )
  97. {
  98. // 获取顶部的边,然后在顶部边上侧绘制等宽线
  99. QLine topLine = Utility::getSideLineByID(m_isoLineInfo.pWidget, (short)SIDE_DIRECTION::SIDE_TOP);
  100. this->drawIsoLines(painter, topLine, SIDE_DIRECTION::SIDE_TOP);
  101. }
  102. }
  103. }
  104. }
  105. /// <summary>
  106. /// 根据指定的位置绘制线条
  107. /// </summary>
  108. /// <param name="painter"></param>
  109. /// <param name="side"></param>
  110. /// <param name="sideDir"></param>
  111. void WindowAppItemIsometricLine::drawIsoLines(QPainter* painter, const QLine& side, SIDE_DIRECTION sideDir)
  112. {
  113. // 设置颜色风格
  114. painter->setPen(QPen(COLOR_REFLINE, PEN_LINE_WIDTH, Qt::SolidLine));
  115. QLine line1, line2;
  116. // 在右侧绘制
  117. if (sideDir == SIDE_DIRECTION::SIDE_RIGHT)
  118. {
  119. // 上侧标尺
  120. line1.setLine(
  121. side.p1().x() + ISOLINE_SPACE,
  122. side.p1().y() - ISOLINE_FIX,
  123. side.p1().x() + ISOLINE_SPACE + ISOLINE_MARK_LEN,
  124. side.p1().y() - ISOLINE_FIX
  125. );
  126. // 下侧标尺
  127. line2.setLine(
  128. side.p2().x() + ISOLINE_SPACE,
  129. side.p2().y() + ISOLINE_FIX,
  130. side.p2().x() + ISOLINE_SPACE + ISOLINE_MARK_LEN,
  131. side.p2().y() + ISOLINE_FIX
  132. );
  133. }
  134. // 在下侧绘制
  135. else if (sideDir == SIDE_DIRECTION::SIDE_BOTTOM)
  136. {
  137. // 左侧标尺
  138. line1.setLine(
  139. side.p1().x() - ISOLINE_FIX,
  140. side.p1().y() + ISOLINE_SPACE,
  141. side.p1().x() - ISOLINE_FIX,
  142. side.p1().y() + ISOLINE_SPACE + ISOLINE_MARK_LEN
  143. );
  144. // 右侧标尺
  145. line2.setLine(
  146. side.p2().x() + ISOLINE_FIX,
  147. side.p2().y() + ISOLINE_SPACE,
  148. side.p2().x() + ISOLINE_FIX,
  149. side.p2().y() + ISOLINE_SPACE + ISOLINE_MARK_LEN
  150. );
  151. }
  152. // 在左侧绘制
  153. else if (sideDir == SIDE_DIRECTION::SIDE_LEFT)
  154. {
  155. // 上侧标尺
  156. line1.setLine(
  157. side.p1().x() - ISOLINE_SPACE - ISOLINE_MARK_LEN,
  158. side.p1().y() - ISOLINE_FIX,
  159. side.p1().x() - ISOLINE_SPACE,
  160. side.p1().y() - ISOLINE_FIX
  161. );
  162. // 下侧标尺
  163. line2.setLine(
  164. side.p2().x() - ISOLINE_SPACE - ISOLINE_MARK_LEN,
  165. side.p2().y() + ISOLINE_FIX,
  166. side.p2().x() - ISOLINE_SPACE,
  167. side.p2().y() + ISOLINE_FIX
  168. );
  169. }
  170. // 在上侧绘制
  171. else if (sideDir == SIDE_DIRECTION::SIDE_TOP)
  172. {
  173. // 左侧标尺
  174. line1.setLine(
  175. side.p1().x() - ISOLINE_FIX,
  176. side.p1().y() - ISOLINE_SPACE - ISOLINE_MARK_LEN,
  177. side.p1().x() - ISOLINE_FIX,
  178. side.p1().y() - ISOLINE_SPACE
  179. );
  180. // 右侧标尺
  181. line2.setLine(
  182. side.p2().x() + ISOLINE_FIX,
  183. side.p2().y() - ISOLINE_SPACE - ISOLINE_MARK_LEN,
  184. side.p2().x() + ISOLINE_FIX,
  185. side.p2().y() - ISOLINE_SPACE
  186. );
  187. }
  188. // 错误,不应该执行到这里
  189. else
  190. {
  191. vDebug() << "[Error] Invalid side direction: " << (int)sideDir;
  192. return;
  193. }
  194. // 绘制标尺线条
  195. painter->drawLine(line1);
  196. painter->drawLine(line2);
  197. // 绘制箭头
  198. this->drawIsoArrowLines(painter, line1, line2, sideDir);
  199. }
  200. /// <summary>
  201. /// 绘制箭头线条
  202. /// </summary>
  203. /// <param name="painter"></param>
  204. void WindowAppItemIsometricLine::drawIsoArrowLines(QPainter* painter, QLine line1, QLine line2, SIDE_DIRECTION sideDir)
  205. {
  206. QLineF arrowLine;
  207. // 如果是左侧边或者右侧边,那么就是纵向的等高线
  208. if (sideDir == SIDE_DIRECTION::SIDE_RIGHT || sideDir == SIDE_DIRECTION::SIDE_LEFT)
  209. {
  210. // 线条
  211. arrowLine.setLine(
  212. line1.x1() + ISOLINE_MARK_LEN / 2,
  213. line1.y1() + ISOLINE_ARROW_SIZE + 1,
  214. line2.x1() + ISOLINE_MARK_LEN / 2,
  215. line2.y1() - ISOLINE_ARROW_SIZE - 1
  216. );
  217. painter->drawLine(arrowLine);
  218. }
  219. // 其他情况就是横向的等宽线
  220. else
  221. {
  222. // 线条
  223. arrowLine.setLine(
  224. line1.x1() + ISOLINE_ARROW_SIZE + 1,
  225. line1.y1() + ISOLINE_MARK_LEN / 2,
  226. line2.x1() - ISOLINE_ARROW_SIZE - 1,
  227. line2.y1() + ISOLINE_MARK_LEN / 2
  228. );
  229. painter->drawLine(arrowLine);
  230. }
  231. // 加上箭头
  232. this->drawIsoArrow(painter, arrowLine);
  233. // 翻转线条,绘制另一侧箭头
  234. arrowLine.setPoints(arrowLine.p2(), arrowLine.p1());
  235. this->drawIsoArrow(painter, arrowLine);
  236. }
  237. /// <summary>
  238. /// 为指定的线条绘制箭头
  239. /// </summary>
  240. /// <param name="isoLine"></param>
  241. void WindowAppItemIsometricLine::drawIsoArrow(QPainter* painter, QLineF isoLine)
  242. {
  243. // 获取单位向量
  244. QLineF v = isoLine.unitVector();
  245. // 设置箭头长度
  246. v.setLength(ISOLINE_ARROW_SIZE);
  247. v.translate(QPointF(isoLine.dx(), isoLine.dy()));
  248. // 计算法向量
  249. QLineF n = v.normalVector();
  250. // 设置箭头宽度
  251. n.setLength(n.length() * 0.5);
  252. // 计算两次法向量获取反向的法向量
  253. QLineF n2 = n.normalVector().normalVector();
  254. // 三个向量的终点即是三角形的三个顶点
  255. const QPointF points[3] = { v.p2(), n.p2(), n2.p2() };
  256. // 按照三个顶点绘制多边形,然后填充
  257. painter->setBrush(QBrush(COLOR_REFLINE, Qt::SolidPattern));
  258. painter->drawPolygon(points, 3);
  259. }