#include "WindowAppItemIsometricLine.h" WindowAppItemIsometricLine::WindowAppItemIsometricLine(const UI_ISOLINE_INFO& lineInfo) : m_isoLineInfo(lineInfo) { } /// /// 绘制线条 /// /// /// /// void WindowAppItemIsometricLine::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget /*= nullptr*/) { Q_UNUSED(option); Q_UNUSED(widget); painter->setRenderHint(QPainter::Antialiasing, true); painter->save(); // 绘制等宽线条 this->drawIsoLines(painter); painter->restore(); } /// /// 绘制两个端点 /// /// void WindowAppItemIsometricLine::drawIsoLines(QPainter* painter) { // 如果stretchDir参数是None,那么绘制的就是目标控件的等宽线 // 因为目标控件的等宽线永远都只出现在右侧和下侧 if (m_isoLineInfo.stretchDir == STRETCH_DIRECTION::DIR_NONE) { // 右侧的等高线 if (m_isoLineInfo.sideDir == SIDE_DIRECTION::SIDE_RIGHT) { QLine rightLine = Utility::getSideLineByID(m_isoLineInfo.pWidget, (short)SIDE_DIRECTION::SIDE_RIGHT); this->drawIsoLines(painter, rightLine, SIDE_DIRECTION::SIDE_RIGHT); } // 下侧的等宽线 else if (m_isoLineInfo.sideDir == SIDE_DIRECTION::SIDE_BOTTOM) { QLine bottomLine = Utility::getSideLineByID(m_isoLineInfo.pWidget, (short)SIDE_DIRECTION::SIDE_BOTTOM); this->drawIsoLines(painter, bottomLine, SIDE_DIRECTION::SIDE_BOTTOM); } // 错误,不应该走到这里 else { vDebug() << "[Error] Invalid SideDirection:" << (short) m_isoLineInfo.sideDir; } } // 如果stretchDir参数是有值的,那么绘制的就是源控件的等宽线 // 源控件的等宽线就需要根据拖拽方向来绘制在不同的位置了,需要额外解析一下 else { STRETCH_DIRECTION sDir = m_isoLineInfo.stretchDir; // 如果是等高线 if (m_isoLineInfo.sideDir == SIDE_DIRECTION::SIDE_RIGHT) { // 如果拖拽的是上、下、左上、左下,等高线在右侧 if (sDir == STRETCH_DIRECTION::DIR_TOP || sDir == STRETCH_DIRECTION::DIR_BOTTOM || sDir == STRETCH_DIRECTION::DIR_LEFTTOP || sDir == STRETCH_DIRECTION::DIR_LEFTBOTTOM ) { // 获取右侧的边,然后在右侧边的右侧绘制等高线 QLine rightLine = Utility::getSideLineByID(m_isoLineInfo.pWidget, (short)SIDE_DIRECTION::SIDE_RIGHT); this->drawIsoLines(painter, rightLine, SIDE_DIRECTION::SIDE_RIGHT); } // 如果拖拽的是右上、右下,等高线在左侧 else if (sDir == STRETCH_DIRECTION::DIR_RIGHTTOP || sDir == STRETCH_DIRECTION::DIR_RIGHTBOTTOM ) { // 获取左侧的边,然后在左侧边的左侧绘制等高线 QLine leftLine = Utility::getSideLineByID(m_isoLineInfo.pWidget, (short)SIDE_DIRECTION::SIDE_LEFT); this->drawIsoLines(painter, leftLine, SIDE_DIRECTION::SIDE_LEFT); } } // 如果是等宽线 else if (m_isoLineInfo.sideDir == SIDE_DIRECTION::SIDE_BOTTOM) { // 如果拖拽的是左、右、左上、右上,等宽线在下侧 if (sDir == STRETCH_DIRECTION::DIR_LEFT || sDir == STRETCH_DIRECTION::DIR_RIGHT || sDir == STRETCH_DIRECTION::DIR_LEFTTOP || sDir == STRETCH_DIRECTION::DIR_RIGHTTOP ) { // 获取底部的边,然后在底部边下侧绘制等宽线 QLine bottomLine = Utility::getSideLineByID(m_isoLineInfo.pWidget, (short)SIDE_DIRECTION::SIDE_BOTTOM); this->drawIsoLines(painter, bottomLine, SIDE_DIRECTION::SIDE_BOTTOM); } // 如果拖拽的是右下、左下,等宽线在上侧 else if (sDir == STRETCH_DIRECTION::DIR_LEFTBOTTOM || sDir == STRETCH_DIRECTION::DIR_RIGHTBOTTOM ) { // 获取顶部的边,然后在顶部边上侧绘制等宽线 QLine topLine = Utility::getSideLineByID(m_isoLineInfo.pWidget, (short)SIDE_DIRECTION::SIDE_TOP); this->drawIsoLines(painter, topLine, SIDE_DIRECTION::SIDE_TOP); } } } } /// /// 根据指定的位置绘制线条 /// /// /// /// void WindowAppItemIsometricLine::drawIsoLines(QPainter* painter, const QLine& side, SIDE_DIRECTION sideDir) { // 设置颜色风格 painter->setPen(QPen(COLOR_REFLINE, PEN_LINE_WIDTH, Qt::SolidLine)); QLine line1, line2; // 在右侧绘制 if (sideDir == SIDE_DIRECTION::SIDE_RIGHT) { // 上侧标尺 line1.setLine( side.p1().x() + ISOLINE_SPACE, side.p1().y() - ISOLINE_FIX, side.p1().x() + ISOLINE_SPACE + ISOLINE_MARK_LEN, side.p1().y() - ISOLINE_FIX ); // 下侧标尺 line2.setLine( side.p2().x() + ISOLINE_SPACE, side.p2().y() + ISOLINE_FIX, side.p2().x() + ISOLINE_SPACE + ISOLINE_MARK_LEN, side.p2().y() + ISOLINE_FIX ); } // 在下侧绘制 else if (sideDir == SIDE_DIRECTION::SIDE_BOTTOM) { // 左侧标尺 line1.setLine( side.p1().x() - ISOLINE_FIX, side.p1().y() + ISOLINE_SPACE, side.p1().x() - ISOLINE_FIX, side.p1().y() + ISOLINE_SPACE + ISOLINE_MARK_LEN ); // 右侧标尺 line2.setLine( side.p2().x() + ISOLINE_FIX, side.p2().y() + ISOLINE_SPACE, side.p2().x() + ISOLINE_FIX, side.p2().y() + ISOLINE_SPACE + ISOLINE_MARK_LEN ); } // 在左侧绘制 else if (sideDir == SIDE_DIRECTION::SIDE_LEFT) { // 上侧标尺 line1.setLine( side.p1().x() - ISOLINE_SPACE - ISOLINE_MARK_LEN, side.p1().y() - ISOLINE_FIX, side.p1().x() - ISOLINE_SPACE, side.p1().y() - ISOLINE_FIX ); // 下侧标尺 line2.setLine( side.p2().x() - ISOLINE_SPACE - ISOLINE_MARK_LEN, side.p2().y() + ISOLINE_FIX, side.p2().x() - ISOLINE_SPACE, side.p2().y() + ISOLINE_FIX ); } // 在上侧绘制 else if (sideDir == SIDE_DIRECTION::SIDE_TOP) { // 左侧标尺 line1.setLine( side.p1().x() - ISOLINE_FIX, side.p1().y() - ISOLINE_SPACE - ISOLINE_MARK_LEN, side.p1().x() - ISOLINE_FIX, side.p1().y() - ISOLINE_SPACE ); // 右侧标尺 line2.setLine( side.p2().x() + ISOLINE_FIX, side.p2().y() - ISOLINE_SPACE - ISOLINE_MARK_LEN, side.p2().x() + ISOLINE_FIX, side.p2().y() - ISOLINE_SPACE ); } // 错误,不应该执行到这里 else { vDebug() << "[Error] Invalid side direction: " << (int)sideDir; return; } // 绘制标尺线条 painter->drawLine(line1); painter->drawLine(line2); // 绘制箭头 this->drawIsoArrowLines(painter, line1, line2, sideDir); } /// /// 绘制箭头线条 /// /// void WindowAppItemIsometricLine::drawIsoArrowLines(QPainter* painter, QLine line1, QLine line2, SIDE_DIRECTION sideDir) { QLineF arrowLine; // 如果是左侧边或者右侧边,那么就是纵向的等高线 if (sideDir == SIDE_DIRECTION::SIDE_RIGHT || sideDir == SIDE_DIRECTION::SIDE_LEFT) { // 线条 arrowLine.setLine( line1.x1() + ISOLINE_MARK_LEN / 2, line1.y1() + ISOLINE_ARROW_SIZE + 1, line2.x1() + ISOLINE_MARK_LEN / 2, line2.y1() - ISOLINE_ARROW_SIZE - 1 ); painter->drawLine(arrowLine); } // 其他情况就是横向的等宽线 else { // 线条 arrowLine.setLine( line1.x1() + ISOLINE_ARROW_SIZE + 1, line1.y1() + ISOLINE_MARK_LEN / 2, line2.x1() - ISOLINE_ARROW_SIZE - 1, line2.y1() + ISOLINE_MARK_LEN / 2 ); painter->drawLine(arrowLine); } // 加上箭头 this->drawIsoArrow(painter, arrowLine); // 翻转线条,绘制另一侧箭头 arrowLine.setPoints(arrowLine.p2(), arrowLine.p1()); this->drawIsoArrow(painter, arrowLine); } /// /// 为指定的线条绘制箭头 /// /// void WindowAppItemIsometricLine::drawIsoArrow(QPainter* painter, QLineF isoLine) { // 获取单位向量 QLineF v = isoLine.unitVector(); // 设置箭头长度 v.setLength(ISOLINE_ARROW_SIZE); v.translate(QPointF(isoLine.dx(), isoLine.dy())); // 计算法向量 QLineF n = v.normalVector(); // 设置箭头宽度 n.setLength(n.length() * 0.5); // 计算两次法向量获取反向的法向量 QLineF n2 = n.normalVector().normalVector(); // 三个向量的终点即是三角形的三个顶点 const QPointF points[3] = { v.p2(), n.p2(), n2.p2() }; // 按照三个顶点绘制多边形,然后填充 painter->setBrush(QBrush(COLOR_REFLINE, Qt::SolidPattern)); painter->drawPolygon(points, 3); }