| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641 | 
							- """The definition of the base geometrical entity with attributes common to
 
- all derived geometrical entities.
 
- Contains
 
- ========
 
- GeometryEntity
 
- GeometricSet
 
- Notes
 
- =====
 
- A GeometryEntity is any object that has special geometric properties.
 
- A GeometrySet is a superclass of any GeometryEntity that can also
 
- be viewed as a sympy.sets.Set.  In particular, points are the only
 
- GeometryEntity not considered a Set.
 
- Rn is a GeometrySet representing n-dimensional Euclidean space. R2 and
 
- R3 are currently the only ambient spaces implemented.
 
- """
 
- from __future__ import annotations
 
- from sympy.core.basic import Basic
 
- from sympy.core.containers import Tuple
 
- from sympy.core.evalf import EvalfMixin, N
 
- from sympy.core.numbers import oo
 
- from sympy.core.symbol import Dummy
 
- from sympy.core.sympify import sympify
 
- from sympy.functions.elementary.trigonometric import cos, sin, atan
 
- from sympy.matrices import eye
 
- from sympy.multipledispatch import dispatch
 
- from sympy.printing import sstr
 
- from sympy.sets import Set, Union, FiniteSet
 
- from sympy.sets.handlers.intersection import intersection_sets
 
- from sympy.sets.handlers.union import union_sets
 
- from sympy.solvers.solvers import solve
 
- from sympy.utilities.misc import func_name
 
- from sympy.utilities.iterables import is_sequence
 
- # How entities are ordered; used by __cmp__ in GeometryEntity
 
- ordering_of_classes = [
 
-     "Point2D",
 
-     "Point3D",
 
-     "Point",
 
-     "Segment2D",
 
-     "Ray2D",
 
-     "Line2D",
 
-     "Segment3D",
 
-     "Line3D",
 
-     "Ray3D",
 
-     "Segment",
 
-     "Ray",
 
-     "Line",
 
-     "Plane",
 
-     "Triangle",
 
-     "RegularPolygon",
 
-     "Polygon",
 
-     "Circle",
 
-     "Ellipse",
 
-     "Curve",
 
-     "Parabola"
 
- ]
 
- x, y = [Dummy('entity_dummy') for i in range(2)]
 
- T = Dummy('entity_dummy', real=True)
 
- class GeometryEntity(Basic, EvalfMixin):
 
-     """The base class for all geometrical entities.
 
-     This class does not represent any particular geometric entity, it only
 
-     provides the implementation of some methods common to all subclasses.
 
-     """
 
-     __slots__: tuple[str, ...] = ()
 
-     def __cmp__(self, other):
 
-         """Comparison of two GeometryEntities."""
 
-         n1 = self.__class__.__name__
 
-         n2 = other.__class__.__name__
 
-         c = (n1 > n2) - (n1 < n2)
 
-         if not c:
 
-             return 0
 
-         i1 = -1
 
-         for cls in self.__class__.__mro__:
 
-             try:
 
-                 i1 = ordering_of_classes.index(cls.__name__)
 
-                 break
 
-             except ValueError:
 
-                 i1 = -1
 
-         if i1 == -1:
 
-             return c
 
-         i2 = -1
 
-         for cls in other.__class__.__mro__:
 
-             try:
 
-                 i2 = ordering_of_classes.index(cls.__name__)
 
-                 break
 
-             except ValueError:
 
-                 i2 = -1
 
-         if i2 == -1:
 
-             return c
 
-         return (i1 > i2) - (i1 < i2)
 
-     def __contains__(self, other):
 
-         """Subclasses should implement this method for anything more complex than equality."""
 
-         if type(self) is type(other):
 
-             return self == other
 
-         raise NotImplementedError()
 
-     def __getnewargs__(self):
 
-         """Returns a tuple that will be passed to __new__ on unpickling."""
 
-         return tuple(self.args)
 
-     def __ne__(self, o):
 
-         """Test inequality of two geometrical entities."""
 
-         return not self == o
 
-     def __new__(cls, *args, **kwargs):
 
