Why is this blowing up?

Can somebody tell me what is wrong with this code (fragments shown below). It throws some sort of exception which Inkscape catches when it gets down to
(*result).back().append(ls);
However, there is no problem doing
output.back().append(ls); // output is what result was named in the caller
in pathv_to_linear, where "output" was created. It is only a problem when the pathvector has been passed into the second (recursive) function.
Geom::PathVector pathv_to_linear( Geom::PathVector const &pathv, double maxdisp) { Geom::PathVector output; Geom::PathVector tmppath = pathv_to_linear_and_cubic_beziers(pathv); for (Geom::PathVector::const_iterator pit = tmppath.begin(); pit != tmppath.end(); ++pit) { output.push_back( Geom::Path() ); output.back().start( pit->initialPoint() ); output.back().close( pit->closed() ); for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { ... double xe,ye; int pset = 0; // set to 1 once a last point has been set recursive_bezier4( A[X], A[Y], B[X], B[Y], C[X], C[Y], D[X], D[Y], &xe, &ye, &pset, &output, 0); ... }
void recursive_bezier4(const double x1, const double y1, const double x2, const double y2, const double x3, const double y3, const double x4, const double y4, double *xe, double *ye, // last point added, if any int *pset, // 1 if value for xe,ye have been set Geom::PathVector *result, int level) { ... r1=Geom::Point(x23,y23); Geom::LineSegment ls(r0, r1); (*result).back().append(ls); // <---- Blows up here ... recursive_bezier4(x1, y1, x12, y12, x123, y123, x1234, y1234, xe, ye, pset, result, level+1); recursive_bezier4(x1234, y1234, x234, y234, x34, y34, x4, y4, xe, ye, pset, result, level+1); }
**************************************
I tried putting this
r0=Geom::Point(0.0,0.0); r1=Geom::Point(1.0,1.0); Geom::LineSegment ls(r0, r1); (*result).back().append(ls); // blows up here
at the top of recursive_bezier4, and it blew up in the first call, so it isn't losing the pointer in the recursion, it is invalid from the first call. However, there are no compiler errors or warnings.
I also tried it this way:
//in pathv_to_linear recursive_bezier4( A[X], A[Y], B[X], B[Y], C[X], C[Y], D[X], D[Y], &xe, &ye, &pset, output, 0);
void recursive_bezier4(const double x1, const double y1, const double x2, const double y2, const double x3, const double y3, const double x4, const double y4, double *xe, double *ye, // last point added, if any int *pset, // 1 if value for xe,ye have been set Geom::PathVector &result, int level) { .. r0=Geom::Point(0.0,0.0); r1=Geom::Point(1.0,1.0); Geom::LineSegment ls(r0, r1); result.back().append(ls);
but it had the same problem, or at least the (new) error was on the same line.
When run in gdb inkscape still caught the exception, so gdb did not break at the problem. My guess is that even if gdb had caught it it would not have been very informative, just some inscrutable error at the line where I already know the problem shows up.
Any ideas what might be causing this?
Thanks,
David Mathog mathog@...1176... Manager, Sequence Analysis Facility, Biology Division, Caltech

2013/2/21 mathog <mathog@...1176...>:
Can somebody tell me what is wrong with this code (fragments shown below). It throws some sort of exception which Inkscape catches when it gets down to
(*result).back().append(ls);
This is throwing Geom::ContinuityError, because the initial point of the segment you are appending does not match the final point of the path. If the path is empty and default-constructed, its final point is (0,0). Admittedly this is not good API design - in this case the final point should be undefined until the first append() call. This was probably done to represent degenerate 1-point subpaths which can be constructed in SVG.
This problem can be avoided by a) constructing the path with the initial point of the first segment as a parameter b) using Geom::SVGPathGenerator.
Regards, Krzysztof

On 21-Feb-2013 17:32, Krzysztof Kosiński wrote:
2013/2/21 mathog <mathog@...1176...>:
Can somebody tell me what is wrong with this code (fragments shown below). It throws some sort of exception which Inkscape catches when it gets down to
(*result).back().append(ls);
This is throwing Geom::ContinuityError, because the initial point of the segment you are appending does not match the final point of the path. If the path is empty and default-constructed, its final point is (0,0). Admittedly this is not good API design - in this case the final point should be undefined until the first append() call. This was probably done to represent degenerate 1-point subpaths which can be constructed in SVG.
This problem can be avoided by a) constructing the path with the initial point of the first segment as a parameter b) using Geom::SVGPathGenerator.
Hmm, that does not quite fit with what I observed. In the end I programmed around the problem, whatever it is, like this:
... Geom::PathVector output; ... Geom::BezierCurve const *curve = dynamic_cast<Geom::BezierCurve const *>(&*cit); Geom::CubicBezier b((*curve)[0], (*curve)[1], (*curve)[2], (*curve)[3]); std::vectorGeom::Point bzrpoints = b.points(); Geom::Point A = bzrpoints[0]; Geom::Point B = bzrpoints[1]; Geom::Point C = bzrpoints[2]; Geom::Point D = bzrpoints[3]; std::vectorGeom::Point pointlist; pointlist.push_back(A); recursive_bezier4( A[X], A[Y], B[X], B[Y], C[X], C[Y], D[X], D[Y], pointlist, 0); pointlist.push_back(D); Geom::Point r0; Geom::Point r1 = pointlist[0]; for (unsigned int i=1; i<pointlist.size();i++){ r0 = r1; r1 = pointlist[i]; Geom::LineSegment ls(r0, r1); output.back().append(ls); } pointlist.clear();
where in recursive_bezier4() points were added like this:
void recursive_bezier4(const double x1, const double y1, const double x2, const double y2, const double x3, const double y3, const double x4, const double y4, std::vectorGeom::Point &m_points, int level) { ... m_points.push_back(Geom::Point(x2, y2)); // various points, not just these two ... }
In the first iteration of this approach the push_back() for points A and D were not present. This resulted in a path consisting of all the new midpoints, but not the original end points. The thing is, the (first) resultant output.back().append(ls) would blow up if called in recursive_bezier4(), but not when called, as above, outside of it. Yet the list of line segments it was being fed were identical in the two cases, so the first line segment was also the same. So the "first line segment does not match" error, if this is what it was (since I could never get by it), only triggered for append() in the recursive_bezier4() function, not in the pathv_to_linear() function which called it. How could object.back().append() distinguish between those two cases?
Anyway, since the current method works the question is somewhat academic - until the next time somebody tries to use output.back().append() in the same way.
Thanks,
David Mathog mathog@...1176... Manager, Sequence Analysis Facility, Biology Division, Caltech
participants (2)
-
Krzysztof Kosiński
-
mathog