Open GoogleCodeExporter opened 9 years ago
The issue is NOT that the line is vertical (that was just my bad guess for a
chance occurrence) but that the point is ON the line.
If the module is designed with the precondition for the Line2(Point2, Point2)
constructor: "the points are not identical so that the line has non-zero
length", then the module should catch the exception at certain places, for
example so that Point2.distance(Line2) does not raise the exception when the
point is on the line, but instead returns 0, which is a valid scalar distance.
On the other hand, a set interpretation of Line2 might allow the points
defining the line to be the same (having an empty interior set and a boundary
set of cardinality one.) Possibly the module documentation should make clear
that the module does not comply to such a set interpretation. I am not an
expert, my comment is flavored by my recent reading of the Shapely/GEOS module.
Also AttributeError is not the correct exception to raise. AttributeError
means the attribute could not be found by the Python interpreter. ValueError
should be raised, ("Raised when a built-in operation or function receives an
argument that has the right type but an inappropriate value, and the situation
is not described by a more precise exception such as IndexError.") or the
module should define its own exception (since the module is not really
"built-in".)
Also, if it is a precondition that the points of the Line2() constructor can
not be the same point, an assertion could check that earlier (and would raise a
more understandable message.) Without suffering performance since assertions
can be turned off.
Original comment by boo...@nc.rr.com
on 21 May 2012 at 11:53
This discusses a proposed fix.
An invariant is that Lines and Rays have infinite length, or equivalently,
length() is undefined.
LineSegments have a finite length, but it can be zero.
Lines have no bounding points. LineSegments and Rays have a set of bounding
points. A Ray has one bounding point and a LineSegment has two.
Another invariant of Line and Ray is that they have a non-zero vector in the
implementation. The problem is that this assertion is also made for
LineSegment, when it inherits Line.__init__().
A fix might be to breakout most of the __init__ constructor for Line(), all
except the assertion at the end that the vector is non-zero. Define an
__init__ for LineSegment and Ray that calls said constructor. Line.__init__
would also call the constructor. Only Line and Ray would also make said
assertion in their __init___.
I haven't tested this proposed fix.
Another simpler, but hacky, fix would be to define nearest(), which instead of
returning a LineSegment as connect() does, returns a Point. connect() would
continue to raise an exception when it returns a zero-length LineSegment.
nearest() would catch that exception and return the point of intersection. I
haven't fully thought out the implications. It might be better if connect()
always returns a LineSegment, even if zero length. Then you might interpret
such a condition as tangency? For example, some references "properly count"
the points of tangency of a line to a convex polygon vertex (or circle?) as a
set of cardinality two.
Original comment by boo...@nc.rr.com
on 21 May 2012 at 8:40
I tested the proposed fix. It works in that no exception is raised for the
problem case. But the fix is not entirely satisfactory because a zero-length
line segment does not intersect() with the line it supposedly connects a point
to.
foo = LineSegment2(Point2(0,1), Point2(0,0))
foo.connect(Point2(0, 0.7)).intersect(foo)
returns None
Original comment by boo...@nc.rr.com
on 21 May 2012 at 10:31
I tried a different fix:
1. catch the exception in connect() and return a Point2 instead of a
LineSegment2
2. define Point2._swap() and .length()
3. define Line2._intersect_point2() to return given point if the point is on
the line.
(Currently, it is not implemented, which seems like another deficiency.)
Seems to work for:
>>> from pyeuclid import *
>>> foo = LineSegment2(Point2(0,1), Point2(0,0))
>>> bar = foo.connect(Point2(0, 0.7))
>>> bar.intersect(foo)
Point2(0.00, 0.70)
I am not sure it is the best possible fix, but it seems intuitive:
LineSegment has a finite length greater than 0
connect() returns either a LineSeqment or a Point
Point.length() is always 0
Line.intersect(Point) returns the point if it is on the line, else None
Original comment by boo...@nc.rr.com
on 22 May 2012 at 1:32
Is this a duplicate of bug #12 ?
Original comment by rodrigo....@gmail.com
on 6 Aug 2014 at 9:31
Original issue reported on code.google.com by
boo...@nc.rr.com
on 20 May 2012 at 11:18