-         # Points are sequences, but they should not
 
-         # be converted to Tuples, so use this detection function instead.
 
-         def is_seq_and_not_point(a):
 
-             # we cannot use isinstance(a, Point) since we cannot import Point
 
-             if hasattr(a, 'is_Point') and a.is_Point:
 
-                 return False
 
-             return is_sequence(a)
 
-         args = [Tuple(*a) if is_seq_and_not_point(a) else sympify(a) for a in args]
 
-         return Basic.__new__(cls, *args)
 
-     def __radd__(self, a):
 
-         """Implementation of reverse add method."""
 
-         return a.__add__(self)
 
-     def __rtruediv__(self, a):
 
-         """Implementation of reverse division method."""
 
-         return a.__truediv__(self)
 
-     def __repr__(self):
 
-         """String representation of a GeometryEntity that can be evaluated
 
-         by sympy."""
 
-         return type(self).__name__ + repr(self.args)
 
-     def __rmul__(self, a):
 
-         """Implementation of reverse multiplication method."""
 
-         return a.__mul__(self)
 
-     def __rsub__(self, a):
 
-         """Implementation of reverse subtraction method."""
 
-         return a.__sub__(self)
 
-     def __str__(self):
 
-         """String representation of a GeometryEntity."""
 
-         return type(self).__name__ + sstr(self.args)
 
-     def _eval_subs(self, old, new):
 
-         from sympy.geometry.point import Point, Point3D
 
-         if is_sequence(old) or is_sequence(new):
 
-             if isinstance(self, Point3D):
 
-                 old = Point3D(old)
 
-                 new = Point3D(new)
 
-             else:
 
-                 old = Point(old)
 
-                 new = Point(new)
 
-             return  self._subs(old, new)
 
-     def _repr_svg_(self):
 
-         """SVG representation of a GeometryEntity suitable for IPython"""
 
-         try:
 
-             bounds = self.bounds
 
-         except (NotImplementedError, TypeError):
 
-             # if we have no SVG representation, return None so IPython
 
-             # will fall back to the next representation
 
-             return None
 
-         if not all(x.is_number and x.is_finite for x in bounds):
 
-             return None
 
-         svg_top = '''<svg xmlns="http://www.w3.org/2000/svg"
 
-             xmlns:xlink="http://www.w3.org/1999/xlink"
 
-             width="{1}" height="{2}" viewBox="{0}"
 
-             preserveAspectRatio="xMinYMin meet">
 
-             <defs>
 
-                 <marker id="markerCircle" markerWidth="8" markerHeight="8"
 
-                     refx="5" refy="5" markerUnits="strokeWidth">
 
-                     <circle cx="5" cy="5" r="1.5" style="stroke: none; fill:#000000;"/>
 
-                 </marker>
 
-                 <marker id="markerArrow" markerWidth="13" markerHeight="13" refx="2" refy="4"
 
-                        orient="auto" markerUnits="strokeWidth">
 
-                     <path d="M2,2 L2,6 L6,4" style="fill: #000000;" />
 
-                 </marker>
 
-                 <marker id="markerReverseArrow" markerWidth="13" markerHeight="13" refx="6" refy="4"
 
-                        orient="auto" markerUnits="strokeWidth">
 
-                     <path d="M6,2 L6,6 L2,4" style="fill: #000000;" />
 
-                 </marker>
 
-             </defs>'''
 
-         # Establish SVG canvas that will fit all the data + small space
 
-         xmin, ymin, xmax, ymax = map(N, bounds)
 
-         if xmin == xmax and ymin == ymax:
 
-             # This is a point; buffer using an arbitrary size
 
-             xmin, ymin, xmax, ymax = xmin - .5, ymin -.5, xmax + .5, ymax + .5
 
-         else:
 
-             # Expand bounds by a fraction of the data ranges
 
-             expand = 0.1  # or 10%; this keeps arrowheads in view (R plots use 4%)
 
-             widest_part = max([xmax - xmin, ymax - ymin])
 
-             expand_amount = widest_part * expand
 
-             xmin -= expand_amount
 
