From 791090bd775b6a2b488ae2078c8479fcd3324a2c Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 22 Apr 2020 14:43:26 -0400 Subject: [PATCH] Doc: update section 9.11 for new function table layout. This also makes an attempt to flesh out the docs for some of the more severely underdocumented geometric operators and functions. This effort exposed that the point <^ point (point_below) and point >^ point (point_above) operators are misnamed; they should be <<| and |>>, because they act like the other operators named that way and not like the other operators named <^ and >^. But I just documented them that way; fixing it is matter for another patch. The haphazard datatype coverage of many of the operators is also now depressingly obvious. Discussion: https://postgr.es/m/158110996889.1089.4224139874633222837@wrigleys.postgresql.org --- doc/src/sgml/func.sgml | 1576 +++++++++++++++++++++++++++------------- 1 file changed, 1086 insertions(+), 490 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 6cb2467dca..90a2582dfd 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -9446,188 +9446,576 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple linkend="functions-geometry-conv-table"/>. + + Geometric Operators + + + + + OperatorDescriptionExample(s) + + + + + + + + geometric_type + point + geometric_type + + Adds the coordinates of the second point to those of each + point of the first argument, thus performing translation. + Available for point, box, path, + circle. + + box '(1,1),(0,0)' + point '(2,0)' + (3,1),(2,0) + + + + + + path + path + path + + Concatenates two open paths (returns NULL if either path is closed). + + path '[(0,0),(1,1)]' + path '[(2,2),(3,3),(4,4)]' + [(0,0),(1,1),(2,2),(3,3),(4,4)] + + + + + + geometric_type - point + geometric_type + + Subtracts the coordinates of the second point from those + of each point of the first argument, thus performing translation. + Available for point, box, path, + circle. + + box '(1,1),(0,0)' - point '(2,0)' + (-1,1),(-2,0) + + + + + + geometric_type * point + geometric_type + + Multiplies each point of the first argument by the second + pointFor this purpose, the + product of two points + (x1,y1) and + (x2,y2) is + defined as + (x1*x2 - + y1*y2, + x1*y2 + + y1*x2).. + Interpreting the point as a vector, this is equivalent to + scaling the object's size and distance from the origin by the length + of the vector, and rotating it counterclockwise around the origin by + the vector's angle from the x axis. + Available for point, box, path, + circle. + + path '((0,0),(1,0),(1,1))' * point '(3.0,0)' + ((0,0),(3,0),(3,3)) + + path '((0,0),(1,0),(1,1))' * point(cosd(45), sind(45)) + ((0,0),&zwsp;(0.7071067811865475,0.7071067811865475),&zwsp;(0,1.414213562373095)) + + + + + + geometric_type / point + geometric_type + + Divides each point of the first argument by the + second pointFor this purpose, the + quotient of two points + (x1,y1) and + (x2,y2) is + defined as + ((x1*x2 + + y1*y2) / + L, + (y1*x2 - + x1*y2) / + L), + where L = + x2*x2 + + y2*y2.. + Interpreting the point as a vector, this is equivalent to + scaling the object's size and distance from the origin down by the + length of the vector, and rotating it clockwise around the origin by + the vector's angle from the x axis. + Available for point, box, path, + circle. + + path '((0,0),(1,0),(1,1))' / point '(2.0,0)' + ((0,0),(0.5,0),(0.5,0.5)) + + path '((0,0),(1,0),(1,1))' / point(cosd(45), sind(45)) + ((0,0),&zwsp;(0.7071067811865476,-0.7071067811865476),&zwsp;(1.4142135623730951,0)) + + + + + + @-@ geometric_type + double precision + + Computes the total length. + Available for lseg, path. + + @-@ path '[(0,0),(1,0),(1,1)]' + 2 + + + + + + @@ geometric_type + point + + Computes the center point. + Available for box, lseg, path, + polygon, circle. + + @@ box '(2,2),(0,0)' + (1,1) + + + + + + # geometric_type + integer + + Returns the number of points. + Available for path, polygon. + + # path '((1,0),(0,1),(-1,0))' + 3 + + + + + + geometric_type # geometric_type + point + + Computes the point of intersection, or NULL if there is none. + Available for lseg, line. + + lseg '[(0,0),(1,1)]' # lseg '[(1,0),(0,1)]' + (0.5,0.5) + + + + + + box # box + box + + Computes the intersection of two boxes, or NULL if there is none. + + box '(2,2),(-1,-1)' # box '(1,1),(-2,-2)' + (1,1),(-1,-1) + + + + + + geometric_type ## geometric_type + point + + Computes the closest point to the first object on the second object. + Available for these pairs of types: + (point, box), + (point, lseg), + (point, line), + (lseg, box), + (lseg, lseg), + (lseg, line), + (line, box), + (line, lseg). + + point '(0,0)' ## lseg '[(2,0),(0,2)]' + (1,1) + + + + + + geometric_type <-> geometric_type + double precision + + Computes the distance between the objects. + Available for all seven geometric types, for all combinations + of point with another geometric type, and for + these additional pairs of types: + (box, lseg), + (box, line), + (lseg, line), + (polygon, circle) + (and the commutator cases). + + circle '<(0,0),1>' <-> circle '<(5,0),1>' + 3 + + + + + + geometric_type @> geometric_type + boolean + + Does first object contain second? + Available for these pairs of types: + (box, point), + (box, box), + (path, point), + (polygon, point), + (polygon, polygon), + (circle, point), + (circle, circle). + + circle '<(0,0),2>' @> point '(1,1)' + t + + + + + + geometric_type <@ geometric_type + boolean + + Is first object contained in or on second? + Available for these pairs of types: + (point, box), + (point, lseg), + (point, line), + (point, path), + (point, polygon), + (point, circle), + (box, box), + (lseg, box), + (lseg, line), + (polygon, polygon), + (circle, circle). + + point '(1,1)' <@ circle '<(0,0),2>' + t + + + + + + geometric_type && geometric_type + boolean + + Do these objects overlap? (One point in common makes this true.) + Available for box, polygon, + circle. + + box '(1,1),(0,0)' && box '(2,2),(0,0)' + t + + + + + + geometric_type << geometric_type + boolean + + Is first object strictly left of second? + Available for point, box, + polygon, circle. + + circle '<(0,0),1>' << circle '<(5,0),1>' + t + + + + + + geometric_type >> geometric_type + boolean + + Is first object strictly right of second? + Available for point, box, + polygon, circle. + + circle '<(5,0),1>' >> circle '<(0,0),1>' + t + + + + + + geometric_type &< geometric_type + boolean + + Does first object not extend to the right of second? + Available for box, polygon, + circle. + + box '(1,1),(0,0)' &< box '(2,2),(0,0)' + t + + + + + + geometric_type &> geometric_type + boolean + + Does first object not extend to the left of second? + Available for box, polygon, + circle. + + box '(3,3),(0,0)' &> box '(2,2),(0,0)' + t + + + + + + geometric_type <<| geometric_type + boolean + + Is first object strictly below second? + Available for box, polygon, + circle. + + box '(3,3),(0,0)' <<| box '(5,5),(3,4)' + t + + + + + + geometric_type |>> geometric_type + boolean + + Is first object strictly above second? + Available for box, polygon, + circle. + + box '(5,5),(3,4)' |>> box '(3,3),(0,0)' + t + + + + + + geometric_type &<| geometric_type + boolean + + Does first object not extend above second? + Available for box, polygon, + circle. + + box '(1,1),(0,0)' &<| box '(2,2),(0,0)' + t + + + + + + geometric_type |&> geometric_type + boolean + + Does first object not extend below second? + Available for box, polygon, + circle. + + box '(3,3),(0,0)' |&> box '(2,2),(0,0)' + t + + + + + + box <^ box + boolean + + Is first object below second (allows edges to touch)? + + box '((1,1),(0,0))' <^ box '((2,2),(1,1))' + t + + + + + + point <^ point + boolean + + Is first object strictly below second? + (This operator is misnamed; it should be <<|.) + + point '(1,0)' <^ point '(1,1)' + t + + + + + + box >^ box + boolean + + Is first object above second (allows edges to touch)? + + box '((2,2),(1,1))' >^ box '((1,1),(0,0))' + t + + + + + + point >^ point + boolean + + Is first object strictly above second? + (This operator is misnamed; it should be |>>.) + + point '(1,1)' >^ point '(1,0)' + t + + + + + + geometric_type ?# geometric_type + boolean + + Do these objects intersect? + Available for these pairs of types: + (box, box), + (lseg, box), + (lseg, lseg), + (lseg, line), + (line, box), + (line, line), + (path, path). + + lseg '[(-1,0),(1,0)]' ?# box '(2,2),(-2,-2)' + t + + + + + + ?- geometric_type + boolean + + Is line horizontal? + Available for lseg, line. + + ?- lseg '[(-1,0),(1,0)]' + t + + + + + + point ?- point + boolean + + Are points horizontally aligned (that is, have same y coordinate)? + + point '(1,0)' ?- point '(0,0)' + t + + + + + + ?| geometric_type + boolean + + Is line vertical? + Available for lseg, line. + + ?| lseg '[(-1,0),(1,0)]' + f + + + + + + point ?| point + boolean + + Are points vertically aligned (that is, have same x coordinate)? + + point '(0,1)' ?| point '(0,0)' + t + + + + + + geometric_type ?-| geometric_type + boolean + + Are lines perpendicular? + Available for lseg, line. + + lseg '[(0,0),(0,1)]' ?-| lseg '[(0,0),(1,0)]' + t + + + + + + geometric_type ?|| geometric_type + boolean + + Are lines parallel? + Available for lseg, line. + + lseg '[(-1,0),(1,0)]' ?|| lseg '[(-1,2),(1,2)]' + t + + + + + + geometric_type ~= geometric_type + boolean + + Are these objects the same? + Available for point, box, + polygon, circle. + + polygon '((0,0),(1,1))' ~= polygon '((1,1),(0,0))' + t + + + + +
+ - Note that the same as operator, ~=, represents - the usual notion of equality for the point, + Note that the same as operator, ~=, + represents the usual notion of equality for the point, box, polygon, and circle types. - Some of these types also have an = operator, but - = compares - for equal areas only. The other scalar comparison operators - (<= and so on) likewise compare areas for these types. + Some of the geometric types also have an = operator, but + = compares for equal areas only. + The other scalar comparison operators (<= and so + on), where available for these types, likewise compare areas. - - Geometric Operators - - - - Operator - Description - Example - - - - - + - Translation - box '((0,0),(1,1))' + point '(2.0,0)' - - - - - Translation - box '((0,0),(1,1))' - point '(2.0,0)' - - - * - Scaling/rotation - box '((0,0),(1,1))' * point '(2.0,0)' - - - / - Scaling/rotation - box '((0,0),(2,2))' / point '(2.0,0)' - - - # - Point or box of intersection - box '((1,-1),(-1,1))' # box '((1,1),(-2,-2))' - - - # - Number of points in path or polygon - # path '((1,0),(0,1),(-1,0))' - - - @-@ - Length or circumference - @-@ path '((0,0),(1,0))' - - - @@ - Center - @@ circle '((0,0),10)' - - - ## - Closest point to first operand on second operand - point '(0,0)' ## lseg '((2,0),(0,2))' - - - <-> - Distance between - circle '((0,0),1)' <-> circle '((5,0),1)' - - - && - Overlaps? (One point in common makes this true.) - box '((0,0),(1,1))' && box '((0,0),(2,2))' - - - << - Is strictly left of? - circle '((0,0),1)' << circle '((5,0),1)' - - - >> - Is strictly right of? - circle '((5,0),1)' >> circle '((0,0),1)' - - - &< - Does not extend to the right of? - box '((0,0),(1,1))' &< box '((0,0),(2,2))' - - - &> - Does not extend to the left of? - box '((0,0),(3,3))' &> box '((0,0),(2,2))' - - - <<| - Is strictly below? - box '((0,0),(3,3))' <<| box '((3,4),(5,5))' - - - |>> - Is strictly above? - box '((3,4),(5,5))' |>> box '((0,0),(3,3))' - - - &<| - Does not extend above? - box '((0,0),(1,1))' &<| box '((0,0),(2,2))' - - - |&> - Does not extend below? - box '((0,0),(3,3))' |&> box '((0,0),(2,2))' - - - <^ - Is below (allows touching)? - circle '((0,0),1)' <^ circle '((0,5),1)' - - - >^ - Is above (allows touching)? - circle '((0,5),1)' >^ circle '((0,0),1)' - - - ?# - Intersects? - lseg '((-1,0),(1,0))' ?# box '((-2,-2),(2,2))' - - - ?- - Is horizontal? - ?- lseg '((-1,0),(1,0))' - - - ?- - Are horizontally aligned? - point '(1,0)' ?- point '(0,0)' - - - ?| - Is vertical? - ?| lseg '((-1,0),(1,0))' - - - ?| - Are vertically aligned? - point '(0,1)' ?| point '(0,0)' - - - ?-| - Is perpendicular? - lseg '((0,0),(0,1))' ?-| lseg '((0,0),(1,0))' - - - ?|| - Are parallel? - lseg '((-1,0),(1,0))' ?|| lseg '((-1,2),(1,2))' - - - @> - Contains? - circle '((0,0),2)' @> point '(1,1)' - - - <@ - Contained in or on? - point '(1,1)' <@ circle '((0,0),2)' - - - ~= - Same as? - polygon '((0,0),(1,1))' ~= polygon '((1,1),(0,0))' - - - -
- Before PostgreSQL 8.2, the containment @@ -9637,308 +10025,532 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple - - area - - - center - - - diameter - - - height - - - isclosed - - - isopen - - - length - - - npoints - - - pclose - - - popen - - - radius - - - width - - - Geometric Functions - - - - Function - Return Type - Description - Example - - - - - area(object) - double precision - area - area(box '((0,0),(1,1))') - - - center(object) - point - center - center(box '((0,0),(1,2))') - - - diameter(circle) - double precision - diameter of circle - diameter(circle '((0,0),2.0)') - - - height(box) - double precision - vertical size of box - height(box '((0,0),(1,1))') - - - isclosed(path) - boolean - a closed path? - isclosed(path '((0,0),(1,1),(2,0))') - - - isopen(path) - boolean - an open path? - isopen(path '[(0,0),(1,1),(2,0)]') - - - length(object) - double precision - length - length(path '((-1,0),(1,0))') - - - npoints(path) - int - number of points - npoints(path '[(0,0),(1,1),(2,0)]') - - - npoints(polygon) - int - number of points - npoints(polygon '((1,1),(0,0))') - - - pclose(path) - path - convert path to closed - pclose(path '[(0,0),(1,1),(2,0)]') - - - popen(path) - path - convert path to open - popen(path '((0,0),(1,1),(2,0))') - - - radius(circle) - double precision - radius of circle - radius(circle '((0,0),2.0)') - - - width(box) - double precision - horizontal size of box - width(box '((0,0),(1,1))') - - - + Geometric Functions + + + + + FunctionDescriptionExample(s) + + + + + + + + + area + + area ( geometric_type ) + double precision + + Computes area. + Available for box, path, circle. + A path input must be closed, else NULL is returned. + Also, if the path is self-intersecting, the result may be + meaningless. + + area(box '(2,2),(0,0)') + 4 + + + + + + + center + + center ( geometric_type ) + point + + Computes center point. + Available for box, circle. + + center(box '(1,2),(0,0)') + (0.5,1) + + + + + + + diagonal + + diagonal ( box ) + lseg + + Extracts box's diagonal as a line segment + (same as lseg(box)). + + diagonal(box '(1,2),(0,0)') + [(1,2),(0,0)] + + + + + + + diameter + + diameter ( circle ) + double precision + + Computes diameter of circle. + + diameter(circle '<(0,0),2>') + 4 + + + + + + + height + + height ( box ) + double precision + + Computes vertical size of box. + + height(box '(1,2),(0,0)') + 2 + + + + + + + isclosed + + isclosed ( path ) + boolean + + Is path closed? + + isclosed(path '((0,0),(1,1),(2,0))') + t + + + + + + + isopen + + isopen ( path ) + boolean + + Is path open? + + isopen(path '[(0,0),(1,1),(2,0)]') + t + + + + + + + length + + length ( geometric_type ) + double precision + + Computes the total length. + Available for lseg, path. + + length(path '((-1,0),(1,0))') + 4 + + + + + + + npoints + + npoints ( geometric_type ) + integer + + Returns the number of points. + Available for path, polygon. + + npoints(path '[(0,0),(1,1),(2,0)]') + 3 + + + + + + + pclose + + pclose ( path ) + path + + Converts path to closed form. + + pclose(path '[(0,0),(1,1),(2,0)]') + ((0,0),(1,1),(2,0)) + + + + + + + popen + + popen ( path ) + path + + Converts path to open form. + + popen(path '((0,0),(1,1),(2,0))') + [(0,0),(1,1),(2,0)] + + + + + + + radius + + radius ( circle ) + double precision + + Computes radius of circle. + + radius(circle '<(0,0),2>') + 2 + + + + + + + slope + + slope ( point, point ) + double precision + + Computes slope of a line drawn through the two points. + + slope(point '(0,0)', point '(2,1)') + 0.5 + + + + + + + width + + width ( box ) + double precision + + Computes horizontal size of box. + + width(box '(1,2),(0,0)') + 1 + + + +
- Geometric Type Conversion Functions - - - - Function - Return Type - Description - Example - - - - - - - box - - box(circle) - - box - circle to box - box(circle '((0,0),2.0)') - - - box(point) - box - point to empty box - box(point '(0,0)') - - - box(point, point) - box - points to box - box(point '(0,0)', point '(1,1)') - - - box(polygon) - box - polygon to box - box(polygon '((0,0),(1,1),(2,0))') - - - bound_box(box, box) - box - boxes to bounding box - bound_box(box '((0,0),(1,1))', box '((3,3),(4,4))') - - - - - circle - - circle(box) - - circle - box to circle - circle(box '((0,0),(1,1))') - - - circle(point, double precision) - circle - center and radius to circle - circle(point '(0,0)', 2.0) - - - circle(polygon) - circle - polygon to circle - circle(polygon '((0,0),(1,1),(2,0))') - - - line(point, point) - line - points to line - line(point '(-1,0)', point '(1,0)') - - - - - lseg - - lseg(box) - - lseg - box diagonal to line segment - lseg(box '((-1,0),(1,0))') - - - lseg(point, point) - lseg - points to line segment - lseg(point '(-1,0)', point '(1,0)') - - - - - path - - path(polygon) - - path - polygon to path - path(polygon '((0,0),(1,1),(2,0))') - - - - - point - - point(double - precision, double precision) - - point - construct point - point(23.4, -44.5) - - - point(box) - point - center of box - point(box '((-1,0),(1,0))') - - - point(circle) - point - center of circle - point(circle '((0,0),2.0)') - - - point(lseg) - point - center of line segment - point(lseg '((-1,0),(1,0))') - - - point(polygon) - point - center of polygon - point(polygon '((0,0),(1,1),(2,0))') - - - - - polygon - - polygon(box) - - polygon - box to 4-point polygon - polygon(box '((0,0),(1,1))') - - - polygon(circle) - polygon - circle to 12-point polygon - polygon(circle '((0,0),2.0)') - - - polygon(npts, circle) - polygon - circle to npts-point polygon - polygon(12, circle '((0,0),2.0)') - - - polygon(path) - polygon - path to polygon - polygon(path '((0,0),(1,1),(2,0))') - - - + Geometric Type Conversion Functions + + + + + FunctionDescriptionExample(s) + + + + + + + + + box + + box ( circle ) + box + + Computes box inscribed within the circle. + + box(circle '<(0,0),2>') + (1.414213562373095,1.414213562373095),&zwsp;(-1.414213562373095,-1.414213562373095) + + + + + + box ( point ) + box + + Converts point to empty box. + + box(point '(1,0)') + (1,0),(1,0) + + + + + + box ( point, point ) + box + + Converts any two corner points to box. + + box(point '(0,1)', point '(1,0)') + (1,1),(0,0) + + + + + + box ( polygon ) + box + + Computes bounding box of polygon. + + box(polygon '((0,0),(1,1),(2,0))') + (2,1),(0,0) + + + + + + + bound_box + + bound_box ( box, box ) + box + + Computes bounding box of two boxes. + + bound_box(box '(1,1),(0,0)', box '(4,4),(3,3)') + (4,4),(0,0) + + + + + + + circle + + circle ( box ) + circle + + Computes smallest circle enclosing box. + + circle(box '(1,1),(0,0)') + <(0.5,0.5),0.7071067811865476> + + + + + + circle ( point, double precision ) + circle + + Constructs circle from center and radius. + + circle(point '(0,0)', 2.0) + <(0,0),2> + + + + + + circle ( polygon ) + circle + + Converts polygon to circle. The circle's center is the mean of the + positions of the polygon's points, and the radius is the average + distance of the polygon's points from that center. + + circle(polygon '((0,0),(1,3),(2,0))') + <(1,1),1.6094757082487299> + + + + + + + line + + line ( point, point ) + line + + Converts two points to the line through them. + + line(point '(-1,0)', point '(1,0)') + {0,-1,0} + + + + + + + lseg + + lseg ( box ) + lseg + + Extracts box's diagonal as a line segment. + + lseg(box '(1,0),(-1,0)') + [(1,0),(-1,0)] + + + + + + lseg ( point, point ) + lseg + + Constructs line segment from two endpoints. + + lseg(point '(-1,0)', point '(1,0)') + [(-1,0),(1,0)] + + + + + + + path + + path ( polygon ) + path + + Converts polygon to a closed path with the same list of points. + + path(polygon '((0,0),(1,1),(2,0))') + ((0,0),(1,1),(2,0)) + + + + + + + point + + point ( double precision, double precision ) + point + + Constructs point from its coordinates. + + point(23.4, -44.5) + (23.4,-44.5) + + + + + + point ( box ) + point + + Computes center of box. + + point(box '(1,0),(-1,0)') + (0,0) + + + + + + point ( circle ) + point + + Computes center of circle. + + point(circle '<(0,0),2>') + (0,0) + + + + + + point ( lseg ) + point + + Computes center of line segment. + + point(lseg '[(-1,0),(1,0)]') + (0,0) + + + + + + point ( polygon ) + point + + Computes center of polygon (the mean of the + positions of the polygon's points). + + point(polygon '((0,0),(1,1),(2,0))') + (1,0.3333333333333333) + + + + + + + polygon + + polygon ( box ) + polygon + + Converts box to a 4-point polygon. + + polygon(box '(1,1),(0,0)') + ((0,0),(0,1),(1,1),(1,0)) + + + + + + polygon ( circle ) + polygon + + Converts circle to a 12-point polygon. + + polygon(circle '<(0,0),2>') + ((-2,0),&zwsp;(-1.7320508075688774,0.9999999999999999),&zwsp;(-1.0000000000000002,1.7320508075688772),&zwsp;(-1.2246063538223773e-16,2),&zwsp;(0.9999999999999996,1.7320508075688774),&zwsp;(1.732050807568877,1.0000000000000007),&zwsp;(2,2.4492127076447545e-16),&zwsp;(1.7320508075688776,-0.9999999999999994),&zwsp;(1.0000000000000009,-1.7320508075688767),&zwsp;(3.673819061467132e-16,-2),&zwsp;(-0.9999999999999987,-1.732050807568878),&zwsp;(-1.7320508075688767,-1.0000000000000009)) + + + + + + polygon ( integer, circle ) + polygon + + Converts circle to an n-point polygon. + + polygon(4, circle '<(3,0),1>') + ((2,0),&zwsp;(3,1),&zwsp;(4,1.2246063538223773e-16),&zwsp;(3,-1)) + + + + + + polygon ( path ) + polygon + + Converts closed path to a polygon with the same list of points. + + polygon(path '((0,0),(1,1),(2,0))') + ((0,0),(1,1),(2,0)) + + + + +
@@ -9951,22 +10563,6 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple as an array of two point values. - - The area function works for the types - box, circle, and path. - The area function only works on the - path data type if the points in the - path are non-intersecting. For example, the - path - '((0,0),(0,1),(2,1),(2,2),(1,2),(1,0),(0,0))'::PATH - will not work; however, the following visually identical - path - '((0,0),(0,1),(1,1),(1,2),(2,2),(2,1),(1,1),(1,0),(0,0))'::PATH - will work. If the concept of an intersecting versus - non-intersecting path is confusing, draw both of the - above paths side by side on a piece of graph paper. - -