Exemplo n.º 1
0
/**
 * Zooms the view in a way that the given window is visible and fills the view.
 * The view is updated.
 */
void RGraphicsView::zoomTo(const RBox& window, int margin) {
    if (!window.isValid()) {
        return;
    }

    saveViewport();

    RVector f(RMAXDOUBLE, RMAXDOUBLE);
    double w = window.getWidth();
    double h = window.getHeight();

    if (w<1.0e-6 && h<1.0e-6) {
        return;
    }

    if (w>1.0e-6) {
        f.x = (getWidth() - 2 * margin) / w;
    }
    if (h>1.0e-6) {
        f.y = (getHeight() - 2 * margin) / h;
    }

    f.x = f.y = qMin(f.x, f.y);

    if (RSettings::getLimitZoomAndScroll() && f.x < 1.0e-9) {
        //f.x = f.y = 1.0;
        return;
    }

    setFactor(f.x);

    /*
    RBox viewWindow = mapToView(window);
    qDebug() << "viewWindow: " << viewWindow;
    RVector size = viewWindow.getSize();
    RVector f;

    if (size.x > 1.0e-6) {
        f.x = (getWidth() - 2 * margin) / size.x;
    } else {
        f.x = RMAXDOUBLE;
    }

    if (size.y > 1.0e-6) {
        f.y = (getHeight() - 2 * margin) / size.y;
    } else {
        f.y = RMAXDOUBLE;
    }

    f.x = f.y = qMin(f.x, f.y);

    if (f.x < 1.0e-6 || f.x == RMAXDOUBLE) {
        f.x = f.y = 1.0;
    }

    setFactor(factor * f.x);
    */

    centerToBox(window);
}
Exemplo n.º 2
0
/**
 * \return True if this vector is inside the given box, false otherwise.
 */
bool RVector::isInside(const RBox& b) const {
    RVector bMin = b.getMinimum();
    RVector bMax = b.getMaximum();

    return (x >= bMin.x && x <= bMax.x && y >= bMin.y && y <= bMax.y && z
            >= bMin.z && z <= bMax.z);
}
Exemplo n.º 3
0
void RGraphicsSceneQt::exportRay(const RRay& ray) {
    bool created = beginPath();

    Q_ASSERT(currentPainterPath.isValid());

    // find largest view box over all attached views:
    RBox box;
    QList<RGraphicsView*>::iterator it;
    for (it=views.begin(); it!=views.end(); it++) {
        RBox b = (*it)->getBox();
        box.growToIncludeBox(b);
    }

    // trim line to view box:
    RLine clippedLine = ray.getClippedLine(box);

    double offs = clippedLine.getStartPoint().getDistanceTo(ray.getBasePoint());
    if (RMath::isSameDirection(ray.getBasePoint().getAngleTo(clippedLine.getStartPoint()), ray.getDirection1())) {
        offs *= -1;
    }

    exportLine(clippedLine, offs);

    currentPainterPath.setAlwaysRegen(true);

    if (created) {
        endPath();
    }
}
Exemplo n.º 4
0
RPolyline RPasteOperation::getBoundary(double unitFactor) {
    RBox box = sourceDocument.getBoundingBox();
    RPolyline polyline = box.getPolyline2d();
    polyline.scale(scale * unitFactor);
    polyline.rotate(rotation);
    polyline.move(offset);
    return polyline;
}
Exemplo n.º 5
0
void ROrthoGrid::paintGridLines(const RVector& space, const RBox& box, bool meta) {
    if (!space.isValid()) {
        return;
    }

    // updates cache if necessary:
    getProjection();
    isIsometric();

    RVector min = box.getCorner1();
    RVector max = box.getCorner2();

    double deltaX = max.x - min.x;
    double deltaY = max.y - min.y;

    if (deltaX / space.x > 1e3 || deltaY / space.y > 1e3) {
        return;
    }

    double dx = deltaY / tan(M_PI/6);
    if (isometric) {
        min.x -= dx;
        max.x += dx;
    }
    int c;
    double x;
    for (x=min.x, c=0; x<max.x; x+=space.x, c++) {
        //int x2 = RMath::mround(x/space.x);
        //if (!isometric || c%2==0) {
        if (isometric) {
            if (projection==RS::IsoTop || projection==RS::IsoRight) {
                view.paintGridLine(RLine(RVector(x, min.y), RVector(x+dx, max.y)));
            }
            if (projection==RS::IsoTop || projection==RS::IsoLeft) {
                view.paintGridLine(RLine(RVector(x, min.y), RVector(x-dx, max.y)));
            }

            // vertical grid lines:
            if (projection==RS::IsoRight || projection==RS::IsoLeft) {
                view.paintGridLine(RLine(RVector(x, min.y), RVector(x, max.y)));
                view.paintGridLine(RLine(RVector(x-space.x/2, min.y), RVector(x-space.x/2, max.y)));
            }
        }
        else {
            view.paintGridLine(RLine(RVector(x, min.y), RVector(x, max.y)));
        }
        //}
    }

    // horizontal lines:
    if (!isometric) {
        for (double y=min.y; y<max.y; y+=space.y) {
            view.paintGridLine(RLine(RVector(min.x, y), RVector(max.x, y)));
        }
    }
}
Exemplo n.º 6
0
RBox RImageData::getBoundingBox(bool ignoreEmpty) const {
    Q_UNUSED(ignoreEmpty)

    RBox ret;
    QList<RLine> edges = getEdges();
    for (int i=0; i<edges.size(); i++) {
        ret.growToInclude(edges.at(i).getBoundingBox());
    }
    return ret;
}
Exemplo n.º 7
0
/**
 * \return The bounding box that contains this entity.
 */