-             ymin -= expand_amount
 
-             xmax += expand_amount
 
-             ymax += expand_amount
 
-         dx = xmax - xmin
 
-         dy = ymax - ymin
 
-         width = min([max([100., dx]), 300])
 
-         height = min([max([100., dy]), 300])
 
-         scale_factor = 1. if max(width, height) == 0 else max(dx, dy) / max(width, height)
 
-         try:
 
-             svg = self._svg(scale_factor)
 
-         except (NotImplementedError, TypeError):
 
-             # if we have no SVG representation, return None so IPython
 
-             # will fall back to the next representation
 
-             return None
 
-         view_box = "{} {} {} {}".format(xmin, ymin, dx, dy)
 
-         transform = "matrix(1,0,0,-1,0,{})".format(ymax + ymin)
 
-         svg_top = svg_top.format(view_box, width, height)
 
-         return svg_top + (
 
-             '<g transform="{}">{}</g></svg>'
 
-             ).format(transform, svg)
 
-     def _svg(self, scale_factor=1., fill_color="#66cc99"):
 
-         """Returns SVG path element for the GeometryEntity.
 
-         Parameters
 
-         ==========
 
-         scale_factor : float
 
-             Multiplication factor for the SVG stroke-width.  Default is 1.
 
-         fill_color : str, optional
 
-             Hex string for fill color. Default is "#66cc99".
 
-         """
 
-         raise NotImplementedError()
 
-     def _sympy_(self):
 
-         return self
 
-     @property
 
-     def ambient_dimension(self):
 
-         """What is the dimension of the space that the object is contained in?"""
 
-         raise NotImplementedError()
 
-     @property
 
-     def bounds(self):
 
-         """Return a tuple (xmin, ymin, xmax, ymax) representing the bounding
 
-         rectangle for the geometric figure.
 
-         """
 
-         raise NotImplementedError()
 
-     def encloses(self, o):
 
-         """
 
-         Return True if o is inside (not on or outside) the boundaries of self.
 
-         The object will be decomposed into Points and individual Entities need
 
-         only define an encloses_point method for their class.
 
-         See Also
 
-         ========
 
-         sympy.geometry.ellipse.Ellipse.encloses_point
 
-         sympy.geometry.polygon.Polygon.encloses_point
 
-         Examples
 
-         ========
 
-         >>> from sympy import RegularPolygon, Point, Polygon
 
-         >>> t  = Polygon(*RegularPolygon(Point(0, 0), 1, 3).vertices)
 
-         >>> t2 = Polygon(*RegularPolygon(Point(0, 0), 2, 3).vertices)
 
-         >>> t2.encloses(t)
 
-         True
 
-         >>> t.encloses(t2)
 
-         False
 
-         """
 
-         from sympy.geometry.point import Point
 
-         from sympy.geometry.line import Segment, Ray, Line
 
-         from sympy.geometry.ellipse import Ellipse
 
-         from sympy.geometry.polygon import Polygon, RegularPolygon
 
-         if isinstance(o, Point):
 
-             return self.encloses_point(o)
 
-         elif isinstance(o, Segment):
 
-             return all(self.encloses_point(x) for x in o.points)
 
-         elif isinstance(o, (Ray, Line)):
 
-             return False
 
-         elif isinstance(o, Ellipse):
 
-             return self.encloses_point(o.center) and \
 
-                 self.encloses_point(
 
-                 Point(o.center.x + o.hradius, o.center.y)) and \
 
-                 not self.intersection(o)
 
-         elif isinstance(o, Polygon):
 
-             if isinstance(o, RegularPolygon):
 
-                 if not self.encloses_point(o.center):
 
-                     return False
 
-             return all(self.encloses_point(v) for v in o.vertices)
 
-         raise NotImplementedError()
 
-     def equals(self, o):
 
-         return self == o
 
-     def intersection(self, o):
 
-         """
 
-         Returns a list of all of the intersections of self with o.
 
-         Notes
 
-         =====
 
-         An entity is not required to implement this method.
 
-         If two different types of entities can intersect, the item with
 
-         higher index in ordering_of_classes should implement
 
-         intersections with anything having a lower index.
 
-         See Also
 
-         ========
 
-         sympy.geometry.util.intersection
 
-         """
 
