void tst_QPainterPath::angleAtPercent() { for (int angle = 0; angle < 360; ++angle) { QLineF line = QLineF::fromPolar(100, angle); QPainterPath path; path.moveTo(line.p1()); path.lineTo(line.p2()); QCOMPARE(path.angleAtPercent(0.5), line.angle()); } }
void PrimitivePainter::drawLabel(QPainterPath* R, QPainter* thePainter, qreal PixelPerM, QString str, QString strBg) const { if (!DrawLabel) return; if (str.isEmpty() && strBg.isEmpty()) return; thePainter->save(); if (getLabelArea()) { QPointF C(R->boundingRect().center()); drawPointLabel(C, str, strBg, thePainter, PixelPerM); thePainter->restore(); return; } LineParameters lp = labelBoundary(); qreal WW = PixelPerM*lp.Proportional+lp.Fixed; if (WW < 10) return; //qreal WWR = qMax(PixelPerM*R->widthOf()*BackgroundScale+BackgroundOffset, PixelPerM*R->widthOf()*ForegroundScale+ForegroundOffset); QPainterPath textPath; QPainterPath tranformedRoadPath = *R; QFont font = getLabelFont(); if (!str.isEmpty()) { QRegion rg = thePainter->clipRegion(); font.setPixelSize(int(WW)); QFontMetrics metrics(font); if (font.pixelSize() >= 5 && tranformedRoadPath.length() > metrics.width(str)) { thePainter->setFont(font); int repeat = int((tranformedRoadPath.length() / ((metrics.width(str) * LABEL_PATH_DISTANCE))) - 0.5); int numSegment = repeat+1; qreal lenSegment = tranformedRoadPath.length() / numSegment; qreal startSegment = 0; QPainterPath textPath; do { QRegion rg = thePainter->clipRegion(); qreal curLen = startSegment + ((lenSegment - metrics.width(str)) / 2); int modIncrement = 1; qreal modAngle = 0; int modY = 0; if (cos(angToRad(tranformedRoadPath.angleAtPercent((startSegment+(lenSegment/2))/tranformedRoadPath.length()))) < 0) { modIncrement = -1; modAngle = 180.0; curLen += metrics.width(str); } for (int i = 0; i < str.length(); ++i) { qreal t = tranformedRoadPath.percentAtLength(curLen); QPointF pt = tranformedRoadPath.pointAtPercent(t); qreal angle = tranformedRoadPath.angleAtPercent(t); modY = (metrics.ascent()/2)-3; QMatrix m; m.translate(pt.x(), pt.y()); m.rotate(-angle+modAngle); QPainterPath charPath; charPath.addText(0, modY, font, str.mid(i, 1)); charPath = charPath * m; textPath.addPath(charPath); qreal incremenet = metrics.width(str[i]); curLen += (incremenet * modIncrement); } startSegment += lenSegment; } while (--repeat >= 0); if (getLabelHalo()) { thePainter->setPen(QPen(Qt::white, font.pixelSize()/6)); thePainter->drawPath(textPath); } thePainter->setPen(Qt::NoPen); thePainter->setBrush(LabelColor); thePainter->drawPath(textPath); thePainter->setClipRegion(rg); } } if (DrawLabelBackground && !strBg.isEmpty()) { QRegion rg = thePainter->clipRegion(); font.setPixelSize(int(WW)); QFontMetrics metrics(font); int repeat = int((tranformedRoadPath.length() / (metrics.width(strBg) * LABEL_STRAIGHT_DISTANCE)) - 0.5); int numSegment = repeat+1; qreal lenSegment = tranformedRoadPath.length() / numSegment; qreal startSegment = 0; do { int modX = 0; int modY = 0; qreal curLen = startSegment + (lenSegment / 2); qreal t = tranformedRoadPath.percentAtLength(curLen); QPointF pt = tranformedRoadPath.pointAtPercent(t); modX = - (metrics.width(strBg)/2); //modX = WW; modY = (metrics.ascent()/2); QPainterPath textPath, bgPath; textPath.addText(modX, modY, font, strBg); bgPath.addRect(textPath.boundingRect().adjusted(-BG_SPACING, -BG_SPACING, BG_SPACING, BG_SPACING)); bool rgContains = false; for (int i=0; i<rg.rects().size(); i++) { if (rg.rects()[i].contains(bgPath.boundingRect().toRect().translated(pt.toPoint()))) { rgContains = true; break; } } if (rgContains) { thePainter->translate(pt); thePainter->setPen(QPen(LabelColor, BG_PEN_SZ)); thePainter->setBrush(LabelBackgroundColor); thePainter->drawPath(bgPath); if (getLabelHalo()) { thePainter->setPen(QPen(Qt::white, font.pixelSize()/5)); thePainter->drawPath(textPath); } thePainter->setPen(Qt::NoPen); thePainter->setBrush(LabelColor); thePainter->drawPath(textPath); rg -= bgPath.boundingRect().toRect().translated(pt.toPoint()); } startSegment += lenSegment; } while (--repeat >= 0); thePainter->setClipRegion(rg); } thePainter->restore(); }
qreal Geometry::tangentLineAt(QPainterPath const &path, QPointF const &point) { qreal const percentage = percentageAt(path, point); return path.angleAtPercent(percentage); }
void PageItem_PathText::DrawObj_Item(ScPainter *p, QRectF cullingArea) { itemText.invalidateAll(); firstChar = 0; MaxChars = 0; int a; double chs; QString chstr, chstr2, chstr3; ScText *hl; double dx; FPoint point = FPoint(0, 0); FPoint tangent = FPoint(0, 0); uint seg = 0; double segLen = 0; QColor tmp; CurX = Extra; QString cachedStroke = ""; QString cachedFill = ""; double cachedFillShade = -1; double cachedStrokeShade = -1; QString actStroke = ""; QString actFill = ""; double actFillShade = -1; double actStrokeShade = -1; QColor cachedFillQ; QColor cachedStrokeQ; if (!m_Doc->layerOutline(LayerID)) { if (PoShow) { p->setupPolygon(&PoLine, false); if (NamedLStyle.isEmpty()) { if ((!patternStrokeVal.isEmpty()) && (m_Doc->docPatterns.contains(patternStrokeVal))) { if (patternStrokePath) { QPainterPath guidePath = PoLine.toQPainterPath(false); DrawStrokePattern(p, guidePath); } else { p->setPattern(&m_Doc->docPatterns[patternStrokeVal], patternStrokeScaleX, patternStrokeScaleY, patternStrokeOffsetX, patternStrokeOffsetY, patternStrokeRotation, patternStrokeSkewX, patternStrokeSkewY, patternStrokeMirrorX, patternStrokeMirrorY); p->setStrokeMode(ScPainter::Pattern); p->strokePath(); } } else if (GrTypeStroke > 0) { if ((!gradientStrokeVal.isEmpty()) && (!m_Doc->docGradients.contains(gradientStrokeVal))) gradientStrokeVal = ""; if (!(gradientStrokeVal.isEmpty()) && (m_Doc->docGradients.contains(gradientStrokeVal))) stroke_gradient = m_Doc->docGradients[gradientStrokeVal]; if (stroke_gradient.Stops() < 2) // fall back to solid stroking if there are not enough colorstops in the gradient. { if (lineColor() != CommonStrings::None) { p->setBrush(strokeQColor); p->setStrokeMode(ScPainter::Solid); } else p->setStrokeMode(ScPainter::None); } else { p->setStrokeMode(ScPainter::Gradient); p->stroke_gradient = stroke_gradient; if (GrTypeStroke == 6) p->setGradient(VGradient::linear, FPoint(GrStrokeStartX, GrStrokeStartY), FPoint(GrStrokeEndX, GrStrokeEndY), FPoint(GrStrokeStartX, GrStrokeStartY), GrStrokeScale, GrStrokeSkew); else p->setGradient(VGradient::radial, FPoint(GrStrokeStartX, GrStrokeStartY), FPoint(GrStrokeEndX, GrStrokeEndY), FPoint(GrStrokeFocalX, GrStrokeFocalY), GrStrokeScale, GrStrokeSkew); } p->strokePath(); } else if (lineColor() != CommonStrings::None) { p->setStrokeMode(ScPainter::Solid); p->strokePath(); } } else { p->setStrokeMode(ScPainter::Solid); multiLine ml = m_Doc->MLineStyles[NamedLStyle]; QColor tmp; for (int it = ml.size()-1; it > -1; it--) { if (ml[it].Color != CommonStrings::None) // && (ml[it].Width != 0)) { SetQColor(&tmp, ml[it].Color, ml[it].Shade); p->setPen(tmp, ml[it].Width, static_cast<Qt::PenStyle>(ml[it].Dash), static_cast<Qt::PenCapStyle>(ml[it].LineEnd), static_cast<Qt::PenJoinStyle>(ml[it].LineJoin)); p->strokePath(); } } } } } double totalTextLen = 0.0; double totalCurveLen = 0.0; double extraOffset = 0.0; if (itemText.length() != 0) { CurX += itemText.charStyle(0).fontSize() * itemText.charStyle(0).tracking() / 10000.0; totalTextLen += itemText.charStyle(0).fontSize() * itemText.charStyle(0).tracking() / 10000.0; } segLen = PoLine.lenPathSeg(seg); for (a = firstChar; a < itemText.length(); ++a) { hl = itemText.item(a); chstr = hl->ch; if (chstr[0] == SpecialChars::PAGENUMBER || chstr[0] == SpecialChars::PARSEP || chstr[0] == SpecialChars::PAGECOUNT || chstr[0] == SpecialChars::TAB || chstr[0] == SpecialChars::LINEBREAK) continue; if (a < itemText.length()-1) chstr += itemText.text(a+1, 1); hl->glyph.yadvance = 0; layoutGlyphs(itemText.charStyle(a), chstr, hl->glyph); hl->glyph.shrink(); if (hl->ch == SpecialChars::OBJECT) totalTextLen += (hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth()) * hl->glyph.scaleH; else totalTextLen += hl->glyph.wide()+hl->fontSize() * hl->tracking() / 10000.0; } for (uint segs = 0; segs < PoLine.size()-3; segs += 4) { totalCurveLen += PoLine.lenPathSeg(segs); } if ((itemText.defaultStyle().alignment() != 0) && (totalCurveLen >= totalTextLen + Extra)) { if (itemText.defaultStyle().alignment() == 2) { CurX = totalCurveLen - totalTextLen; CurX -= Extra; } if (itemText.defaultStyle().alignment() == 1) CurX = (totalCurveLen - totalTextLen) / 2.0; if ((itemText.defaultStyle().alignment() == 3) || (itemText.defaultStyle().alignment() == 4)) extraOffset = (totalCurveLen - Extra - totalTextLen) / static_cast<double>(itemText.length()); } #ifndef NLS_PROTO QPainterPath guidePath = PoLine.toQPainterPath(false); QList<QPainterPath> pathList = decomposePath(guidePath); QPainterPath currPath = pathList[0]; int currPathIndex = 0; for (a = firstChar; a < itemText.length(); ++a) { CurY = 0; hl = itemText.item(a); chstr = hl->ch; if (chstr[0] == SpecialChars::PAGENUMBER || chstr[0] == SpecialChars::PARSEP || chstr[0] == SpecialChars::PAGECOUNT || chstr[0] == SpecialChars::TAB || chstr[0] == SpecialChars::LINEBREAK) continue; chs = hl->fontSize(); if (a < itemText.length()-1) chstr += itemText.text(a+1, 1); hl->glyph.yadvance = 0; layoutGlyphs(itemText.charStyle(a), chstr, hl->glyph); hl->glyph.shrink(); // HACK if (hl->ch == SpecialChars::OBJECT) dx = (hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth()) * hl->glyph.scaleH / 2.0; else dx = hl->glyph.wide() / 2.0; CurX += dx; double currPerc = currPath.percentAtLength(CurX); if (currPerc >= 0.9999999) { currPathIndex++; if (currPathIndex == pathList.count()) { MaxChars = a; break; } currPath = pathList[currPathIndex]; CurX = dx; currPerc = currPath.percentAtLength(CurX); } double currAngle = currPath.angleAtPercent(currPerc); #if QT_VERSION >= 0x040400 if (currAngle <= 180.0) currAngle *= -1.0; else currAngle = 360.0 - currAngle; #endif QPointF currPoint = currPath.pointAtPercent(currPerc); tangent = FPoint(cos(currAngle * M_PI / 180.0), sin(currAngle * M_PI / 180.0)); point = FPoint(currPoint.x(), currPoint.y()); hl->glyph.xoffset = 0; hl->PtransX = point.x(); hl->PtransY = point.y(); hl->PRot = currAngle * M_PI / 180.0; hl->PDx = dx; QTransform trafo = QTransform( 1, 0, 0, -1, -dx, 0 ); if (textPathFlipped) trafo *= QTransform(1, 0, 0, -1, 0, 0); if (textPathType == 0) trafo *= QTransform( tangent.x(), tangent.y(), tangent.y(), -tangent.x(), point.x(), point.y() ); // ID's Rainbow mode else if (textPathType == 1) trafo *= QTransform( 1, 0, 0, -1, point.x(), point.y() ); // ID's Stair Step mode else if (textPathType == 2) { double a = 1; if (tangent.x() < 0) a = -1; if (fabs(tangent.x()) > 0.1) trafo *= QTransform( a, (tangent.y() / tangent.x()) * a, 0, -1, point.x(), point.y() ); // ID's Skew mode else trafo *= QTransform( a, 4 * a, 0, -1, point.x(), point.y() ); } QTransform sca = p->worldMatrix(); trafo *= sca; p->save(); QTransform savWM = p->worldMatrix(); p->setWorldMatrix(trafo); if (!m_Doc->RePos) { actFill = itemText.charStyle(a).fillColor(); actFillShade = itemText.charStyle(a).fillShade(); if (actFill != CommonStrings::None) { p->setFillMode(ScPainter::Solid); if ((cachedFillShade != actFillShade) || (cachedFill != actFill)) { SetQColor(&tmp, actFill, actFillShade); p->setBrush(tmp); cachedFillQ = tmp; cachedFill = actFill; cachedFillShade = actFillShade; } else p->setBrush(cachedFillQ); } else p->setFillMode(ScPainter::None); actStroke = itemText.charStyle(a).strokeColor(); actStrokeShade = itemText.charStyle(a).strokeShade(); if (actStroke != CommonStrings::None) { if ((cachedStrokeShade != actStrokeShade) || (cachedStroke != actStroke)) { SetQColor(&tmp, actStroke, actStrokeShade); p->setPen(tmp, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); cachedStrokeQ = tmp; cachedStroke = actStroke; cachedStrokeShade = actStrokeShade; } else p->setPen(cachedStrokeQ, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); } p->translate(0.0, BaseOffs); if (hl->ch == SpecialChars::OBJECT) DrawObj_Embedded(p, cullingArea, itemText.charStyle(a), hl->embedded.getItem()); else drawGlyphs(p, itemText.charStyle(a), hl->glyph); } p->setWorldMatrix(savWM); p->restore(); MaxChars = a+1; CurX -= dx; if (hl->ch == SpecialChars::OBJECT) CurX += (hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth()) * hl->glyph.scaleH; else CurX += hl->glyph.wide()+hl->fontSize() * hl->tracking() / 10000.0 + extraOffset; } #endif }
//! //! Updates the path end points according to the positions of start and end //! nodes. //! void ConnectionGraphicsItem::updatePath () { prepareGeometryChange(); // calculate positions of the end points QPointF startPoint = m_startPoint; QPointF endPoint = m_endPoint; if (m_startNodeItem) startPoint += m_startNodeItem->pos(); if (m_endNodeItem) endPoint += m_endNodeItem->pos(); // calculate the rectangles to help calculating the positions of the node's anchor points const qreal offset = 10; QRectF baseAnchorRect = QRectF(-offset, -offset, 2 * offset, 2 * offset); QRectF startAnchorRect = baseAnchorRect.translated(startPoint); QRectF endAnchorRect = baseAnchorRect.translated(endPoint); if (m_startNodeItem) startAnchorRect = m_startNodeItem->rect().adjusted(-offset, -offset, offset, offset).translated(m_startNodeItem->pos()); if (m_endNodeItem) endAnchorRect = m_endNodeItem->rect().adjusted(-offset, -offset, offset, offset).translated(m_endNodeItem->pos()); // // Diagram of anchor points for start and end nodes: // // x x sU2, sU1 eU1, eU2 x x // ,----, ,----, // | | | | // | | | | // | x| x sP, sO eO, eP x |x | // '----' '----' // x x sL2, sL1 eL1, eL2 x x // QPointF sP = startPoint; QPointF sO = QPointF(startAnchorRect.right(), startPoint.y()); QPointF sU1 = startAnchorRect.topRight(); QPointF sU2 = startAnchorRect.topLeft(); QPointF sL1 = startAnchorRect.bottomRight(); QPointF sL2 = startAnchorRect.bottomLeft(); QPointF eP = endPoint; QPointF eO = QPointF(endAnchorRect.left(), endPoint.y()); QPointF eU1 = endAnchorRect.topLeft(); QPointF eU2 = endAnchorRect.topRight(); QPointF eL1 = endAnchorRect.bottomLeft(); QPointF eL2 = endAnchorRect.bottomRight(); // declare path segments QList<QPointF> startPoints; QPainterPath cubicPath; QList<QPointF> endPoints; // construct the path segments if (eO.x() < sO.x() && eU2.x() > sL2.x() && eU2.y() < sL2.y() && eL2.y() > sU2.y()) { //> case 1V: elements very close to each other startPoints << sP << sO; QPointF offsetVector = QPointF(0, 0.75 * (eO.y() - sO.y())); cubicPath.moveTo(sO); cubicPath.cubicTo(sO + offsetVector, eO - offsetVector, eO); endPoints << eO << eP; } else if (eO.x() >= sO.x()) { //> case 1H: end node is right of start node startPoints << sP << sO; QPointF offsetVector = QPointF(0.75 * (eO.x() - sO.x()), 0); cubicPath.moveTo(sO); cubicPath.cubicTo(sO + offsetVector, eO - offsetVector, eO); endPoints << eO << eP; } else if (eU1.y() >= sL1.y()) { //> case 2LV startPoints << sP << sO << sL1; QPointF offsetVector = QPointF(0, 0.75 * (eU1.y() - sL1.y())); cubicPath.moveTo(sL1); cubicPath.cubicTo(sL1 + offsetVector, eU1 - offsetVector, eU1); endPoints << eU1 << eO << eP; } else if (eL1.y() <= sU1.y()) { //> case 2UV startPoints << sP << sO << sU1; QPointF offsetVector = QPointF(0, 0.75 * (eL1.y() - sU1.y())); cubicPath.moveTo(sU1); cubicPath.cubicTo(sU1 + offsetVector, eL1 - offsetVector, eL1); endPoints << eL1 << eO << eP; } else if (eP.y() >= sP.y()) { //> case 3L startPoints << sP << sO << sL1 << sL2; QPointF offsetVector = QPointF(0.75 * (eU2.x() - sL2.x()), 0); cubicPath.moveTo(sL2); cubicPath.cubicTo(sL2 + offsetVector, eU2 - offsetVector, eU2); endPoints << eU2 << eU1 << eO << eP; } else { //> case 3U startPoints << sP << sO << sU1 << sU2; QPointF offsetVector = QPointF(0.75 * (eL2.x() - sU2.x()), 0); cubicPath.moveTo(sU2); cubicPath.cubicTo(sU2 + offsetVector, eL2 - offsetVector, eL2); endPoints << eL2 << eL1 << eO << eP; } // build the main path from the path segments m_mainPath = QPainterPath(); for (int i = 0; i < startPoints.size(); ++i) if (i == 0) m_mainPath.moveTo(startPoints[0]); else m_mainPath.lineTo(startPoints[i]); m_mainPath.addPath(cubicPath); for (int i = 0; i < endPoints.size(); ++i) if (i == 0) m_mainPath.moveTo(endPoints[0]); else m_mainPath.lineTo(endPoints[i]); // create the shadow path as a copy of the main path m_shadowPath = QPainterPath(m_mainPath); // move the path elements of the shadow path one pixel down and to the right for (int i = 1; i < m_shadowPath.elementCount(); ++i) { QPainterPath::Element element = m_shadowPath.elementAt(i); m_shadowPath.setElementPositionAt(i, element.x + 1, element.y + 1); } // get the center point for the arrow and the angle at that point static const qreal t = 0.5; QPointF arrowPoint = cubicPath.pointAtPercent(t); qreal angle = cubicPath.angleAtPercent(t) * Pi / 180; // calculate the polygon for the arrow head qreal pathLengthFraction = m_mainPath.length() / 10; static const qreal maxArrowSize = 10; qreal arrowSize = pathLengthFraction < maxArrowSize ? pathLengthFraction : maxArrowSize; QPointF arrowPoint1 = arrowPoint - QPointF(arrowSize * sin(angle - Pi / 2), arrowSize * cos(angle - Pi / 2)); QPointF arrowPoint2 = arrowPoint - QPointF(arrowSize * sin(angle + Pi / 3), arrowSize * cos(angle + Pi / 3)); QPointF arrowPoint3 = arrowPoint - QPointF(arrowSize * sin(angle + Pi - Pi / 3), arrowSize * cos(angle + Pi - Pi / 3)); m_arrowHeadPolygon.clear(); m_arrowHeadPolygon << arrowPoint1 << arrowPoint2 << arrowPoint3; // repaint the graphics item update(); }
void SCgAlphabet::paintPair(QPainter *painter, SCgPair *pair) { Q_ASSERT(pair != 0); QVector<QPointF> points = pair->points(); Q_ASSERT(points.size() > 1); static float arrowLength = 10.f; static float arrowWidth = LINE_FAT_WIDTH; if (pair->isOrient()) { static const QPointF arrowPoints[3] = {QPointF(-arrowWidth / 2.f, 0.f), QPointF(arrowWidth / 2.f, 0.f), QPointF(0.f, arrowLength)}; // draw arrow for orient pairs QLineF line(points[points.size() - 2], points.last()); double angle = ::atan2(line.dx(), line.dy()); painter->save(); painter->translate(line.p2()); painter->rotate(-angle * 180.f / M_PI); painter->translate(0.f, -arrowLength); painter->setBrush(QBrush(pair->color(), Qt::SolidPattern)); painter->setPen(Qt::NoPen); painter->drawConvexPolygon(arrowPoints, 3); painter->restore(); // correct last point points.last() -= QPointF((arrowLength) * ::sin(angle), (arrowLength) * ::cos(angle)); } // get type data SCgPosType posType = pair->posType(); SCgConstType constType = pair->constType(); SCgPermType permType = pair->permType(); painter->setBrush(Qt::NoBrush); QPen pen(pair->color()); pen.setCapStyle(Qt::FlatCap); pen.setJoinStyle(Qt::RoundJoin); // draw all cases if (pair->isAccessory()) { pen.setWidthF(LINE_THIN_WIDTH); QPen markPen = pen; if (constType == ConstUnknown && posType == PosUnknown) { painter->setPen(pen); painter->drawPolyline(&(points[0]), points.size()); markPen.setWidthF(LINE_COM_ACCESS_MARK_WIDTH); markPen.setDashPattern(msCommonAccessoryDashPattern); painter->setPen(markPen); painter->drawPolyline(&(points[0]), points.size()); }else { if (permType == Permanent && constType == Var) pen.setDashPattern(msPermVarAccesDashPattern); if (permType == Temporary) { if (constType == Const) pen.setDashPattern(msTempConstAccesDashPattern); else pen.setDashPattern(msTempVarAccesDashPattern); } painter->setPen(pen); painter->drawPolyline(&(points[0]), points.size()); // draw negative lines if (posType == Negative) { painter->setPen(markPen); QPainterPath path = pair->shapeNormal(); float length = path.length() - arrowLength - 3; int i = 0; qreal mult = 28.f; qreal offset = 22.f; qreal l = offset; while (l < length) { qreal perc = path.percentAtLength(l); painter->save(); painter->translate(path.pointAtPercent(perc)); painter->rotate(-path.angleAtPercent(perc)); painter->drawLine(0.f, -LINE_MARK_NEG_LENGTH, 0.f, LINE_MARK_NEG_LENGTH); painter->restore(); l = (++i) * mult + offset; } }else // draw fuzzy lines if (posType == Fuzzy) { painter->setPen(markPen); QPainterPath path = pair->shapeNormal(); float length = path.length() - arrowLength - 3; int i = 0; qreal mult = 28.f; qreal offset = 22.f; qreal l = offset; while (l < length) { qreal perc = path.percentAtLength(l); painter->save(); painter->translate(path.pointAtPercent(perc)); painter->rotate(-path.angleAtPercent(perc)); if (i % 2 == 0) painter->drawLine(0.f, -LINE_MARK_FUZ_LENGTH, 0.f, 0.f); else painter->drawLine(0.f, LINE_MARK_FUZ_LENGTH, 0.f, 0.f); painter->restore(); l = (++i) * mult + offset; } } } }else // draw binary pairs { pen.setWidthF(LINE_FAT_WIDTH); painter->setPen(pen); painter->drawPolyline(&(points[0]), points.size()); if (constType == Var) { pen.setWidthF(LINE_FATIN_WIDTH); pen.setDashPattern(msPermVarNoAccesDashPattern); pen.setDashOffset(20); pen.setColor(QColor(255, 255, 255)); painter->setPen(pen); painter->drawPolyline(&(points[0]), points.size()); }else { pen.setWidthF(LINE_FATIN_WIDTH); pen.setColor(Qt::white); painter->setPen(pen); painter->drawPolyline(&(points[0]), points.size()); if (constType == ConstUnknown) { pen.setWidthF(LINE_THIN_WIDTH); pen.setDashPattern(msPermVarAccesDashPattern); pen.setColor(pair->color()); painter->setPen(pen); painter->drawPolyline(&(points[0]), points.size()); } } } }
void PageItem_PathText::DrawObj_Item(ScPainter *p, QRectF cullingArea) { itemText.invalidateAll(); firstChar = 0; MaxChars = 0; int a; QString chstr, chstr2, chstr3; double dx; FPoint point = FPoint(0, 0); FPoint tangent = FPoint(0, 0); QColor tmp; CurX = m_textDistanceMargins.left(); QString cachedStroke = ""; QString cachedFill = ""; double cachedFillShade = -1; double cachedStrokeShade = -1; QString actStroke = ""; QString actFill = ""; double actFillShade = -1; double actStrokeShade = -1; QColor cachedFillQ; QColor cachedStrokeQ; if (!m_Doc->layerOutline(LayerID)) { if (PoShow) { p->setupPolygon(&PoLine, false); if (NamedLStyle.isEmpty()) { if ((!patternStrokeVal.isEmpty()) && (m_Doc->docPatterns.contains(patternStrokeVal))) { if (patternStrokePath) { QPainterPath guidePath = PoLine.toQPainterPath(false); DrawStrokePattern(p, guidePath); } else { p->setPattern(&m_Doc->docPatterns[patternStrokeVal], patternStrokeScaleX, patternStrokeScaleY, patternStrokeOffsetX, patternStrokeOffsetY, patternStrokeRotation, patternStrokeSkewX, patternStrokeSkewY, patternStrokeMirrorX, patternStrokeMirrorY); p->setStrokeMode(ScPainter::Pattern); p->strokePath(); } } else if (GrTypeStroke > 0) { if ((!gradientStrokeVal.isEmpty()) && (!m_Doc->docGradients.contains(gradientStrokeVal))) gradientStrokeVal = ""; if (!(gradientStrokeVal.isEmpty()) && (m_Doc->docGradients.contains(gradientStrokeVal))) stroke_gradient = m_Doc->docGradients[gradientStrokeVal]; if (stroke_gradient.Stops() < 2) // fall back to solid stroking if there are not enough colorstops in the gradient. { if (lineColor() != CommonStrings::None) { p->setBrush(strokeQColor); p->setStrokeMode(ScPainter::Solid); } else p->setStrokeMode(ScPainter::None); } else { p->setStrokeMode(ScPainter::Gradient); p->stroke_gradient = stroke_gradient; if (GrTypeStroke == 6) p->setGradient(VGradient::linear, FPoint(GrStrokeStartX, GrStrokeStartY), FPoint(GrStrokeEndX, GrStrokeEndY), FPoint(GrStrokeStartX, GrStrokeStartY), GrStrokeScale, GrStrokeSkew); else p->setGradient(VGradient::radial, FPoint(GrStrokeStartX, GrStrokeStartY), FPoint(GrStrokeEndX, GrStrokeEndY), FPoint(GrStrokeFocalX, GrStrokeFocalY), GrStrokeScale, GrStrokeSkew); } p->strokePath(); } else if (lineColor() != CommonStrings::None) { p->setStrokeMode(ScPainter::Solid); p->strokePath(); } } else { p->setStrokeMode(ScPainter::Solid); multiLine ml = m_Doc->MLineStyles[NamedLStyle]; QColor tmp; for (int it = ml.size()-1; it > -1; it--) { if (ml[it].Color != CommonStrings::None) // && (ml[it].Width != 0)) { SetQColor(&tmp, ml[it].Color, ml[it].Shade); p->setPen(tmp, ml[it].Width, static_cast<Qt::PenStyle>(ml[it].Dash), static_cast<Qt::PenCapStyle>(ml[it].LineEnd), static_cast<Qt::PenJoinStyle>(ml[it].LineJoin)); p->strokePath(); } } } } } double totalTextLen = 0.0; double totalCurveLen = 0.0; double extraOffset = 0.0; if (itemText.length() != 0) { CurX += itemText.charStyle(0).fontSize() * itemText.charStyle(0).tracking() / 10000.0; totalTextLen += itemText.charStyle(0).fontSize() * itemText.charStyle(0).tracking() / 10000.0; } itemRenderText.clear(); itemRenderText.setDoc(m_Doc); itemRenderText.setDefaultStyle(itemText.defaultStyle()); for (a = firstChar; a < itemText.length(); ++a) { CharStyle nstyle = itemText.charStyle(a); ParagraphStyle pstyle = itemText.paragraphStyle(a); chstr = itemText.text(a, 1); if ((chstr[0] == SpecialChars::OBJECT) && (itemText.hasObject(a))) { int pot = itemRenderText.length(); itemRenderText.insertObject(pot, itemText.object(a)->inlineCharID); } else { if (!(chstr[0] == SpecialChars::PARSEP || chstr[0] == SpecialChars::TAB || chstr[0] == SpecialChars::LINEBREAK)) chstr = ExpandToken(a); for (int cc = 0; cc < chstr.count(); cc++) { int pot = itemRenderText.length(); itemRenderText.insertChars(pot, chstr.mid(cc, 1)); itemRenderText.applyStyle(pot, pstyle); itemRenderText.applyCharStyle(pot, 1, nstyle); } } chstr.clear(); } textLayout.setStory(&itemRenderText); int spaceCount = 0; double wordExtra = 0; for (a = firstChar; a < itemRenderText.length(); ++a) { GlyphLayout* glyphs = itemRenderText.getGlyphs(a); chstr = itemRenderText.text(a, 1); if (chstr[0] == SpecialChars::PAGENUMBER || chstr[0] == SpecialChars::PARSEP || chstr[0] == SpecialChars::PAGECOUNT || chstr[0] == SpecialChars::TAB || chstr[0] == SpecialChars::LINEBREAK) continue; if (chstr[0] == SpecialChars::BLANK) spaceCount++; if (a < itemRenderText.length()-1) chstr += itemRenderText.text(a+1, 1); glyphs->yadvance = 0; layoutGlyphs(itemRenderText.charStyle(a), chstr, itemRenderText.flags(a), *glyphs); glyphs->shrink(); if (itemRenderText.hasObject(a)) totalTextLen += (itemRenderText.object(a)->width() + itemRenderText.object(a)->lineWidth()) * glyphs->scaleH; else totalTextLen += glyphs->wide()+itemRenderText.charStyle(a).fontSize() * itemRenderText.charStyle(a).tracking() / 10000.0; } for (int segs = 0; segs < PoLine.size()-3; segs += 4) { totalCurveLen += PoLine.lenPathSeg(segs); } if ((itemRenderText.paragraphStyle(0).alignment() != 0) && (totalCurveLen >= totalTextLen + m_textDistanceMargins.left())) { if (itemRenderText.paragraphStyle(0).alignment() == 2) { CurX = totalCurveLen - totalTextLen; CurX -= m_textDistanceMargins.left(); } if (itemRenderText.paragraphStyle(0).alignment() == 1) CurX = (totalCurveLen - totalTextLen) / 2.0; if (itemRenderText.paragraphStyle(0).alignment() == 3) { if (spaceCount != 0) { extraOffset = 0; wordExtra = (totalCurveLen - m_textDistanceMargins.left() - totalTextLen) / static_cast<double>(spaceCount); } else { extraOffset = (totalCurveLen - m_textDistanceMargins.left() - totalTextLen) / static_cast<double>(itemRenderText.length()); wordExtra = 0; } } if (itemRenderText.paragraphStyle(0).alignment() == 4) extraOffset = (totalCurveLen - m_textDistanceMargins.left() - totalTextLen) / static_cast<double>(itemRenderText.length()); } QPainterPath guidePath = PoLine.toQPainterPath(false); QList<QPainterPath> pathList = decomposePath(guidePath); QPainterPath currPath = pathList[0]; int currPathIndex = 0; for (a = firstChar; a < itemRenderText.length(); ++a) { CurY = 0; GlyphLayout* glyphs = itemRenderText.getGlyphs(a); PathData* pdata = & (textLayout.point(a)); chstr = itemRenderText.text(a,1); if (chstr[0] == SpecialChars::PAGENUMBER || chstr[0] == SpecialChars::PARSEP || chstr[0] == SpecialChars::PAGECOUNT || chstr[0] == SpecialChars::TAB || chstr[0] == SpecialChars::LINEBREAK) continue; if (a < itemRenderText.length()-1) chstr += itemRenderText.text(a+1, 1); glyphs->yadvance = 0; layoutGlyphs(itemRenderText.charStyle(a), chstr, itemRenderText.flags(a), *glyphs); glyphs->shrink(); // HACK if (itemRenderText.hasObject(a)) dx = (itemRenderText.object(a)->width() + itemRenderText.object(a)->lineWidth()) * glyphs->scaleH / 2.0; else dx = glyphs->wide() / 2.0; CurX += dx; double currPerc = currPath.percentAtLength(CurX); if (currPerc >= 0.9999999) { currPathIndex++; if (currPathIndex == pathList.count()) { MaxChars = a; break; } currPath = pathList[currPathIndex]; CurX = dx; currPerc = currPath.percentAtLength(CurX); } double currAngle = currPath.angleAtPercent(currPerc); if (currAngle <= 180.0) currAngle *= -1.0; else currAngle = 360.0 - currAngle; QPointF currPoint = currPath.pointAtPercent(currPerc); tangent = FPoint(cos(currAngle * M_PI / 180.0), sin(currAngle * M_PI / 180.0)); point = FPoint(currPoint.x(), currPoint.y()); glyphs->xoffset = 0; pdata->PtransX = point.x(); pdata->PtransY = point.y(); pdata->PRot = currAngle * M_PI / 180.0; pdata->PDx = dx; QTransform trafo = QTransform( 1, 0, 0, -1, -dx, 0 ); if (textPathFlipped) trafo *= QTransform(1, 0, 0, -1, 0, 0); if (textPathType == 0) trafo *= QTransform( tangent.x(), tangent.y(), tangent.y(), -tangent.x(), point.x(), point.y() ); // ID's Rainbow mode else if (textPathType == 1) trafo *= QTransform( 1, 0, 0, -1, point.x(), point.y() ); // ID's Stair Step mode else if (textPathType == 2) { double a = 1; if (tangent.x() < 0) a = -1; if (fabs(tangent.x()) > 0.1) trafo *= QTransform( a, (tangent.y() / tangent.x()) * a, 0, -1, point.x(), point.y() ); // ID's Skew mode else trafo *= QTransform( a, 4 * a, 0, -1, point.x(), point.y() ); } QTransform sca = p->worldMatrix(); trafo *= sca; p->save(); QTransform savWM = p->worldMatrix(); p->setWorldMatrix(trafo); if (!m_Doc->RePos) { actFill = itemRenderText.charStyle(a).fillColor(); actFillShade = itemRenderText.charStyle(a).fillShade(); if (actFill != CommonStrings::None) { p->setFillMode(ScPainter::Solid); if ((cachedFillShade != actFillShade) || (cachedFill != actFill)) { SetQColor(&tmp, actFill, actFillShade); p->setBrush(tmp); cachedFillQ = tmp; cachedFill = actFill; cachedFillShade = actFillShade; } else p->setBrush(cachedFillQ); } else p->setFillMode(ScPainter::None); actStroke = itemRenderText.charStyle(a).strokeColor(); actStrokeShade = itemRenderText.charStyle(a).strokeShade(); if (actStroke != CommonStrings::None) { if ((cachedStrokeShade != actStrokeShade) || (cachedStroke != actStroke)) { SetQColor(&tmp, actStroke, actStrokeShade); p->setPen(tmp, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); cachedStrokeQ = tmp; cachedStroke = actStroke; cachedStrokeShade = actStrokeShade; } else p->setPen(cachedStrokeQ, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); } p->translate(0.0, BaseOffs); if (itemRenderText.hasObject(a)) DrawObj_Embedded(p, cullingArea, itemRenderText.charStyle(a), itemRenderText.object(a)); else drawGlyphs(p, itemRenderText.charStyle(a), itemRenderText.flags(a), *glyphs); } p->setWorldMatrix(savWM); p->restore(); MaxChars = a+1; CurX -= dx; if (itemRenderText.hasObject(a)) CurX += (itemRenderText.object(a)->width() + itemRenderText.object(a)->lineWidth()) * glyphs->scaleH + extraOffset; else if (chstr[0] == SpecialChars::BLANK) CurX += glyphs->wide()+itemRenderText.charStyle(a).fontSize() * itemRenderText.charStyle(a).tracking() / 10000.0 + wordExtra + extraOffset; else CurX += glyphs->wide()+itemRenderText.charStyle(a).fontSize() *itemRenderText.charStyle(a).tracking() / 10000.0 + extraOffset; } }
void LabelScheme::Draw(MapTranslator *renderer, Feature *feature, QPainter *painter) { if(p_label_paint_func) { if(p_label_paint_func(painter, renderer, feature, this)) return; } if(!p_fieldName.isEmpty()) { QString name = feature->GetFieldValue(p_fieldName); if(p_position == QSimpleSpatial::FollowPath && feature->getScheme()->getShapeType() == QSimpleSpatial::PolyLine) { PolylineFeature *pf = static_cast<PolylineFeature *>(feature); if(pf) { const QVector<Points *> *array = pf->getPointsArray(); QPainterPath path; QPointF pathpoint; for(int i = 0;i < array->count();i ++) { Points *points = array->at(i); if(i > 0 && renderer->Coord2ScreenPoint(points->x[0],points->y[0]) != pathpoint) break; pathpoint = renderer->Coord2ScreenPoint(points->x[0],points->y[0]); path.moveTo(pathpoint); for(int j = 1;j < points->count;j ++) { pathpoint = renderer->Coord2ScreenPoint(points->x[j],points->y[j]); path.lineTo(pathpoint); } } painter->setPen(p_pen); painter->setFont(p_font); qreal pathLength = path.length(); qreal textLength = painter->fontMetrics().boundingRect(name).width() * 1.5; if(pathLength > textLength) { qreal length = (pathLength - textLength) / 2; for ( int i = 0; i < name.size(); i++ ) { qreal currentPos = length / pathLength; QPointF point = path.pointAtPercent(currentPos); QRect charRect = painter->fontMetrics().boundingRect(name[i]); charRect.translate(point.x(),point.y()); renderer->addLabelRect(charRect.marginsAdded(QMargins(5,5,5,5))); qreal angle = path.angleAtPercent(currentPos); angle = 360 - angle; painter->save(); painter->translate(point); painter->rotate(angle); painter->drawText(QPoint(p_offset.X, p_offset.Y),QString(name[i])); painter->restore(); length += charRect.width(); length += p_font.pointSize() / 2; } } } } else { QSimpleSpatial::SimplePoint labelPosition = feature->getLabelPosition(p_position); QSimpleSpatial::SimplePoint point = renderer->Coord2Screen(labelPosition); QRect rect = painter->fontMetrics().boundingRect(name); rect.moveTo(point.X - rect.width() / 2 + p_offset.X,point.Y - rect.height() / 2 + p_offset.Y); if(p_allowOverlap || !renderer->isLabelIntersects(rect)) { painter->setPen(p_pen); painter->setFont(p_font); painter->drawText(rect,Qt::AlignVCenter,name); if(!p_allowOverlap) renderer->addLabelRect(rect); } } } }