RBox REntityData::getBoundingBox(bool ignoreEmpty) const {
    Q_UNUSED(ignoreEmpty)

    RBox ret;
    QList<QSharedPointer<RShape> > shapes = getShapes();
    for (int i=0; i<shapes.size(); i++) {
        RBox bb = shapes.at(i)->getBoundingBox();
        ret.growToInclude(bb);
    }
    return ret;
}
Exemplo n.º 8
0
bool RGraphicsView::zoomToSelection() {
    RDocument* document = getDocument();
    if (document == NULL) {
        return false;
    }
    RBox selectionBox = document->getSelectionBox();
    if (selectionBox.isValid() && (selectionBox.getWidth()>RS::PointTolerance || selectionBox.getHeight()>RS::PointTolerance)) {
        zoomTo(selectionBox, getMargin());
        return true;
    }
    return false;
}
Exemplo n.º 9
0
/**
 * \return The bounding box that contains this entity.
 */
RBox REntityData::getBoundingBox() const {
    RBox bb;
    QList<QSharedPointer<RShape> > shapes = getShapes();
    for (int i=0; i<shapes.size(); i++) {
        if (!bb.isValid()) {
            bb = shapes.at(i)->getBoundingBox();
        }
        else {
            bb.growToInclude(shapes.at(i)->getBoundingBox());
        }
    }
    return bb;
}
Exemplo n.º 10
0
RPolyline RPasteOperation::getBoundary(double unitFactor) {
    RBox box = sourceDocument.getBoundingBox();
    RPolyline polyline = box.getPolyline2d();
    if (flipHorizontal) {
        polyline.flipHorizontal();
    }
    if (flipVertical) {
        polyline.flipVertical();
    }
    polyline.scale(scale * unitFactor);
    polyline.rotate(getRotation());
    polyline.move(getOffset());
    return polyline;
}
Exemplo n.º 11
0
RBox RMemoryStorage::getSelectionBox() const {
    RBlock::Id currentBlock = getCurrentBlockId();
    RBox ret;
    QHash<RObject::Id, QSharedPointer<REntity> >::const_iterator it;
    for (it = entityMap.constBegin(); it != entityMap.constEnd(); ++it) {
        QSharedPointer<REntity> e = *it;
        if (!e.isNull() && !e->isUndone() && e->isSelected() &&
                e->getBlockId() == currentBlock) {

            ret.growToInclude(e->getBoundingBox());
        }
    }

    return ret;
}
Exemplo n.º 12
0
/**
 * Centers the view on the given \c box. The view is updated.
 *
 * \param box Box to move into the center of the drawing in model coordinates.
 */
void RGraphicsView::centerToBox(const RBox& box) {
    RVector center = box.getCenter();
    RVector boxCenter = mapFromView(RVector(getWidth(), getHeight())/2.0);
    setOffset(offset - (center - boxCenter));
    //regenerate();
    //viewportChangeEvent();
}
Exemplo n.º 13
0
RBox RPolyline::getBoundingBox() const {
    RBox ret;

    if (countVertices()==1) {
        ret = RBox(vertices.at(0), vertices.at(0));
    }

    QList<QSharedPointer<RShape> > sub = getExploded();
    QList<QSharedPointer<RShape> >::iterator it;
    for (it=sub.begin(); it!=sub.end(); ++it) {
        RBox bb = (*it)->getBoundingBox();
        ret.growToInclude(bb);
    }

    return ret;
}
Exemplo n.º 14
0
/**
 * Exports the surfaces of the given box.
 * This is a convenience function that exports 12 triangles but may
 * also be re-implemented to do something else.
 */
void RExporter::exportBox(const RBox& box) {
    QList<RTriangle> triangles = box.getTriangles();
    QList<RTriangle>::iterator it;
    for (it=triangles.begin(); it!=triangles.end(); ++it) {
        exportTriangle(*it);
    }
}
Exemplo n.º 15
0
void RGraphicsView::autoZoom(int margin, bool ignoreEmpty) {
    RDocument* document = getDocument();
    if (document == NULL) {
        return;
    }
    RBox bb = document->getBoundingBox(true, ignoreEmpty);

    // TODO: optional:
    bb.growXY(
        RUnit::convert(
            document->getMaxLineweight()/100.0/2,
            RS::Millimeter,
            document->getUnit()
        )
    );

    zoomTo(bb, (margin!=-1 ? margin : getMargin()));
}
Exemplo n.º 16
0
/**
 * Called whenever the current viewport changed through panning or
 * zooming. Updates the scroll bars, rulers, etc.
 */