-         raise NotImplementedError()
 
-     def is_similar(self, other):
 
-         """Is this geometrical entity similar to another geometrical entity?
 
-         Two entities are similar if a uniform scaling (enlarging or
 
-         shrinking) of one of the entities will allow one to obtain the other.
 
-         Notes
 
-         =====
 
-         This method is not intended to be used directly but rather
 
-         through the `are_similar` function found in util.py.
 
-         An entity is not required to implement this method.
 
-         If two different types of entities can be similar, it is only
 
-         required that one of them be able to determine this.
 
-         See Also
 
-         ========
 
-         scale
 
-         """
 
-         raise NotImplementedError()
 
-     def reflect(self, line):
 
-         """
 
-         Reflects an object across a line.
 
-         Parameters
 
-         ==========
 
-         line: Line
 
-         Examples
 
-         ========
 
-         >>> from sympy import pi, sqrt, Line, RegularPolygon
 
-         >>> l = Line((0, pi), slope=sqrt(2))
 
-         >>> pent = RegularPolygon((1, 2), 1, 5)
 
-         >>> rpent = pent.reflect(l)
 
-         >>> rpent
 
-         RegularPolygon(Point2D(-2*sqrt(2)*pi/3 - 1/3 + 4*sqrt(2)/3, 2/3 + 2*sqrt(2)/3 + 2*pi/3), -1, 5, -atan(2*sqrt(2)) + 3*pi/5)
 
-         >>> from sympy import pi, Line, Circle, Point
 
-         >>> l = Line((0, pi), slope=1)
 
-         >>> circ = Circle(Point(0, 0), 5)
 
-         >>> rcirc = circ.reflect(l)
 
-         >>> rcirc
 
-         Circle(Point2D(-pi, pi), -5)
 
-         """
 
-         from sympy.geometry.point import Point
 
-         g = self
 
-         l = line
 
-         o = Point(0, 0)
 
-         if l.slope.is_zero:
 
-             v = l.args[0].y
 
-             if not v:  # x-axis
 
-                 return g.scale(y=-1)
 
-             reps = [(p, p.translate(y=2*(v - p.y))) for p in g.atoms(Point)]
 
-         elif l.slope is oo:
 
-             v = l.args[0].x
 
-             if not v:  # y-axis
 
-                 return g.scale(x=-1)
 
-             reps = [(p, p.translate(x=2*(v - p.x))) for p in g.atoms(Point)]
 
-         else:
 
-             if not hasattr(g, 'reflect') and not all(
 
-                     isinstance(arg, Point) for arg in g.args):
 
-                 raise NotImplementedError(
 
-                     'reflect undefined or non-Point args in %s' % g)
 
-             a = atan(l.slope)
 
-             c = l.coefficients
 
-             d = -c[-1]/c[1]  # y-intercept
 
-             # apply the transform to a single point
 
-             xf = Point(x, y)
 
-             xf = xf.translate(y=-d).rotate(-a, o).scale(y=-1
 
-                 ).rotate(a, o).translate(y=d)
 
-             # replace every point using that transform
 
-             reps = [(p, xf.xreplace({x: p.x, y: p.y})) for p in g.atoms(Point)]
 
-         return g.xreplace(dict(reps))
 
-     def rotate(self, angle, pt=None):
 
-         """Rotate ``angle`` radians counterclockwise about Point ``pt``.
 
-         The default pt is the origin, Point(0, 0)
 
-         See Also
 
-         ========
 
-         scale, translate
 
-         Examples
 
-         ========
 
-         >>> from sympy import Point, RegularPolygon, Polygon, pi
 
-         >>> t = Polygon(*RegularPolygon(Point(0, 0), 1, 3).vertices)
 
-         >>> t # vertex on x axis
 
-         Triangle(Point2D(1, 0), Point2D(-1/2, sqrt(3)/2), Point2D(-1/2, -sqrt(3)/2))
 
-         >>> t.rotate(pi/2) # vertex on y axis now
 
-         Triangle(Point2D(0, 1), Point2D(-sqrt(3)/2, -1/2), Point2D(sqrt(3)/2, -1/2))
 
-         """
 
