PDA

View Full Version : How to get points drawn by strokePath from outline of QPainterPath



userman
24th April 2017, 16:57
Hi.

Is there any way that we can get points (or polygons) from outline strokePath, generated by QPainter::strokePath function?

I Was able to get access to points inline stroke (marked as green,yellow lines on attached screen) by doing this:




QPolygonF polygon = path.toFillPolygon();
for(int i=0;i < polygon.count(); i++)
{
QLineF lineEdge;
if(i != (polygon.count() - 1))
{
lineEdge.setPoints(polygon.at(i),polygon.at(i+1));
}
else
{
lineEdge.setPoints(polygon.at(i),polygon.at(0));
}

if (i%2 == 0)
{
QPen pen(Qt::yellow, 4);
painter->setPen(pen);
}
else
{
QPen pen(Qt::green, 4);
painter->setPen(pen);
}
painter->drawLine(lineEdge);
}


But how about outline point (marked as black line on attached screen) ? How can we get this?

12444

userman
1st February 2018, 03:02
Solved....

high_flyer
1st February 2018, 10:49
Solved....


Would be nice if you share your solution for others who may face a similar problem...

userman
6th February 2018, 19:58
This is (3 steps - tricky) way, but gives you 100% accuracy of points drawn by QPainter.
Step 1:
Get some points, and create SVG file.


/// Any QPainter element. e.g QLine/QPolygon etc. fill or not any mix of QPainter shapes.
QPainterPath polygonPath;
polygonPath.moveTo(10.0, 80.0);
polygonPath.lineTo(20.0, 10.0);
polygonPath.lineTo(80.0, 30.0);
polygonPath.lineTo(90.0, 70.0);
polygonPath.closeSubpath();

/// To write an SVG file, you first need to configure the output by setting the fileName or outputDevice properties.
QSvgGenerator generator;
string directory = "/home/mydir/";
generator.setFileName(QString::fromStdString(direc tory + "test.svg"));
/// The resolution is specified in dots per inch, and is used to calculate the physical size of an SVG drawing.
generator.setResolution(90); /// If 90 - coordinates in SVG will be in scale 1:1 for size set in setSize()
generator.setSize(QSize(1024, 768));
generator.setTitle(tr("SVG test"));
generator.setDescription(tr("QPainterPath test"));

/// Painting in QSvgGenerator is performed in the same way as for any other paint device.
/// However, it is necessary to use the QPainter::begin() and end() to explicitly begin and end painting on the device.
QPainter painter;
painter.begin(&generator);
painter.drawPath(polygonPath);
painter.end();
/// At this point SVG file was created.


Step 2
Use QtXML to open the SVG file as XML and manipulate it using the DOM or stream functions as appropriate.
In this example the content of test.svg is:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="288.996mm" height="216.747mm"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.2" baseProfile="tiny">
<title>SVG test</title>
<desc>QPainterPath test</desc>
<defs>
</defs>
<g fill="none" stroke="black" stroke-width="1" fill-rule="evenodd" stroke-linecap="square" stroke-linejoin="bevel" >

<path vector-effect="none" fill-rule="evenodd" d="M10,80 L20,10 L80,30 L90,70 L10,80"/>
</g>
</svg>

Step 3
You need to parse this:

d="M10,80 L20,10 L80,30 L90,70 L10,80"

Use for example QRegex to remove all unwanted letters M,L,C...etc and pair elements to x,y coordinates.
Point1(10,80)
Point2(20,10)
Point3(80,30)
Point4(90,70)
Point5(10,80)
And you will find what we expected.

d_stranz
6th February 2018, 23:23
Thanks for posting your solution. It's clever even if it is a little bit kludgy.

You might be able to make this simpler by using the QSvgGenerator::setOutputDevice() and a QBuffer to replace the disk file. You could then use that QBuffer in the QDomDocument::setContent() call.

Uwe
7th February 2018, 11:21
This is (3 steps - tricky) way, but gives you 100% accuracy of points drawn by QPainter.
To be honest I didn't get the point of this all - QPainterPath has a public API for reading all coordinates ?


QPainterPath polygonPath;
polygonPath.moveTo(10.0, 80.0);
...

for ( int i = 0; i < polygonPath.elementCount(); i++ )
{
const auto el = polygonPath.elementAt( i );
switch( el.type() )
{
case QPainterPath::MoveToElement:
....
break;
....
};
}In case you really need a record/replay paint device using QPicture would make more sense as no file IO would be involved. Of course you could also write your own type of paint device for recording QPainter commands like being done f.e in http://qwt.sourceforge.net/class_qwt_null_paint_device.html.

Uwe

userman
7th February 2018, 12:21
To be honest I didn't get the point of this all - QPainterPath has a public API for reading all coordinates ?


QPainterPath polygonPath;
polygonPath.moveTo(10.0, 80.0);
...

for ( int i = 0; i < polygonPath.elementCount(); i++ )
{
const auto el = polygonPath.elementAt( i );
switch( el.type() )
{
case QPainterPath::MoveToElement:
....
break;
....
};
}In case you really need a record/replay paint device using QPicture would make more sense as no file IO would be involved. Of course you could also write your own type of paint device for recording QPainter commands like being done f.e in http://qwt.sourceforge.net/class_qwt_null_paint_device.html.

Uwe
Uwe, you didn't get the point of this all... because you did not read my first post carefully. Please view attached image in first post.
12764
Yes you can read those points this way

polygonPath.elementAt( i );
But it gives you only the middle points of the QPen, marked as green/yellow dash line on my attached image.
In my example i need to find points marked as black line (on attached image)
If you known solution how to do this, please share this info.

Thanks d_stranz yes I can use QIODevice like this:



QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
QSvgGenerator generator;
generator.setOutputDevice(&buffer);
...
buffer.seek(0);
QString s(buffer.readAll());
qInfo() << s;
(do not create physical file - but i did not it for illustrate what is going on. For my purpose, I needed those points in XML anyway, but use setOutputDevice for speed up process is a very good idea)

In example form attached image - has to be created stroke path from red Curve, and read stroke path coordinates from SVG to find those points of black path.
Or there is better solution Uwe?

Uwe
7th February 2018, 13:34
Uwe, you didn't get the point of this all... because you did not read my first post carefully.
Well, there is QPainterPathStroker that is also internally used to create the QPainterPath that gets finally rendered.
So what you need to do is to set up the stroker with the attributes of your pen and then the strokedPath can be read like in my previous posting.

Thought you were talking about the strokedPath in your initial posting as you called it like that.

Uwe

userman
7th February 2018, 15:33
So the (other) final solution is:

Draw along outline points of shape:
12765



QPainterPath path(QPointF(80, 320));
path.lineTo(QPointF(240,90));
path.lineTo(QPointF(330,240));
path.lineTo(QPointF(620,180));
path.lineTo(QPointF(730,110));

QPainterPathStroker stroker;
stroker.setCapStyle(Qt::RoundCap);
stroker.setJoinStyle(Qt::RoundJoin);
stroker.setWidth(100);

QPainterPath strokePath = stroker.createStroke(path).simplified();

for (int i = 0; i < strokePath.elementCount()-1; i++)
{
QPainterPath::Element p1 = strokePath.elementAt(i);
QPainterPath::Element p2 = strokePath.elementAt(i+1);
painter->setPen(QPen(i % 2 == 0 ? Qt::red : Qt::green, 1));
painter->drawLine(QPointF(p1.x, p1.y), QPointF(p2.x, p2.y));
}

Solved.