Bug in getShape from Svg data


#1

Hey Embers,

TL/DR: The Shape2d object returned by a svg::DocRef doesn’t contain valid Path2d objects, because the contours inside don’t start with a MOVETO segment. This in turn causes the reverse() function call on the Path2d objects to mess them up, as it always expects a MOVETO segment in the beginning.

I’ve tried a few fixes (as elaborated below) but still don’t know how to… :frowning:

Elaborate story:

As per a previous topic of mine, I’m working with Shape2d objects generated via a svg::DocRef and attempting to extrude the vector shapes to generate a simple derived model with some depth.

The winding order of the points obtained in the Path2d objects contained within the Shape2d object are not always clock-wise. Even if they were, they might not be after I have performed some transformations on them. Therefore it becomes quite helpful to determine the winding order which the other post explores.

Once the winding order has been determined I call (or do not call) reverse() on the various Path2d objects. It seems generate ‘bad’ Path2d objects however, as they don’t begin with a MOVETO segment. This doesn’t seem to bother the geom::extrude function however, but it does cause the reverse() function to severely alter the Path2d. The reverse() function always expects a path to begin with a MOVETO segment and so will reverse all the points, but only some of the segments.

I thought a quick fix might be to simply manually insert a MOVETO segment in front of every Path2d I get out of the Shape2d object that I get from the svg::DocRef object. But either I’m not doing this correctly or I’m missing something as I’ve only managed to create new Path2d objects that cause geom::extrude to throw an exception I’ve yet to delve into deeper.

So I guess my question is one of two. Either:

  • Does someone have a fix for the code in Cinder to have the svg::DocRef produce proper Path2d objects inside the Shape2d file?
  • Failing that, does anyone have any advice on how to safely add a MOVETO segment at the beginning of any Path2d? I’ve tried simply cloning the very first point at the start and inserting a new MOVETO segment along with it, but that doesn’t seem to go well. The Path2d object confuses me a bit as well, as the moveTo functions don’t seem to automatically add a SegmentType to mSegments like all the other similar functions.

Any thoughts are appreciated!

Cheers,

Gazoo


Extrude on Svg data
#2

Hey again,

It turns out the fix was fairly straight forward, and that I had my diagnosis slightly off. I now believe that svg::DocRef actually generates proper paths but that the reverse() code on the path is faulty. It believes that a MOVETO segment must be present which not true.

I’m going to go out on a limb and guess that it’s a left-over from a previous implementation? In any case, the reverse() function should actually look something like this:

void ReversePath( ci::Path2d & path )
{
	// The path is empty: nothing to do.
	if (path.empty())
		return;

	// Reverse all points.
	auto & points = path.getPoints();
	std::reverse( points.begin(), points.end() );

	auto & segments = path.getSegments();

	// Reverse the segments, but skip the "moveto" and "close":
	if (path.isClosed()) {
		// There should be at least 4 segments: "moveto", "close" and two other segments.
		// No - there is no "moveto" segment, so at least 3 segments
		if (segments.size() > 2)
			std::reverse( segments.begin(), segments.end() - 1 );
	}
	else {
		// There should be at least 3 segments: "moveto" and two other segments.
		// No - there is no "moveto" segment, so at least 2 segments
		if (segments.size() > 1)
			std::reverse( segments.begin(), segments.end() );
	}

}

So basically the change is not to skip the first segment, and a slight adjustment to the size checks.

I’m still not quite done, as my code tends to flip every single contour, meaning ‘holes’ are simply black voids.

As soon as I figure out how to determine if a contour is an inside contour - I’m golden!

Cheers,

Gazoo