void REventHandler::viewportChanged() {
    if (hsb==NULL || vsb==NULL) {
        return;
    }

    hsb->blockSignals(true);
    vsb->blockSignals(true);

    RDocument& document = documentInterface->getDocument();

    RBox box = document.getBoundingBox(true, true);
    double min = box.getMinimum().x * graphicsView->getFactor() - 800;
    double max = box.getMaximum().x * graphicsView->getFactor() - graphicsView->getWidth() + 800;
    hsb->setRange(min, max);
    hsb->setPageStep(graphicsView->getWidth());
    hsb->setValue(-graphicsView->getOffset().x * graphicsView->getFactor());

    min = graphicsView->getHeight() - box.getMaximum().y * graphicsView->getFactor() - 800;
    max = 800 - box.getMinimum().y * graphicsView->getFactor();
    vsb->setRange(min, max);
    vsb->setPageStep(graphicsView->getHeight());
    vsb->setValue(graphicsView->getOffset().y * graphicsView->getFactor());

    hsb->blockSignals(false);
    vsb->blockSignals(false);

    // rulers
    if (hruler!=NULL) {
        hruler->updateViewport();
    }
    if (vruler!=NULL) {
        vruler->updateViewport();
    }

    // grid info label
    QLabel* infoLabel = widget->findChild<QLabel*>("InfoLabel");
    RGrid* grid = graphicsView->getGrid();
    if (grid!=NULL) {
        infoLabel->setText(grid->getInfoText());
    }
}
Exemplo n.º 17
0
/**
 * \return List of bezier spline segments which together represent this curve.
 */
QList<RSpline> RSpline::getBezierSegments(const RBox& queryBox) const {
    // spline is a single bezier segment:
    if (countControlPoints()==getDegree()+1) {
        return QList<RSpline>() << *this;
    }

    updateInternal();

    QList<RSpline> ret;
#ifndef R_NO_OPENNURBS
    ON_NurbsCurve* dup = dynamic_cast<ON_NurbsCurve*>(curve.DuplicateCurve());
    if (dup==NULL) {
        return ret;
    }

    dup->MakePiecewiseBezier();
    for (int i=0; i<=dup->CVCount() - dup->Order(); ++i) {
        ON_BezierCurve bc;
        if (!dup->ConvertSpanToBezier(i, bc)) {
            continue;
        }

        QList<RVector> ctrlPts;
        for (int cpi=0; cpi<bc.CVCount(); cpi++) {
            ON_3dPoint onp;
            bc.GetCV(cpi, onp);
            ctrlPts.append(RVector(onp.x, onp.y, onp.z));
        }
        RSpline bezierSegment(ctrlPts, degree);

        if (!queryBox.isValid() || queryBox.intersects(bezierSegment.getBoundingBox())) {
            ret.append(bezierSegment);
        }
    }
    delete dup;
 #endif

    return ret;
}
Exemplo n.º 18
0
/**
 * Maps the given \c box (e.g. a 3d bounding box) to a 2d box
 * in view coordinates (pixels).
 */
RBox RGraphicsView::mapToView(const RBox& box) const {
    QList<RVector> boxCorners = box.getCorners();

    RVector minView(RMAXDOUBLE, RMAXDOUBLE, RMAXDOUBLE);
    RVector maxView(RMINDOUBLE, RMINDOUBLE, RMINDOUBLE);
    RVector corner;

    for (int i=0; i<8; i++) {
        corner = mapToView(boxCorners[i]);
        minView = RVector::getMinimum(corner, minView);
        maxView = RVector::getMaximum(corner, maxView);
    }

    return RBox(minView, maxView);
}
Exemplo n.º 19
0
void ROrthoGrid::paintGridPoints(const RVector& space, const RBox& box) {
    if (!space.isValid()) {
        return;
    }

    RVector min = box.getCorner1();
    RVector max = box.getCorner2();

    if ((max.x - min.x) / space.x > 1e3 || (max.y - min.y) / space.y > 1e3) {
        return;
    }

    RVector gridPointUcs;
    int x, y;
    for (gridPointUcs.x = min.x; gridPointUcs.x < max.x; gridPointUcs.x += space.x) {
        x = RMath::mround(gridPointUcs.x/space.x);
        for (gridPointUcs.y = min.y; gridPointUcs.y < max.y; gridPointUcs.y += space.y) {
            y = RMath::mround(gridPointUcs.y/space.y);
            if (!isometric || (x+y)%2==0) {
                view.paintGridPoint(gridPointUcs);
            }
        }
    }
}
Exemplo n.º 20
0
QList<RVector> RSnapTangential::snapEntity(
        QSharedPointer<REntity> entity,
        const RVector& point,
        const RBox& queryBox,
        RGraphicsView& view) {

    QList<RVector> ret;

    RDocumentInterface* di = view.getDocumentInterface();
    if (di==NULL) {
        return ret;
    }

    QSharedPointer<RShape> shape = entity->getClosestShape(point, queryBox.getWidth()/2, true);
    if (shape.isNull()) {
        return ret;
    }

    QSharedPointer<RCircle> circle = shape.dynamicCast<RCircle>();
    if (!circle.isNull()) {
        QList<RLine> lines = circle->getTangents(di->getLastPosition());
        for (int i=0; i<lines.length(); i++) {
            ret.append(lines[i].getEndPoint());
        }
    }

    QSharedPointer<RArc> arc = shape.dynamicCast<RArc>();
    if (!arc.isNull()) {
        QList<RLine> lines = arc->getTangents(di->getLastPosition());
        for (int i=0; i<lines.length(); i++) {
            ret.append(lines[i].getEndPoint());
        }
    }

    QSharedPointer<REllipse> ellipse = shape.dynamicCast<REllipse>();
    if (!ellipse.isNull()) {
        QList<RLine> lines = ellipse->getTangents(di->getLastPosition());
        for (int i=0; i<lines.length(); i++) {
            ret.append(lines[i].getEndPoint());
        }
    }

    return ret;
}
Exemplo n.º 21
0
QList<RVector> RSnapPerpendicular::snapEntity(
        QSharedPointer<REntity> entity,
        const RVector& point,
        const RBox& queryBox,
        RGraphicsView& view) {

    QList<RVector> ret;

    RDocumentInterface* di = view.getDocumentInterface();
    if (di==NULL) {
        return ret;
    }

    QSharedPointer<RShape> shape = entity->getClosestShape(point, queryBox.getWidth()/2, true);
    if (shape.isNull()) {
        return ret;
    }

    ret.append(shape->getClosestPointOnShape(di->getLastPosition(), false));

    return ret;
}
Exemplo n.º 22
0
/**
 * \return A polygon that contains this entity.
 * Default implementation returns a polygon around the bounding box.
 */