-         newargs = []
 
-         for a in self.args:
 
-             if isinstance(a, GeometryEntity):
 
-                 newargs.append(a.rotate(angle, pt))
 
-             else:
 
-                 newargs.append(a)
 
-         return type(self)(*newargs)
 
-     def scale(self, x=1, y=1, pt=None):
 
-         """Scale the object by multiplying the x,y-coordinates by x and y.
 
-         If pt is given, the scaling is done relative to that point; the
 
-         object is shifted by -pt, scaled, and shifted by pt.
 
-         See Also
 
-         ========
 
-         rotate, translate
 
-         Examples
 
-         ========
 
-         >>> from sympy import RegularPolygon, Point, Polygon
 
-         >>> t = Polygon(*RegularPolygon(Point(0, 0), 1, 3).vertices)
 
-         >>> t
 
-         Triangle(Point2D(1, 0), Point2D(-1/2, sqrt(3)/2), Point2D(-1/2, -sqrt(3)/2))
 
-         >>> t.scale(2)
 
-         Triangle(Point2D(2, 0), Point2D(-1, sqrt(3)/2), Point2D(-1, -sqrt(3)/2))
 
-         >>> t.scale(2, 2)
 
-         Triangle(Point2D(2, 0), Point2D(-1, sqrt(3)), Point2D(-1, -sqrt(3)))
 
-         """
 
-         from sympy.geometry.point import Point
 
-         if pt:
 
-             pt = Point(pt, dim=2)
 
-             return self.translate(*(-pt).args).scale(x, y).translate(*pt.args)
 
-         return type(self)(*[a.scale(x, y) for a in self.args])  # if this fails, override this class
 
-     def translate(self, x=0, y=0):
 
-         """Shift the object by adding to the x,y-coordinates the values x and y.
 
-         See Also
 
-         ========
 
-         rotate, scale
 
-         Examples
 
-         ========
 
-         >>> from sympy import RegularPolygon, Point, Polygon
 
-         >>> t = Polygon(*RegularPolygon(Point(0, 0), 1, 3).vertices)
 
-         >>> t
 
-         Triangle(Point2D(1, 0), Point2D(-1/2, sqrt(3)/2), Point2D(-1/2, -sqrt(3)/2))
 
-         >>> t.translate(2)
 
-         Triangle(Point2D(3, 0), Point2D(3/2, sqrt(3)/2), Point2D(3/2, -sqrt(3)/2))
 
-         >>> t.translate(2, 2)
 
-         Triangle(Point2D(3, 2), Point2D(3/2, sqrt(3)/2 + 2), Point2D(3/2, 2 - sqrt(3)/2))
 
-         """
 
-         newargs = []
 
-         for a in self.args:
 
-             if isinstance(a, GeometryEntity):
 
-                 newargs.append(a.translate(x, y))
 
-             else:
 
-                 newargs.append(a)
 
-         return self.func(*newargs)
 
-     def parameter_value(self, other, t):
 
-         """Return the parameter corresponding to the given point.
 
-         Evaluating an arbitrary point of the entity at this parameter
 
-         value will return the given point.
 
-         Examples
 
-         ========
 
-         >>> from sympy import Line, Point
 
-         >>> from sympy.abc import t
 
-         >>> a = Point(0, 0)
 
-         >>> b = Point(2, 2)
 
-         >>> Line(a, b).parameter_value((1, 1), t)
 
-         {t: 1/2}
 
-         >>> Line(a, b).arbitrary_point(t).subs(_)
 
-         Point2D(1, 1)
 
-         """
 
-         from sympy.geometry.point import Point
 
-         if not isinstance(other, GeometryEntity):
 
-             other = Point(other, dim=self.ambient_dimension)
 
-         if not isinstance(other, Point):
 
-             raise ValueError("other must be a point")
 
