Beispiel #1
0
QList<QPointF> Geometry::intersection(QLineF const &line, QPainterPath const &path, qreal eps)
{
	QList<QPointF> result;
	QPointF startPoint;
	QPointF endPoint;

	for (int i = 0; i < path.elementCount(); ++i) {
		QPainterPath::Element const element = path.elementAt(i);

		// Checking that element belongs to the wall path
		if (element.isMoveTo()) {
			endPoint = QPointF(element.x, element.y);
			continue;
		}

		startPoint = endPoint;
		endPoint = QPointF(element.x, element.y);
		QLineF currentLine(startPoint, endPoint);
		QPointF intersectionPoint;
		// TODO: consider curve cases
		if (line.intersect(currentLine, &intersectionPoint) != QLineF::NoIntersection
				&& belongs(intersectionPoint, currentLine, eps))
		{
			result << intersectionPoint;
		}
	}

	return result;
}
Beispiel #2
0
GlyphToSVGHelper::GlyphToSVGHelper(QPainterPath path, QTransform tf)
    :m_path(path), m_transform(tf)
{
    QStringList data;
    QPointF curPos;
    for (int i = 0; i < path.elementCount(); ++i)
    {
        QPainterPath::Element cur = path.elementAt(i);
        QPointF curPoint(tf.map(cur));
        if(cur.isMoveTo())
        {
            curPos = curPoint;
            data << QString("M %1 %2").arg(curPos.x()).arg(curPos.y());
        }
        else if(cur.isLineTo())
        {
            curPos = curPoint;
            data << QString("L %1 %2").arg(curPos.x()).arg(curPos.y());
        }
        else if(cur.isCurveTo())
        {
            QPointF c1 = tf.map(path.elementAt(i + 1));
            QPointF c2 = tf.map(path.elementAt(i + 2));
            data << QString("C %1 %2 %3 %4 %5 %6")
                    .arg(curPoint.x()).arg(curPoint.y())
                    .arg(c1.x()).arg(c1.y())
                    .arg(c2.x()).arg(c2.y());

//             qDebug(data.last().toUtf8());

            i += 2;
            curPos = c2;
        }
        else
            qDebug("Unknown point type");
    }

    m_svg += QString("<path d=\"%1\" fill=\"%2\" />").arg(data.join(" ")).arg("black");

}
Beispiel #3
0
void QGIViewPart::dumpPath(const char* text,QPainterPath path)
{
        QPainterPath::Element elem;
        Base::Console().Message(">>>%s has %d elements\n",text,path.elementCount());
        char* typeName;
        for(int iElem = 0; iElem < path.elementCount(); iElem++) {
            elem = path.elementAt(iElem);
            if(elem.isMoveTo()) {
                typeName = "MoveTo";
            } else if (elem.isLineTo()) {
                typeName = "LineTo";
            } else if (elem.isCurveTo()) {
                typeName = "CurveTo";
            } else {
                typeName = "Unknown";
            }
            Base::Console().Message(">>>>> element %d: type:%d/%s pos(%.3f,%.3f) M:%d L:%d C:%d\n",iElem,
                                    elem.type,typeName,elem.x,elem.y,elem.isMoveTo(),elem.isLineTo(),elem.isCurveTo());
        }
}
/*!
    \internal
*/
void QGeoMapPolygonGeometry::updateScreenPoints(const QGeoMap &map)
{
    if (!screenDirty_)
        return;

    if (map.width() == 0 || map.height() == 0) {
        clear();
        return;
    }

    QPointF origin = map.coordinateToScreenPosition(srcOrigin_, false);

    // Create the viewport rect in the same coordinate system
    // as the actual points
    QRectF viewport(0, 0, map.width(), map.height());
    viewport.translate(-1 * origin);

    QPainterPath vpPath;
    vpPath.addRect(viewport);

    QPainterPath ppi;
    if (clipToViewport_)
        ppi = srcPath_.intersected(vpPath); // get the clipped version of the path
    else ppi = srcPath_;

    clear();

    // a polygon requires at least 3 points;
    if (ppi.elementCount() < 3)
        return;

    // Intersection between the viewport and a concave polygon can create multiple polygons
    // joined by a line at the viewport border, and poly2tri does not triangulate this very well
    // so use the full src path if the resulting polygon is concave.
    if (clipToViewport_) {
        int changeInX = 0;
        int changeInY = 0;
        QPainterPath::Element e1 = ppi.elementAt(1);
        QPainterPath::Element e = ppi.elementAt(0);
        QVector2D edgeA(e1.x - e.x ,e1.y - e.y);
        for (int i = 2; i <= ppi.elementCount(); ++i) {
            e = ppi.elementAt(i % ppi.elementCount());
            if (e.x == e1.x && e.y == e1.y)
                continue;
            QVector2D edgeB(e.x - e1.x, e.y - e1.y);
            if ((edgeA.x() < 0) == (edgeB.x() >= 0))
                changeInX++;
            if ((edgeA.y() < 0) == (edgeB.y() >= 0))
                changeInY++;
            edgeA = edgeB;
            e1 = e;
        }
        if (changeInX > 2 || changeInY > 2) // polygon is concave
            ppi = srcPath_;
    }

    // translate the path into top-left-centric coordinates
    QRectF bb = ppi.boundingRect();
    ppi.translate(-bb.left(), -bb.top());
    firstPointOffset_ = -1 * bb.topLeft();

    ppi.closeSubpath();

    screenOutline_ = ppi;

    std::vector<p2t::Point*> curPts;
    curPts.reserve(ppi.elementCount());
    for (int i = 0; i < ppi.elementCount(); ++i) {
        const QPainterPath::Element e = ppi.elementAt(i);
        if (e.isMoveTo() || i == ppi.elementCount() - 1
                || (qAbs(e.x - curPts.front()->x) < 0.1
                    && qAbs(e.y - curPts.front()->y) < 0.1)) {
            if (curPts.size() > 2) {
                p2t::CDT *cdt = new p2t::CDT(curPts);
                cdt->Triangulate();
                std::vector<p2t::Triangle*> tris = cdt->GetTriangles();
                screenVertices_.reserve(screenVertices_.size() + int(tris.size()));
                for (size_t i = 0; i < tris.size(); ++i) {
                    p2t::Triangle *t = tris.at(i);
                    for (int j = 0; j < 3; ++j) {
                        p2t::Point *p = t->GetPoint(j);
                        screenVertices_ << Point(p->x, p->y);
                    }
                }
                delete cdt;
            }
            curPts.clear();
            curPts.reserve(ppi.elementCount() - i);
            curPts.push_back(new p2t::Point(e.x, e.y));
        } else if (e.isLineTo()) {
            curPts.push_back(new p2t::Point(e.x, e.y));
        } else {
            qWarning("Unhandled element type in polygon painterpath");
        }
    }

    if (curPts.size() > 0) {
        qDeleteAll(curPts.begin(), curPts.end());
        curPts.clear();
    }

    screenBounds_ = ppi.boundingRect();

}
void LineRenderable::render(QPainter &painter, const RenderConfig &config) const
{
	QPen pen(painter.pen());
	pen.setCapStyle(cap_style);
	pen.setJoinStyle(join_style);
	if (join_style == Qt::MiterJoin)
	{
		pen.setMiterLimit(LineSymbol::miterLimit());
		fixPenForPdf(pen, painter);
	}
	painter.setPen(pen);
	
	// One-time adjustment for line width
	QRectF bounding_box = config.bounding_box.adjusted(-line_width, -line_width, line_width, line_width);
	const int count = path.elementCount();
	if (count <= 2 || bounding_box.contains(path.controlPointRect()))
	{
		// path fully contained
		painter.drawPath(path);
	}
	else
	{
		// Manually clip the path with bounding_box, this seems to be faster.
		// The code splits up the painter path into new paths which intersect
		// the view rect and renders these only.
		// NOTE: this does not work correctly with miter joins, but this
		//       should be a minor issue.
		QPainterPath::Element element = path.elementAt(0);
		QPainterPath::Element last_element = path.elementAt(count-1);
		bool path_closed = (element.x == last_element.x) && (element.y == last_element.y);
		
		QPainterPath part_path;
		QPainterPath first_path;
		bool path_started = false;
		bool part_finished = false;
		bool current_part_is_first = bounding_box.contains(element);
		
		QPainterPath::Element prev_element = element;
		for (int i = 1; i < count; ++i)
		{
			element = path.elementAt(i);
			if (element.isLineTo())
			{
				qreal min_x, min_y, max_x, max_y;
				if (prev_element.x < element.x)
				{
					min_x = prev_element.x;
					max_x = element.x;
				}
				else
				{
					min_x = element.x;
					max_x = prev_element.x;
				}
				if (prev_element.y < element.y)
				{
					min_y = prev_element.y;
					max_y = element.y;
				}
				else
				{
					min_y = element.y;
					max_y = prev_element.y;
				}
				if ( min_x <= bounding_box.right()  &&
				     max_x >= bounding_box.left()   &&
				     min_y <= bounding_box.bottom() &&
				     max_y >= bounding_box.top() )
				{
					if (!path_started)
					{
						part_path = QPainterPath();
						part_path.moveTo(prev_element.x, prev_element.y);
						path_started = true;
					}
					part_path.lineTo(element.x, element.y);
				}
				else if (path_started)
				{
					part_finished = true;
				}
				else
				{
					current_part_is_first = false;
				}
			}
			else if (element.isCurveTo())
			{
				Q_ASSERT(i < count - 2);
				QPainterPath::Element next_element = path.elementAt(i + 1);
				QPainterPath::Element end_element = path.elementAt(i + 2);
				
				qreal min_x = qMin(prev_element.x, qMin(element.x, qMin(next_element.x, end_element.x)));
				qreal min_y = qMin(prev_element.y, qMin(element.y, qMin(next_element.y, end_element.y)));
				qreal max_x = qMax(prev_element.x, qMax(element.x, qMax(next_element.x, end_element.x)));
				qreal max_y = qMax(prev_element.y, qMax(element.y, qMax(next_element.y, end_element.y)));
				
				if ( min_x <= bounding_box.right()  &&
				     max_x >= bounding_box.left()   &&
				     min_y <= bounding_box.bottom() &&
				     max_y >= bounding_box.top() )
				{
					if (!path_started)
					{
						part_path = QPainterPath();
						part_path.moveTo(prev_element.x, prev_element.y);
						path_started = true;
					}
					part_path.cubicTo(element.x, element.y, next_element.x, next_element.y, end_element.x, end_element.y);
				}
				else if (path_started)
				{
					part_finished = true;
				}
				else
				{
					current_part_is_first = false;
				}
			}
			else if (element.isMoveTo() && path_started)
			{
				part_path.moveTo(element.x, element.y);
			}
			
			if (part_finished)
			{
				if (current_part_is_first && path_closed)
				{
					current_part_is_first = false;
					first_path = part_path;
				}
				else
				{
					painter.drawPath(part_path);
				}
				
				path_started = false;
				part_finished = false;
			}
			
			prev_element = element;
		}
		
		if (path_started)
		{
			if (path_closed && !first_path.isEmpty())
				part_path.connectPath(first_path);
			
			painter.drawPath(part_path);
		}
	}
	
	// DEBUG: show all control points
	/*QPen debugPen(QColor(Qt::red));
	painter.setPen(debugPen);
	for (int i = 0; i < path.elementCount(); ++i)
	{
		const QPainterPath::Element& e = path.elementAt(i);
		painter.drawEllipse(QPointF(e.x, e.y), 0.2f, 0.2f);
	}
	painter.setPen(pen);*/
}
/*!
    \internal
*/
void QGeoMapCircleGeometry::updateScreenPointsInvert(const QGeoMap &map)
{
    if (!screenDirty_)
        return;

    if (map.width() == 0 || map.height() == 0) {
        clear();
        return;
    }

    QPointF origin = map.coordinateToItemPosition(srcOrigin_, false).toPointF();

    QPainterPath ppi = srcPath_;

    clear();

    // a circle requires at least 3 points;
    if (ppi.elementCount() < 3)
        return;

    // translate the path into top-left-centric coordinates
    QRectF bb = ppi.boundingRect();
    ppi.translate(-bb.left(), -bb.top());
    firstPointOffset_ = -1 * bb.topLeft();

    ppi.closeSubpath();

    // calculate actual width of map on screen in pixels
    QGeoCoordinate mapCenter(0, map.cameraData().center().longitude());
    QDoubleVector2D midPoint = map.coordinateToItemPosition(mapCenter, false);
    QDoubleVector2D midPointPlusOne = QDoubleVector2D(midPoint.x() + 1.0, midPoint.y());
    QGeoCoordinate coord1 = map.itemPositionToCoordinate(midPointPlusOne, false);
    double geoDistance = coord1.longitude() - map.cameraData().center().longitude();
    if ( geoDistance < 0 )
        geoDistance += 360.0;
    double mapWidth = 360.0 / geoDistance;

    qreal leftOffset = origin.x() - (map.width()/2.0 - mapWidth/2.0) - firstPointOffset_.x();
    qreal topOffset = origin.y() - (midPoint.y() - mapWidth/2.0) - firstPointOffset_.y();
    QPainterPath ppiBorder;
    ppiBorder.moveTo(QPointF(-leftOffset, -topOffset));
    ppiBorder.lineTo(QPointF(mapWidth - leftOffset, -topOffset));
    ppiBorder.lineTo(QPointF(mapWidth - leftOffset, mapWidth - topOffset));
    ppiBorder.lineTo(QPointF(-leftOffset, mapWidth - topOffset));

    screenOutline_ = ppiBorder;

    std::vector<p2t::Point*> borderPts;
    borderPts.reserve(4);

    std::vector<p2t::Point*> curPts;
    curPts.reserve(ppi.elementCount());
    for (int i = 0; i < ppi.elementCount(); ++i) {
        const QPainterPath::Element e = ppi.elementAt(i);
        if (e.isMoveTo() || i == ppi.elementCount() - 1
                || (qAbs(e.x - curPts.front()->x) < 0.1
                    && qAbs(e.y - curPts.front()->y) < 0.1)) {
            if (curPts.size() > 2) {
                for (int j = 0; j < 4; ++j) {
                    const QPainterPath::Element e2 = ppiBorder.elementAt(j);
                    borderPts.push_back(new p2t::Point(e2.x, e2.y));
                }
                p2t::CDT *cdt = new p2t::CDT(borderPts);
                cdt->AddHole(curPts);
                cdt->Triangulate();
                std::vector<p2t::Triangle*> tris = cdt->GetTriangles();
                screenVertices_.reserve(screenVertices_.size() + int(tris.size()));
                for (size_t i = 0; i < tris.size(); ++i) {
                    p2t::Triangle *t = tris.at(i);
                    for (int j = 0; j < 3; ++j) {
                        p2t::Point *p = t->GetPoint(j);
                        screenVertices_ << QPointF(p->x, p->y);
                    }
                }
                delete cdt;
            }
            curPts.clear();
            curPts.reserve(ppi.elementCount() - i);
            curPts.push_back(new p2t::Point(e.x, e.y));
        } else if (e.isLineTo()) {
            curPts.push_back(new p2t::Point(e.x, e.y));
        } else {
            qWarning("Unhandled element type in circle painterpath");
        }
    }

    if (curPts.size() > 0) {
        qDeleteAll(curPts.begin(), curPts.end());
        curPts.clear();
    }

    if (borderPts.size() > 0) {
        qDeleteAll(borderPts.begin(), borderPts.end());
        borderPts.clear();
    }

    screenBounds_ = ppiBorder.boundingRect();

}