class_docstr: Represents a planar graph with its planar embedding.
  
  The planar embedding is given by a `combinatorial embedding
  <https://en.wikipedia.org/wiki/Graph_embedding#Combinatorial_embedding>`_.
  
  .. note:: `check_planarity` is the preferred way to check if a graph is planar.
  
  **Neighbor ordering:**
  
  In comparison to a usual graph structure, the embedding also stores the
  order of all neighbors for every vertex.
  The order of the neighbors can be given in clockwise (cw) direction or
  counterclockwise (ccw) direction. This order is stored as edge attributes
  in the underlying directed graph. For the edge (u, v) the edge attribute
  'cw' is set to the neighbor of u that follows immediately after v in
  clockwise direction.
  
  In order for a PlanarEmbedding to be valid it must fulfill multiple
  conditions. It is possible to check if these conditions are fulfilled with
  the method :meth:`check_structure`.
  The conditions are:
  
  * Edges must go in both directions (because the edge attributes differ)
  * Every edge must have a 'cw' and 'ccw' attribute which corresponds to a
    correct planar embedding.
  
  As long as a PlanarEmbedding is invalid only the following methods should
  be called:
  
  * :meth:`add_half_edge`
  * :meth:`connect_components`
  
  Even though the graph is a subclass of nx.DiGraph, it can still be used
  for algorithms that require undirected graphs, because the method
  :meth:`is_directed` is overridden. This is possible, because a valid
  PlanarGraph must have edges in both directions.
  
  **Half edges:**
  
  In methods like `add_half_edge` the term "half-edge" is used, which is
  a term that is used in `doubly connected edge lists
  <https://en.wikipedia.org/wiki/Doubly_connected_edge_list>`_. It is used
  to emphasize that the edge is only in one direction and there exists
  another half-edge in the opposite direction.
  While conventional edges always have two faces (including outer face) next
  to them, it is possible to assign each half-edge *exactly one* face.
  For a half-edge (u, v) that is oriented such that u is below v then the
  face that belongs to (u, v) is to the right of this half-edge.
  
  See Also
  --------
  is_planar :
      Preferred way to check if an existing graph is planar.
  
  check_planarity :
      A convenient way to create a `PlanarEmbedding`. If not planar,
      it returns a subgraph that shows this.
  
  Examples
  --------
  
  Create an embedding of a star graph (compare `nx.star_graph(3)`):
  
  >>> G = nx.PlanarEmbedding()
  >>> G.add_half_edge(0, 1)
  >>> G.add_half_edge(0, 2, ccw=1)
  >>> G.add_half_edge(0, 3, ccw=2)
  >>> G.add_half_edge(1, 0)
  >>> G.add_half_edge(2, 0)
  >>> G.add_half_edge(3, 0)
  
  Alternatively the same embedding can also be defined in counterclockwise
  orientation. The following results in exactly the same PlanarEmbedding:
  
  >>> G = nx.PlanarEmbedding()
  >>> G.add_half_edge(0, 1)
  >>> G.add_half_edge(0, 3, cw=1)
  >>> G.add_half_edge(0, 2, cw=3)
  >>> G.add_half_edge(1, 0)
  >>> G.add_half_edge(2, 0)
  >>> G.add_half_edge(3, 0)
  
  After creating a graph, it is possible to validate that the PlanarEmbedding
  object is correct:
  
  >>> G.check_structure()
