class_docstr: A plane is a flat, two-dimensional surface. A plane is the two-dimensional
  analogue of a point (zero-dimensions), a line (one-dimension) and a solid
  (three-dimensions). A plane can generally be constructed by two types of
  inputs. They are:
  - three non-collinear points
  - a point and the plane's normal vector
  
  Attributes
  ==========
  
  p1
  normal_vector
  
  Examples
  ========
  
  >>> from sympy import Plane, Point3D
  >>> Plane(Point3D(1, 1, 1), Point3D(2, 3, 4), Point3D(2, 2, 2))
  Plane(Point3D(1, 1, 1), (-1, 2, -1))
  >>> Plane((1, 1, 1), (2, 3, 4), (2, 2, 2))
  Plane(Point3D(1, 1, 1), (-1, 2, -1))
  >>> Plane(Point3D(1, 1, 1), normal_vector=(1,4,7))
  Plane(Point3D(1, 1, 1), (1, 4, 7))
docstr: Return a perpendicular passing through the given points. If the
  direction ratio between the points is the same as the Plane's normal
  vector then, to select from the infinite number of possible planes,
  a third point will be chosen on the z-axis (or the y-axis
  if the normal vector is already parallel to the z-axis). If less than
  two points are given they will be supplied as follows: if no point is
  given then pt1 will be self.p1; if a second point is not given it will
  be a point through pt1 on a line parallel to the z-axis (if the normal
  is not already the z-axis, otherwise on the line parallel to the
  y-axis).
  
  Parameters
  ==========
  
  pts: 0, 1 or 2 Point3D
  
  Returns
  =======
  
  Plane
  
  Examples
  ========
  
  >>> from sympy import Plane, Point3D
  >>> a, b = Point3D(0, 0, 0), Point3D(0, 1, 0)
  >>> Z = (0, 0, 1)
  >>> p = Plane(a, normal_vector=Z)
  >>> p.perpendicular_plane(a, b)
  Plane(Point3D(0, 0, 0), (1, 0, 0))
code: def perpendicular_plane(self, *pts):
      """
      Return a perpendicular passing through the given points. If the
      direction ratio between the points is the same as the Plane's normal
      vector then, to select from the infinite number of possible planes,
      a third point will be chosen on the z-axis (or the y-axis
      if the normal vector is already parallel to the z-axis). If less than
      two points are given they will be supplied as follows: if no point is
      given then pt1 will be self.p1; if a second point is not given it will
      be a point through pt1 on a line parallel to the z-axis (if the normal
      is not already the z-axis, otherwise on the line parallel to the
      y-axis).
  
      Parameters
      ==========
  
      pts: 0, 1 or 2 Point3D
  
      Returns
      =======
  
      Plane
  
      Examples
      ========
  
      >>> from sympy import Plane, Point3D
      >>> a, b = Point3D(0, 0, 0), Point3D(0, 1, 0)
      >>> Z = (0, 0, 1)
      >>> p = Plane(a, normal_vector=Z)
      >>> p.perpendicular_plane(a, b)
      Plane(Point3D(0, 0, 0), (1, 0, 0))
      """
      if len(pts) > 2:
          raise ValueError("No more than 2 pts should be provided.")
  
      pts = list(pts)
      if len(pts) == 0:
          pts.append(self.p1)
      if len(pts) == 1:
          x, y, z = self.normal_vector
          if x == y == 0:
              dir = (0, 1, 0)
          else:
              dir = (0, 0, 1)
          pts.append(pts[0] + Point3D(*dir))
  
      p1, p2 = [Point(i, dim=3) for i in pts]
      l = Line3D(p1, p2)
      n = Line3D(p1, direction_ratio=self.normal_vector)
      if l in n:  # XXX should an error be raised instead?
          # there are infinitely many perpendicular planes;
          x, y, z = self.normal_vector
          if x == y == 0:
              # the z axis is the normal so pick a pt on the y-axis
              p3 = Point3D(0, 1, 0)  # case 1
          else:
              # else pick a pt on the z axis
              p3 = Point3D(0, 0, 1)  # case 2
          # in case that point is already given, move it a bit
          if p3 in l:
              p3 *= 2  # case 3
      else:
          p3 = p1 + Point3D(*self.normal_vector)  # case 4
      return Plane(p1, p2, p3)
  
imports: from sympy.core import Dummy, Rational, S, Symbol
  from sympy.core.symbol import _symbol
  from sympy.functions.elementary.trigonometric import cos, sin, acos, asin, sqrt
  from .entity import GeometryEntity
  from .line import Line, Ray, Segment, Line3D, LinearEntity, LinearEntity3D, Ray3D, Segment3D
  from .point import Point, Point3D
  from sympy.matrices import Matrix
  from sympy.polys.polytools import cancel
  from sympy.solvers import solve, linsolve
  from sympy.utilities.iterables import uniq, is_sequence
  from sympy.utilities.misc import filldedent, func_name, Undecidable
  from mpmath.libmp.libmpf import prec_to_dps
  import random
label_desc: Use image node_id 18 for calling the Plane obj's underlying member method code with example usage: obj.perpendicular_plane() and returns: Plane