/* * UBGeometryUtils.cpp * * Created on: Sep 20, 2008 * Author: luc */ #include "UBGeometryUtils.h" const double PI = 4.0 * atan(1.0); UBGeometryUtils::UBGeometryUtils() { // NOOP } UBGeometryUtils::~UBGeometryUtils() { // NOOP } QPolygonF UBGeometryUtils::lineToPolygon(const QLineF& pLine, const qreal& pWidth) { qreal x1 = pLine.x1(); qreal y1 = pLine.y1(); qreal x2 = pLine.x2(); qreal y2 = pLine.y2(); qreal alpha = (90.0 - pLine.angle()) * PI / 180.0; qreal hypothenuse = pWidth / 2; // TODO UB 4.x PERF cache sin/cos table qreal opposite = sin(alpha) * hypothenuse; qreal adjacent = cos(alpha) * hypothenuse; QPointF p1a(x1 - adjacent, y1 - opposite); QPointF p1b(x1 + adjacent, y1 + opposite); QPointF p2a(x2 - adjacent, y2 - opposite); QPointF p2b(x2 + adjacent, y2 + opposite); QPainterPath painterPath; painterPath.moveTo(p1a); painterPath.lineTo(p2a); painterPath.arcTo(x2 - hypothenuse, y2 - hypothenuse, pWidth, pWidth, (90.0 + pLine.angle()), -180.0); //painterPath.lineTo(p2b); painterPath.lineTo(p1b); painterPath.arcTo(x1 - hypothenuse, y1 - hypothenuse, pWidth, pWidth, -1 * (90.0 - pLine.angle()), -180.0); painterPath.closeSubpath(); return painterPath.toFillPolygon(); } QPolygonF UBGeometryUtils::lineToPolygon(const QPointF& pStart, const QPointF& pEnd, const qreal& pStartWidth, const qreal& pEndWidth) { qreal x1 = pStart.x(); qreal y1 = pStart.y(); qreal x2 = pEnd.x(); qreal y2 = pEnd.y(); QLineF line(pStart, pEnd); qreal alpha = (90.0 - line.angle()) * PI / 180.0; qreal hypothenuseStart = pStartWidth / 2; qreal hypothenuseEnd = pEndWidth / 2; qreal sinAlpha = sin(alpha); qreal cosAlpha = cos(alpha); // TODO UB 4.x PERF cache sin/cos table qreal oppositeStart = sinAlpha * hypothenuseStart; qreal adjacentStart = cosAlpha * hypothenuseStart; QPointF p1a(x1 - adjacentStart, y1 - oppositeStart); QPointF p1b(x1 + adjacentStart, y1 + oppositeStart); qreal oppositeEnd = sinAlpha * hypothenuseEnd; qreal adjacentEnd = cosAlpha * hypothenuseEnd; QPointF p2a(x2 - adjacentEnd, y2 - oppositeEnd); QPainterPath painterPath; painterPath.moveTo(p1a); painterPath.lineTo(p2a); painterPath.arcTo(x2 - hypothenuseEnd, y2 - hypothenuseEnd, pEndWidth, pEndWidth, (90.0 + line.angle()), -180.0); painterPath.lineTo(p1b); painterPath.arcTo(x1 - hypothenuseStart, y1 - hypothenuseStart, pStartWidth, pStartWidth, -1 * (90.0 - line.angle()), -180.0); painterPath.closeSubpath(); return painterPath.toFillPolygon(); } QPolygonF UBGeometryUtils::arcToPolygon(const QLineF& startRadius, qreal spanAngleInDegrees, qreal width) { qreal startAngleInDegrees = - startRadius.angle(); if (startAngleInDegrees > 180) startAngleInDegrees -= 360; else if (startAngleInDegrees < -180) startAngleInDegrees += 360; qreal radiusLength = startRadius.length(); qreal angle = 2 * asin(width / (2 * radiusLength)) * 180 / PI; bool overlap = abs(spanAngleInDegrees) > 360 - angle; if (overlap) spanAngleInDegrees = spanAngleInDegrees < 0 ? -360 : 360; qreal endAngleInDegrees = startAngleInDegrees + spanAngleInDegrees; qreal innerRadius = radiusLength - width / 2; QRectF innerSquare( startRadius.p1().x() - innerRadius, startRadius.p1().y() - innerRadius, 2 * innerRadius, 2 * innerRadius); qreal outerRadius = radiusLength + width / 2; QRectF outerSquare( startRadius.p1().x() - outerRadius, startRadius.p1().y() - outerRadius, 2 * outerRadius, 2 * outerRadius); QRectF startSquare( startRadius.p2().x() - width / 2, startRadius.p2().y() - width / 2, width, width); QRectF endSquare( startRadius.p1().x() + radiusLength * cos(endAngleInDegrees * PI / 180.0) - width / 2, startRadius.p1().y() + radiusLength * sin(endAngleInDegrees * PI / 180.0) - width / 2, width, width); QPainterPath painterPath( QPointF( startRadius.p1().x() + innerRadius * cos(startAngleInDegrees * PI / 180.0), startRadius.p1().y() + innerRadius * sin(startAngleInDegrees * PI / 180.0))); startAngleInDegrees = - startAngleInDegrees; endAngleInDegrees = - endAngleInDegrees; spanAngleInDegrees = - spanAngleInDegrees; if (overlap) { painterPath.addEllipse(outerSquare); QPainterPath innerPainterPath; innerPainterPath.addEllipse(innerSquare); painterPath = painterPath.subtracted(innerPainterPath); } else { painterPath.arcTo(innerSquare, startAngleInDegrees, spanAngleInDegrees); painterPath.arcTo(endSquare, 180.0 + endAngleInDegrees, spanAngleInDegrees > 0 ? -180.0 : 180.0); painterPath.arcTo(outerSquare, endAngleInDegrees, - spanAngleInDegrees); painterPath.arcTo(startSquare, startAngleInDegrees, spanAngleInDegrees > 0 ? -180.0 : 180.0); painterPath.closeSubpath(); } return painterPath.toFillPolygon(); } QPointF UBGeometryUtils::pointConstrainedInRect(QPointF point, QRectF rect) { return QPointF(qMax(rect.x(), qMin(rect.x() + rect.width(), point.x())), qMax(rect.y(), qMin(rect.y() + rect.height(), point.y()))); } QPoint UBGeometryUtils::pointConstrainedInRect(QPoint point, QRect rect) { return QPoint(qMax(rect.x(), qMin(rect.x() + rect.width(), point.x())), qMax(rect.y(), qMin(rect.y() + rect.height(), point.y()))); } QRectF UBGeometryUtils::lineToInnerRect(const QLineF& pLine, const qreal& pWidth) { qreal centerX = (pLine.x1() + pLine.x2()) / 2; qreal centerY = (pLine.y1() + pLine.y2()) / 2; qreal side = sqrt((pWidth * pWidth) / 2); qreal halfSide = side / 2; return QRectF(centerX - halfSide, centerY - halfSide, side, side); } QVector UBGeometryUtils::crashPointList(const QVector points) { QVector result(points); int position = 1; while(position < result.size()) { if (result.at(position) == result.at(position - 1)) { result.remove(position); } else { ++position; } } return result; }