-         sol = solve(self.arbitrary_point(T) - other, T, dict=True)
 
-         if not sol:
 
-             raise ValueError("Given point is not on %s" % func_name(self))
 
-         return {t: sol[0][T]}
 
- class GeometrySet(GeometryEntity, Set):
 
-     """Parent class of all GeometryEntity that are also Sets
 
-     (compatible with sympy.sets)
 
-     """
 
-     __slots__ = ()
 
-     def _contains(self, other):
 
-         """sympy.sets uses the _contains method, so include it for compatibility."""
 
-         if isinstance(other, Set) and other.is_FiniteSet:
 
-             return all(self.__contains__(i) for i in other)
 
-         return self.__contains__(other)
 
- @dispatch(GeometrySet, Set)  # type:ignore # noqa:F811
 
- def union_sets(self, o): # noqa:F811
 
-     """ Returns the union of self and o
 
-     for use with sympy.sets.Set, if possible. """
 
-     # if its a FiniteSet, merge any points
 
-     # we contain and return a union with the rest
 
-     if o.is_FiniteSet:
 
-         other_points = [p for p in o if not self._contains(p)]
 
-         if len(other_points) == len(o):
 
-             return None
 
-         return Union(self, FiniteSet(*other_points))
 
-     if self._contains(o):
 
-         return self
 
-     return None
 
- @dispatch(GeometrySet, Set)  # type: ignore # noqa:F811
 
- def intersection_sets(self, o): # noqa:F811
 
-     """ Returns a sympy.sets.Set of intersection objects,
 
-     if possible. """
 
-     from sympy.geometry.point import Point
 
-     try:
 
-         # if o is a FiniteSet, find the intersection directly
 
-         # to avoid infinite recursion
 
-         if o.is_FiniteSet:
 
-             inter = FiniteSet(*(p for p in o if self.contains(p)))
 
-         else:
 
-             inter = self.intersection(o)
 
-     except NotImplementedError:
 
-         # sympy.sets.Set.reduce expects None if an object
 
-         # doesn't know how to simplify
 
-         return None
 
-     # put the points in a FiniteSet
 
-     points = FiniteSet(*[p for p in inter if isinstance(p, Point)])
 
-     non_points = [p for p in inter if not isinstance(p, Point)]
 
-     return Union(*(non_points + [points]))
 
- def translate(x, y):
 
-     """Return the matrix to translate a 2-D point by x and y."""
 
-     rv = eye(3)
 
-     rv[2, 0] = x
 
-     rv[2, 1] = y
 
-     return rv
 
- def scale(x, y, pt=None):
 
-     """Return the matrix to multiply a 2-D point's coordinates by x and y.
 
-     If pt is given, the scaling is done relative to that point."""
 
-     rv = eye(3)
 
-     rv[0, 0] = x
 
-     rv[1, 1] = y
 
-     if pt:
 
-         from sympy.geometry.point import Point
 
-         pt = Point(pt, dim=2)
 
-         tr1 = translate(*(-pt).args)
 
-         tr2 = translate(*pt.args)
 
-         return tr1*rv*tr2
 
-     return rv
 
- def rotate(th):
 
-     """Return the matrix to rotate a 2-D point about the origin by ``angle``.
 
-     The angle is measured in radians. To Point a point about a point other
 
-     then the origin, translate the Point, do the rotation, and
 
-     translate it back:
 
-     >>> from sympy.geometry.entity import rotate, translate
 
-     >>> from sympy import Point, pi
 
-     >>> rot_about_11 = translate(-1, -1)*rotate(pi/2)*translate(1, 1)
 
-     >>> Point(1, 1).transform(rot_about_11)
 
-     Point2D(1, 1)
 
-     >>> Point(0, 0).transform(rot_about_11)
 
-     Point2D(2, 0)
 
-     """
 
-     s = sin(th)
 
-     rv = eye(3)*cos(th)
 
-     rv[0, 1] = s
 
-     rv[1, 0] = -s
 
-     rv[2, 2] = 1
 
-     return rv
 
 
  |