class_docstr_tok: ["Represents","a","planar","graph","with","its","planar","embedding",".","The","planar","embedding","is","given","by","a","`","combinatorial","embedding","<","https",":","\/\/en.wikipedia.org\/wiki\/Graph_embedding","#","Combinatorial_embedding",">","`","_",".","..","note",":",":","`","check_planarity","`","is","the","preferred","way","to","check","if","a","graph","is","planar",".","*","*","Neighbor","ordering",":","*","*","In","comparison","to","a","usual","graph","structure",",","the","embedding","also","stores","the","order","of","all","neighbors","for","every","vertex",".","The","order","of","the","neighbors","can","be","given","in","clockwise","(","cw",")","direction","or","counterclockwise","(","ccw",")","direction",".","This","order","is","stored","as","edge","attributes","in","the","underlying","directed","graph",".","For","the","edge","(","u",",","v",")","the","edge","attribute","'cw","'","is","set","to","the","neighbor","of","u","that","follows","immediately","after","v","in","clockwise","direction",".","In","order","for","a","PlanarEmbedding","to","be","valid","it","must","fulfill","multiple","conditions",".","It","is","possible","to","check","if","these","conditions","are","fulfilled","with","the","method",":","meth",":","`","check_structure","`",".","The","conditions","are",":","*","Edges","must","go","in","both","directions","(","because","the","edge","attributes","differ",")","*","Every","edge","must","have","a","'cw","'","and","'ccw","'","attribute","which","corresponds","to","a","correct","planar","embedding",".","As","long","as","a","PlanarEmbedding","is","invalid","only","the","following","methods","should","be","called",":","*",":","meth",":","`","add_half_edge","`","*",":","meth",":","`","connect_components","`","Even","though","the","graph","is","a","subclass","of","nx.DiGraph",",","it","can","still","be","used","for","algorithms","that","require","undirected","graphs",",","because","the","method",":","meth",":","`","is_directed","`","is","overridden",".","This","is","possible",",","because","a","valid","PlanarGraph","must","have","edges","in","both","directions",".","*","*","Half","edges",":","*","*","In","methods","like","`","add_half_edge","`","the","term","``","half-edge","''","is","used",",","which","is","a","term","that","is","used","in","`","doubly","connected","edge","lists","<","https",":","\/\/en.wikipedia.org\/wiki\/Doubly_connected_edge_list",">","`","_",".","It","is","used","to","emphasize","that","the","edge","is","only","in","one","direction","and","there","exists","another","half-edge","in","the","opposite","direction",".","While","conventional","edges","always","have","two","faces","(","including","outer","face",")","next","to","them",",","it","is","possible","to","assign","each","half-edge","*","exactly","one","*","face",".","For","a","half-edge","(","u",",","v",")","that","is","oriented","such","that","u","is","below","v","then","the","face","that","belongs","to","(","u",",","v",")","is","to","the","right","of","this","half-edge",".","See","Also","--","--","--","--","is_planar",":","Preferred","way","to","check","if","an","existing","graph","is","planar",".","check_planarity",":","A","convenient","way","to","create","a","`","PlanarEmbedding","`",".","If","not","planar",",","it","returns","a","subgraph","that","shows","this",".","Examples","--","--","--","--","Create","an","embedding","of","a","star","graph","(","compare","`","nx.star_graph","(","3",")","`",")",":",">",">",">","G","=","nx.PlanarEmbedding","(",")",">",">",">","G.add_half_edge","(","0",",","1",")",">",">",">","G.add_half_edge","(","0",",","2",",","ccw=1",")",">",">",">","G.add_half_edge","(","0",",","3",",","ccw=2",")",">",">",">","G.add_half_edge","(","1",",","0",")",">",">",">","G.add_half_edge","(","2",",","0",")",">",">",">","G.add_half_edge","(","3",",","0",")","Alternatively","the","same","embedding","can","also","be","defined","in","counterclockwise","orientation",".","The","following","results","in","exactly","the","same","PlanarEmbedding",":",">",">",">","G","=","nx.PlanarEmbedding","(",")",">",">",">","G.add_half_edge","(","0",",","1",")",">",">",">","G.add_half_edge","(","0",",","3",",","cw=1",")",">",">",">","G.add_half_edge","(","0",",","2",",","cw=3",")",">",">",">","G.add_half_edge","(","1",",","0",")",">",">",">","G.add_half_edge","(","2",",","0",")",">",">",">","G.add_half_edge","(","3",",","0",")","After","creating","a","graph",",","it","is","possible","to","validate","that","the","PlanarEmbedding","object","is","correct",":",">",">",">","G.check_structure","(",")"]
docstr: Adds a half-edge from `start_node` to `end_node`.
  
  If the half-edge is not the first one out of `start_node`, a reference
  node must be provided either in the clockwise (parameter `cw`) or in
  the counterclockwise (parameter `ccw`) direction. Only one of `cw`/`ccw`
  can be specified (or neither in the case of the first edge).
  Note that specifying a reference in the clockwise (`cw`) direction means
  inserting the new edge in the first counterclockwise position with
  respect to the reference (and vice-versa).
  
  Parameters
  ----------
  start_node : node
      Start node of inserted edge.
  end_node : node
      End node of inserted edge.
  cw, ccw: node
      End node of reference edge.
      Omit or pass `None` if adding the first out-half-edge of `start_node`.
  
  
  Raises
  ------
  NetworkXException
      If the `cw` or `ccw` node is not a successor of `start_node`.
      If `start_node` has successors, but neither `cw` or `ccw` is provided.
      If both `cw` and `ccw` are specified.
  
  See Also
  --------
  connect_components