RPolyline REntityData::getHull(double offset) const {
    RBox bb = getBoundingBox();
    bb.grow(offset);
    return bb.getPolyline2d();
}
Exemplo n.º 23
0
bool RShape::stretch(const RBox& area, const RVector& offset) {
    return stretch(area.getPolyline2d(), offset);
}
Exemplo n.º 24
0
/**
 * Renders the text data into painter paths.
 */
void RTextRenderer::render() {
    boundingBox = RBox();
    painterPaths.clear();
    richText = "";

    QString text = textData.getEscapedText();
    //RVector position = textData.getPosition();
    RVector position = textData.getAlignmentPoint();
    double textHeight = textData.getTextHeight();
    RS::VAlign verticalAlignment = textData.getVAlign();
    RS::HAlign horizontalAlignment = textData.getHAlign();
    double lineSpacingFactor = textData.getLineSpacingFactor();
    QString fontName = textData.getFontName();
    bool bold = textData.isBold();
    bool italic = textData.isItalic();
    double angle = textData.getAngle();
    //RColor color = textData.getColor(true);

    // split up text where separation is required due to line feed,
    // or any type of height change (\P, \H[0-9]*.?[0-9]+;, \S*/*;)

    // split up text at every formatting change:
    QRegExp regExpAll(rxAll);
    QStringList literals = text.split(regExpAll);

    // collect formatting change information for every literal:
    QStringList formattings;
    int pos = 0;
    while ((pos = regExpAll.indexIn(text, pos)) != -1) {
        formattings << regExpAll.cap(1);
        pos += regExpAll.matchedLength();
    }

    // x position in real units:
    double xCursor = 0.0;
    // y position for next text line:
    double yCursor = 0.0;
    // painter paths for current text line:
    QList<RPainterPath> linePaths;
    // max ascent of current text line:
    double maxAscent = 0.0;
    // max descent of current line:
    double minDescent = 0.0;
    // max descent of _previous_ line:
    double minDescentPrevious = 0.0;
    // true for the first block of the current line:
    bool firstBlockInLine = true;
    // current line has leading spaces:
    bool leadingSpaces = false;
    // current line has trailing spaces:
    bool trailingSpaces = false;
    // text has leading empty lines:
    bool leadingEmptyLines = false;
    // text has trailing empty lines:
    bool trailingEmptyLines = false;
    int lineCounter = 0;
    QString textBlock;
    QList<QTextLayout::FormatRange> formats;

    bool blockChangedHeightOrFont = false;

    // implicit top level format block:
    QTextCharFormat f;
    f.setForeground(QBrush(QColor()));
    currentFormat.push(f);
    QTextLayout::FormatRange fr;
    fr.start = 0;
    fr.length = 0;
    fr.format = currentFormat.top();
    formats.append(fr);
    blockHeight.push(textHeight);
    blockFont.push(fontName);
    blockBold.push(bold);
    blockItalic.push(italic);
    useCadFont.push(RFontList::isCadFont(fontName));
    openTags.push(QStringList());

    width = 0.0;
    height = 0.0;

    // iterate through all text blocks:
    for (int i=0; i<literals.size(); ++i) {

        // the literal text, e.g. "ABC":
        QString literal = literals.at(i);

        // the formatting _after_ the text, e.g. "\C1;"
        QString formatting;
        if (i<formattings.size()) {
            formatting = formattings.at(i);
        }

//        qDebug() << "block: " << i;
//        qDebug() << "  literal: " << literal;
//        qDebug() << "  literal length: " << literal.length();
//        qDebug() << "  formatting: " << formatting;
//        qDebug() << "  font: " << blockFont.top();
//        qDebug() << "  height: " << blockHeight.top();
//        qDebug() << "  cad font: " << useCadFont.top();
//        qDebug() << "  xCursor: " << xCursor;

        // handle literal:
        textBlock.append(literal);

        if (firstBlockInLine) {
            if (!literal.isEmpty()) {
                if (literal.at(0).isSpace()) {
                    leadingSpaces = true;
                }
            }
            else {
                if (formatting=="\\~") {
                    leadingSpaces = true;
                }
            }
            firstBlockInLine = false;
        }

        bool lineFeed = false;
        bool paragraphFeed = false;
        bool heightChange = false;
        bool stackedText = false;
        bool fontChange = false;
        bool colorChange = false;
        bool blockEnd = false;

        // detect formatting that ends the current text block:
        if (!formatting.isEmpty()) {
            fontChange = QRegExp(rxFontChangeTtf).exactMatch(formatting) ||
                QRegExp(rxFontChangeCad).exactMatch(formatting);
            colorChange = QRegExp(rxColorChangeCustom).exactMatch(formatting) ||
                QRegExp(rxColorChangeIndex).exactMatch(formatting);
            heightChange = QRegExp(rxHeightChange).exactMatch(formatting);
            stackedText = QRegExp(rxStackedText).exactMatch(formatting);
            lineFeed = QRegExp(rxLineFeed).exactMatch(formatting);
            paragraphFeed = QRegExp(rxParagraphFeed).exactMatch(formatting);
            blockEnd = QRegExp(rxEndBlock).exactMatch(formatting);
        }

        bool start = (i==0);
        bool end = (i==literals.size()-1);

        // first line is empty:
        if (textBlock.trimmed().isEmpty() && (lineFeed || paragraphFeed || end)) {
            if (start) {
                leadingEmptyLines = true;
            }
            else if (end) {
                trailingEmptyLines = true;
            }
        }

        // reached a new text block that needs to be rendered separately
        // due to line feed, height change, font change, ...:
        if (target==RichText ||
            lineFeed || paragraphFeed || heightChange || stackedText ||
            fontChange || colorChange || end
            || (blockEnd && blockChangedHeightOrFont)) {

            // render block _before_ format change that requires new block:
            if (textBlock!="") {
                // fix format lengths to match up. each format stops where
                // the next one starts. formatting that is carried over is set
                // again for the new format.
                for (int i=0; i<formats.size(); i++) {
                    int nextStart;
                    if (i<formats.size()-1) {
                        nextStart = formats[i+1].start;
                    }
                    else {
                        nextStart = textBlock.length();
                    }
                    formats[i].length = nextStart - formats[i].start;
                }

                if (target==RichText) {
                    richText += getRichTextForBlock(
                                   textBlock, formats);
                }

                if (target==PainterPaths) {
                    double horizontalAdvance = 0.0;
                    double horizontalAdvanceNoSpacing = 0.0;
                    double ascent = 0.0;
                    double descent = 0.0;
                    QList<RPainterPath> paths;

                    // get painter paths for current text block at height 1.0:
                    paths = getPainterPathsForBlock(
                                textBlock, formats,
                                horizontalAdvance,
                                horizontalAdvanceNoSpacing,
                                ascent, descent);

                    // transform to scale text from 1.0 to current text height:
                    QTransform sizeTransform;
                    sizeTransform.scale(blockHeight.top(), blockHeight.top());

                    // transform for current block due to xCursor position:
                    QTransform blockTransform;
                    blockTransform.translate(xCursor, 0);

                    // combine transforms for current text block:
                    QTransform allTransforms = sizeTransform;
                    allTransforms *= blockTransform;

                    maxAscent = qMax(maxAscent, ascent * blockHeight.top());
                    minDescent = qMin(minDescent, descent * blockHeight.top());

                    // transform paths of current block and append to paths
                    // of current text line:
                    for (int i=0; i<paths.size(); ++i) {
                        RPainterPath p = paths.at(i);
                        p.transform(allTransforms);
                        linePaths.append(p);
                    }

                    xCursor += horizontalAdvance * blockHeight.top();
                }
            }

            // empty text, might be line feed, we need ascent, descent anyway:
            else if (lineFeed || paragraphFeed || end) {
                if (target==PainterPaths) {
                    double horizontalAdvance = 0.0;
                    double horizontalAdvanceNoSpacing = 0.0;
                    double ascent = 0.0;
                    double descent = 0.0;

                    // get painter paths for current text block at height 1.0:
                    getPainterPathsForBlock(
                                "A", QList<QTextLayout::FormatRange>(),
                                horizontalAdvance,
                                horizontalAdvanceNoSpacing,
                                ascent, descent);

                    maxAscent = qMax(maxAscent, ascent * blockHeight.top());
                    minDescent = qMin(minDescent, descent * blockHeight.top());
                }
            }

            // handle stacked text:
            if (stackedText) {
                QRegExp reg;
                reg.setPattern(rxStackedText);
                reg.exactMatch(formatting);

                if (target==PainterPaths) {
                    double horizontalAdvance[2];
                    horizontalAdvance[0] = 0.0;
                    horizontalAdvance[1] = 0.0;
                    double horizontalAdvanceNoSpacing[2];
                    horizontalAdvanceNoSpacing[0] = 0.0;
                    horizontalAdvanceNoSpacing[1] = 0.0;
                    double heightFactor = 0.4;

                    // s==0: superscript, s==1: subscript:
                    for (int s=0; s<=1; ++s) {
                        QString script = reg.cap(s+1);

                        QList<RPainterPath> paths;

                        double ascent = 0.0;
                        double descent = 0.0;

                        QList<QTextLayout::FormatRange> localFormats;

                        QTextLayout::FormatRange fr;
                        fr.start = 0;
                        fr.length = script.length();
                        fr.format = currentFormat.top();
                        localFormats.append(fr);

                        // get painter paths for superscript at height 1.0:
                        paths = getPainterPathsForBlock(
                                    script, localFormats,
                                    horizontalAdvance[s],
                                    horizontalAdvanceNoSpacing[s],
                                    ascent, descent);

                        if (s==0) {
                            maxAscent = qMax(maxAscent, ascent * blockHeight.top() * heightFactor + blockHeight.top()*(1.0-heightFactor));
                        }
                        else {
                            minDescent = qMin(minDescent, descent * blockHeight.top() * heightFactor);
                        }

                        // transform to scale text from 1.0 to current text height * 0.4:
                        QTransform sizeTransform;
                        sizeTransform.scale(blockHeight.top()*heightFactor, blockHeight.top()*heightFactor);

                        // move top text more to the right for italic texts:
                        double xOffset = 0.0;
                        if (s==0 && blockItalic.top()==true) {
                            double y = blockHeight.top()*(1.0-heightFactor);
                            // assume italic means roughly 12 degrees:
                            xOffset = tan(RMath::deg2rad(12)) * y;
                        }

                        // transform for current block due to xCursor position
                        // and top or bottom text position:
                        QTransform blockTransform;
                        blockTransform.translate(xCursor + xOffset,
                                                 s==0 ? blockHeight.top()*(1.0-heightFactor) : 0.0);

                        horizontalAdvance[s] += xOffset / (blockHeight.top() * heightFactor);

                        // combine transforms for current text block:
                        QTransform allTransforms = sizeTransform;
                        allTransforms *= blockTransform;

                        // transform paths of current block and append to paths
                        // of current text line:
                        for (int i=0; i<paths.size(); ++i) {
                            RPainterPath p = paths.at(i);
                            p.transform(allTransforms);
                            linePaths.append(p);
                        }
                    }

                    xCursor += qMax(horizontalAdvance[0], horizontalAdvance[1]) * blockHeight.top() * heightFactor;
                }

                if (target==RichText) {
                    QString super = reg.cap(1);
                    QString sub = reg.cap(2);
                    if (!super.isEmpty()) {
                        richText += QString("<span style=\"vertical-align:super;\">%1</span>").arg(super);
                    }
                    if (!sub.isEmpty()) {
                        richText += QString("<span style=\"vertical-align:sub;\">%1</span>").arg(sub);
                    }
                }
            }

            // prepare for next text block:
            if (lineFeed || paragraphFeed || end) {
                if (!textBlock.isEmpty()) {
                    if (textBlock.at(textBlock.length()-1).isSpace()) {
                        trailingSpaces = true;
                    }
                }
//                else {
//                    if (formatting=="\\~") {
//                        trailingSpaces = true;
//                    }
//                }
            }

            textBlock = "";
            formats.clear();
            QTextLayout::FormatRange fr;
            fr.start = 0;
            fr.length = 0;
            fr.format = currentFormat.top();
            formats.append(fr);

            // handle text line.
            // add all painter paths of the current line to result set of
            // painter paths. apply line feed transformations.
            if (lineFeed || paragraphFeed || end) {
//                qDebug() << "lineFeed: adding text line:";
//                qDebug() << "  maxAscent: " << maxAscent;
//                qDebug() << "  minDescent: " << minDescent;
//                qDebug() << "  minDescentPrevious: " << minDescentPrevious;
//                qDebug() << "got line feed or end";
//                qDebug() << "  trailingSpaces: " << trailingSpaces;

                if (target==RichText) {
                    if (lineFeed || paragraphFeed) {
                        richText += "<br/>";
                    }
                }

                if (lineCounter!=0) {
                    yCursor += (minDescentPrevious - maxAscent) * lineSpacingFactor;
                }

                // calculate line bounding box for alignment without spaces at borders:
                RBox lineBoundingBox;
                for (int i=0; i<linePaths.size(); ++i) {
                    RPainterPath p = linePaths.at(i);
                    lineBoundingBox.growToInclude(p.getBoundingBox());
                }

                double featureSize = lineBoundingBox.getHeight();

                QTransform lineTransform;

                switch (horizontalAlignment) {
                case RS::HAlignAlign:
                case RS::HAlignFit:
                case RS::HAlignLeft:
                    if (!leadingSpaces) {
                        // move completely to the left (left border is 0.0):
                        lineTransform.translate(
                                    -lineBoundingBox.getMinimum().x,
                                    yCursor);
                    }
                    else {
                        lineTransform.translate(0, yCursor);
                    }
                    break;
                case RS::HAlignMid:
                case RS::HAlignCenter:
                    if (!leadingSpaces && !trailingSpaces) {
                        lineTransform.translate(
                                    -(lineBoundingBox.getMinimum().x +
                                      lineBoundingBox.getMaximum().x)/2.0,
                                    yCursor);
                    }
                    else {
                        lineTransform.translate(-xCursor/2.0, yCursor);
                    }
                    break;
                case RS::HAlignRight:
                    if (!trailingSpaces) {
                        lineTransform.translate(-lineBoundingBox.getMaximum().x, yCursor);
                    }
                    else {
                        lineTransform.translate(-xCursor, yCursor);
                    }
                    break;
                }

                width = qMax(width, lineBoundingBox.getMaximum().x - qMin(0.0, lineBoundingBox.getMinimum().x));

                // add current text line to result set:
                QPen pen;
                for (int i=0; i<linePaths.size(); ++i) {
                    RPainterPath p = linePaths[i];
                    if (i==0) {
                        pen = p.getPen();
                        if (pen.style()==Qt::NoPen) {
                           pen = QPen(p.getBrush().color());
                        }
                    }
                    p.transform(lineTransform);
                    p.setFeatureSize(featureSize);
                    painterPaths.append(p);
                    boundingBox.growToInclude(p.getBoundingBox());
                }

                RPainterPath bbPath;
                bbPath.addBox(lineBoundingBox);
                bbPath.transform(lineTransform);
                bbPath.setFeatureSize(-featureSize);
                bbPath.setPen(pen);
                painterPaths.append(bbPath);

                lineCounter++;
                xCursor = 0.0;
                maxAscent = 0.0;
                minDescentPrevious = minDescent;
                minDescent = 0.0;
                linePaths.clear();
                firstBlockInLine = true;
                leadingSpaces = false;
                trailingSpaces = false;
            }
        }

        // handle formatting after text block, that applies either
        // to the next text block(s) or the rest of the current text block:
        if (formatting.isEmpty()) {
            continue;
        }

        QRegExp reg;

        // unicode:
        reg.setPattern(rxUnicode);
        if (reg.exactMatch(formatting)) {
            textBlock += QChar(reg.cap(1).toInt(0, 16));
            continue;
        }

        // curly braket open:
        reg.setPattern(rxCurlyOpen);
        if (reg.exactMatch(formatting)) {
            textBlock += "{";
            continue;
        }

        // curly braket close:
        reg.setPattern(rxCurlyClose);
        if (reg.exactMatch(formatting)) {
            textBlock += "}";
            continue;
        }

        // degree:
        reg.setPattern(rxDegree);
        if (reg.exactMatch(formatting)) {
            textBlock += chDegree;
            continue;
        }

        // plus/minus:
        reg.setPattern(rxPlusMinus);
        if (reg.exactMatch(formatting)) {
            textBlock += chPlusMinus;
            continue;
        }

        // diameter:
        reg.setPattern(rxDiameter);
        if (reg.exactMatch(formatting)) {
            textBlock += chDiameter;
            continue;
        }

        // backslash:
        reg.setPattern(rxBackslash);
        if (reg.exactMatch(formatting)) {
            textBlock += "\\";
            continue;
        }

        // non-breaking space:
        reg.setPattern(rxNonBreakingSpace);
        if (reg.exactMatch(formatting)) {
            if (target==PainterPaths) {
                textBlock += QChar(Qt::Key_nobreakspace);
            }
            if (target==RichText) {
                textBlock += "&nbsp;";
            }
            continue;
        }

        // font change (TTF):
        reg.setPattern(rxFontChangeTtf);
        if (reg.exactMatch(formatting)) {
            blockFont.top() = reg.cap(1);
            blockBold.top() = (reg.cap(2).toInt()!=0);
            blockItalic.top() = (reg.cap(3).toInt()!=0);
            useCadFont.top() = false;
            blockChangedHeightOrFont = true;

            if (target==RichText) {
                QString style;
                style += QString("font-family:%1;").arg(blockFont.top());
                style += QString("font-weight:%1;").arg(blockBold.top() ? "bold" : "normal");
                style += QString("font-style:%1;").arg(blockItalic.top() ? "italic" : "normal");
                richText += QString("<span style=\"%1\">").arg(style);
                openTags.top().append("span");
            }
            continue;
        }

        // font change (CAD):
        reg.setPattern(rxFontChangeCad);
        if (reg.exactMatch(formatting)) {
            blockFont.top() = reg.cap(1);
            useCadFont.top() = true;
            if (xCursor>RS::PointTolerance) {
                RFont* f = RFontList::get(blockFont.top());
                if (f!=NULL && f->isValid()) {
                    xCursor += f->getLetterSpacing() / 9.0;
                }
            }
            blockChangedHeightOrFont = true;

            if (target==RichText) {
                QString style;
                style += QString("font-family:%1;").arg(blockFont.top());
                richText += QString("<span style=\"%1\">").arg(style);
                openTags.top().append("span");
            }
            continue;
        }

        // height change:
        reg.setPattern(rxHeightChange);
        if (reg.exactMatch(formatting)) {
            bool factor = reg.cap(2)=="x";

            if (factor) {
                blockHeight.top() *= reg.cap(1).toDouble();
            }
            else {
                blockHeight.top() = reg.cap(1).toDouble();
            }
            blockChangedHeightOrFont = true;

            if (target==RichText) {
                QString style;
                style += QString("font-size:%1pt;").arg(blockHeight.top() * fontHeightFactor);
                richText += QString("<span style=\"%1\">").arg(style);
                openTags.top().append("span");
            }
            continue;
        }

        QTextLayout::FormatRange fr;
        fr.start = textBlock.length();
        fr.length = 0;

        // start format block:
        reg.setPattern(rxBeginBlock);
        if (reg.exactMatch(formatting)) {
            currentFormat.push(currentFormat.top());
            blockFont.push(blockFont.top());
            blockBold.push(blockBold.top());
            blockItalic.push(blockItalic.top());
            blockHeight.push(blockHeight.top());
            useCadFont.push(useCadFont.top());
            if (target==RichText) {
                openTags.push(QStringList());
            }
            blockChangedHeightOrFont = false;
            continue;
        }

        // end format block:
        reg.setPattern(rxEndBlock);
        if (reg.exactMatch(formatting)) {
            currentFormat.pop();
            fr.format = currentFormat.top();
            formats.append(fr);
            blockFont.pop();
            blockBold.pop();
            blockItalic.pop();
            blockHeight.pop();
            useCadFont.pop();
            blockChangedHeightOrFont = false;

            if (target==RichText) {
                // close all tags that were opened in this block:
                for (int i=openTags.top().size()-1; i>=0; --i) {
                    QString tag = openTags.top().at(i);
                    richText += QString("</%1>").arg(tag);
                }
                openTags.pop();
            }

            continue;
        }

        // color change (indexed):
        reg.setPattern(rxColorChangeIndex);
        if (reg.exactMatch(formatting)) {
            RColor blockColor = RColor::createFromCadIndex(reg.cap(1));
            if (blockColor.isByLayer()) {
                currentFormat.top().setForeground(RColor::CompatByLayer);
            } else if (blockColor.isByBlock()) {
                currentFormat.top().setForeground(RColor::CompatByBlock);
            }
            else {
                currentFormat.top().setForeground(blockColor);
            }
            fr.format = currentFormat.top();
            formats.append(fr);

            if (target==RichText) {
                QString style;
                style += QString("color:%1;").arg(blockColor.name());
                richText += QString("<span style=\"%1\">").arg(style);
                openTags.top().append("span");
            }
            continue;
        }

        // color change (custom):
        reg.setPattern(rxColorChangeCustom);
        if (reg.exactMatch(formatting)) {
            RColor blockColor = RColor::createFromCadCustom(reg.cap(1));
            currentFormat.top().setForeground(blockColor);
            fr.format = currentFormat.top();
            formats.append(fr);

            if (target==RichText) {
                QString style;
                style += QString("color:%1;").arg(blockColor.name());
                richText += QString("<span style=\"%1\">").arg(style);
                openTags.top().append("span");
            }
            continue;
        }
    }

    if (target==PainterPaths) {
        // at this point, the text is at 0/0 with the base line of the
        // first text line at y==0

        // vertical alignment:
        double topLine = qMax(textHeight, boundingBox.getMaximum().y);
        double bottomLine = qMin(0.0, boundingBox.getMinimum().y);

        QTransform globalTransform;
        globalTransform.translate(position.x, position.y);
        globalTransform.rotate(RMath::rad2deg(angle));
        switch (verticalAlignment) {
        case RS::VAlignTop:
            //if (!leadingEmptyLines) {
                globalTransform.translate(0.0, -topLine);
            //}
            break;
        case RS::VAlignMiddle:
            if (leadingEmptyLines || trailingEmptyLines) {
                globalTransform.translate(0.0, -(yCursor+textHeight)/2.0);
            }
            else {
                globalTransform.translate(0.0, -(bottomLine + topLine) / 2.0);
            }
            break;
        case RS::VAlignBottom:
        case RS::VAlignBase:
            if (trailingEmptyLines) {
                globalTransform.translate(0.0, -yCursor);
            }
            else {
                globalTransform.translate(0.0, -bottomLine);
            }
            break;
        }

        height = boundingBox.getHeight();

        // apply global transform for position, angle and vertical alignment:
        boundingBox = RBox();
        for (int i=0; i<painterPaths.size(); ++i) {
            painterPaths[i].transform(globalTransform);
            boundingBox.growToInclude(painterPaths[i].getBoundingBox());
        }
    }

    if (target==RichText) {
        // close all tags that were opened:
        for (int i=openTags.top().size()-1; i>=0; --i) {
            QString tag = openTags.top().at(i);
            richText += QString("</%1>").arg(tag);
        }
    }
}
Exemplo n.º 25
0
RBox RMemoryStorage::getBoundingBox(bool ignoreHiddenLayers, bool ignoreEmpty) const {
    if (!boundingBoxChanged) {
        return boundingBox[ignoreHiddenLayers][ignoreEmpty];
    }

    RBlock::Id currentBlockId = getCurrentBlockId();
    boundingBox[0][0] = RBox();
    boundingBox[0][1] = RBox();
    boundingBox[1][0] = RBox();
    boundingBox[1][1] = RBox();
    maxLineweight = RLineweight::Weight000;

    QHash<RObject::Id, QSharedPointer<REntity> >::const_iterator it;
    for (it = entityMap.constBegin(); it != entityMap.constEnd(); ++it) {
        QSharedPointer<REntity> e = *it;
        if (e.isNull() || e->isUndone()) {
            continue;
        }

        //if (ignoreHiddenLayers) {
        bool layerHidden = false;
            QSharedPointer<RLayer> layer = queryLayerDirect(e->getLayerId());
            if (layer.isNull() || layer->isFrozen()) {
                layerHidden = true;
            }
        //}

        if (e->getBlockId() == currentBlockId) {
            //bb.growToInclude(e->getBoundingBox(ignoreEmpty));

            RBox bb = e->getBoundingBox(false);
            RBox bbIgnoreEmpty = e->getBoundingBox(true);

            if (!bb.isSane()) {
                continue;
            }

            boundingBox[0][0].growToInclude(bb);
            boundingBox[0][1].growToInclude(bbIgnoreEmpty);
            if (!layerHidden) {
                boundingBox[1][0].growToInclude(bb);
                boundingBox[1][1].growToInclude(bbIgnoreEmpty);
            }
        }

        // don't resolve block references, if line weight is ByBlock,
        // the maxLinewidth will be adjusted when the block reference
        // is encountered:
        QStack<REntity*> blockRefStack;

        RLineweight::Lineweight lw = e->getLineweight(true, blockRefStack);
        maxLineweight = qMax(lw, maxLineweight);
    }

    boundingBoxChanged = false;

//    qDebug() << "\n\nbb: " << boundingBox[0][0];
//    qDebug() << "bb ignoreEmpty: " << boundingBox[0][1];
//    qDebug() << "bb ignoreHiddenLayers: " << boundingBox[1][0];
//    qDebug() << "bb ignoreHiddenLayers, ignoreEmpty: " << boundingBox[1][1];

    return boundingBox[ignoreHiddenLayers][ignoreEmpty];
}