docstr_tok: ["Adds","a","half-edge","from","`","start_node","`","to","`","end_node","`",".","If","the","half-edge","is","not","the","first","one","out","of","`","start_node","`",",","a","reference","node","must","be","provided","either","in","the","clockwise","(","parameter","`","cw","`",")","or","in","the","counterclockwise","(","parameter","`","ccw","`",")","direction",".","Only","one","of","`","cw","`","\/","`","ccw","`","can","be","specified","(","or","neither","in","the","case","of","the","first","edge",")",".","Note","that","specifying","a","reference","in","the","clockwise","(","`","cw","`",")","direction","means","inserting","the","new","edge","in","the","first","counterclockwise","position","with","respect","to","the","reference","(","and","vice-versa",")",".","Parameters","--","--","--","--","--","start_node",":","node","Start","node","of","inserted","edge",".","end_node",":","node","End","node","of","inserted","edge",".","cw",",","ccw",":","node","End","node","of","reference","edge",".","Omit","or","pass","`","None","`","if","adding","the","first","out-half-edge","of","`","start_node","`",".","Raises","--","--","--","NetworkXException","If","the","`","cw","`","or","`","ccw","`","node","is","not","a","successor","of","`","start_node","`",".","If","`","start_node","`","has","successors",",","but","neither","`","cw","`","or","`","ccw","`","is","provided",".","If","both","`","cw","`","and","`","ccw","`","are","specified",".","See","Also","--","--","--","--","connect_components"]
code: def add_half_edge(self, start_node, end_node, *, cw=None, ccw=None):
      """Adds a half-edge from `start_node` to `end_node`.
  
      If the half-edge is not the first one out of `start_node`, a reference
      node must be provided either in the clockwise (parameter `cw`) or in
      the counterclockwise (parameter `ccw`) direction. Only one of `cw`/`ccw`
      can be specified (or neither in the case of the first edge).
      Note that specifying a reference in the clockwise (`cw`) direction means
      inserting the new edge in the first counterclockwise position with
      respect to the reference (and vice-versa).
  
      Parameters
      ----------
      start_node : node
          Start node of inserted edge.
      end_node : node
          End node of inserted edge.
      cw, ccw: node
          End node of reference edge.
          Omit or pass `None` if adding the first out-half-edge of `start_node`.
  
  
      Raises
      ------
      NetworkXException
          If the `cw` or `ccw` node is not a successor of `start_node`.
          If `start_node` has successors, but neither `cw` or `ccw` is provided.
          If both `cw` and `ccw` are specified.
  
      See Also
      --------
      connect_components
      """
  
      succs = self._succ.get(start_node)
      if succs:
          # there is already some edge out of start_node
          leftmost_nbr = next(reversed(self._succ[start_node]))
          if cw is not None:
              if cw not in succs:
                  raise nx.NetworkXError(
                      "Invalid clockwise reference node."
                  )
              if ccw is not None:
                  raise nx.NetworkXError(
                      "Only one of cw/ccw can be specified."
                  )
              ref_ccw = succs[cw]["ccw"]
              super().add_edge(start_node, end_node, cw=cw, ccw=ref_ccw)
              succs[ref_ccw]["cw"] = end_node
              succs[cw]["ccw"] = end_node
              # when (cw == leftmost_nbr), the newly added neighbor is
              # already at the end of dict self._succ[start_node] and
              # takes the place of the former leftmost_nbr
              move_leftmost_nbr_to_end = cw != leftmost_nbr
          elif ccw is not None:
              if ccw not in succs:
                  raise nx.NetworkXError(
                      "Invalid counterclockwise reference node."
                  )
              ref_cw = succs[ccw]["cw"]
              super().add_edge(start_node, end_node, cw=ref_cw, ccw=ccw)
              succs[ref_cw]["ccw"] = end_node
              succs[ccw]["cw"] = end_node
              move_leftmost_nbr_to_end = True
          else:
              raise nx.NetworkXError(
                  "Node already has out-half-edge(s), either cw or ccw reference node required."
              )
          if move_leftmost_nbr_to_end:
              # LRPlanarity (via self.add_half_edge_first()) requires that
              # we keep track of the leftmost neighbor, which we accomplish
              # by keeping it as the last key in dict self._succ[start_node]
              succs[leftmost_nbr] = succs.pop(leftmost_nbr)
  
      else:
          if cw is not None or ccw is not None:
              raise nx.NetworkXError("Invalid reference node.")
          # adding the first edge out of start_node
          super().add_edge(
              start_node, end_node, ccw=end_node, cw=end_node
          )
  
imports: from collections import defaultdict
  import networkx
label_desc: Use image node_id 8 for calling the PlanarEmbedding obj's underlying member method code with example usage: obj.add_half_edge(start_node, end_node) without return types