docs: def intersect(self, **kwargs):
          """
              Intersect a Line or Point Collection and the Shoreline
  
              Returns the point of intersection along the coastline
              Should also return a linestring buffer around the interseciton point
              so we can calculate the direction to bounce a particle.
          """
          ls = None
  
          if "linestring" in kwargs:
              ls = kwargs.pop('linestring')
              spoint = Point(ls.coords[0])
              epoint = Point(ls.coords[-1])
          elif "start_point" and "end_point" in kwargs:
              spoint = kwargs.get('start_point')
              epoint = kwargs.get('end_point')
              ls = LineString(list(spoint.coords) + list(epoint.coords))
          elif "single_point" in kwargs:
              spoint = kwargs.get('single_point')
              epoint = None
              ls = LineString(list(spoint.coords) + list(spoint.coords))
          else:
              raise TypeError( "must provide a LineString geometry object, (2) Point geometry objects, or (1) Point geometry object" )
  
          inter = False
  
          # If the current point lies outside of our current shapefile index,
          # re-query the shapefile in a buffer around this point
          if self._spatial_query_object is None or (self._spatial_query_object and not ls.within(self._spatial_query_object)):
              self.index(point=spoint)
  
          for element in self._geoms:
              prepped_element = prep(element)
  
              # Test if starting on land
              if prepped_element.contains(spoint):
                  if epoint is None:
                      # If we only passed in one point, return the intersection is true.
                      return {'point': spoint, 'feature': None}
                  else:
                      # If we are testing a linestring, raise an exception that we started on land.
                      raise Exception('Starting point on land: %s %s %s' % (spoint.envelope, epoint.envelope, element.envelope))
              else:
                  # If we are just checking a single point, continue looping.
                  if epoint is None:
                      continue
  
              inter = ls.intersection(element)
              if inter:
                  # Return the first point in the linestring, and the linestring that it hit
                  if isinstance(inter, MultiLineString):
                      inter = inter.geoms[0]
  
                  inter = Point(inter.coords[0])
                  smaller_int = inter.buffer(self._spatialbuffer)
                  shorelines = element.exterior.intersection(smaller_int)
                  if isinstance(shorelines, LineString):
                      shorelines = [shorelines]
                  else:
                      shorelines = list(shorelines)
  
                  for shore_segment in shorelines:
                      # Once we find the linestring in the Polygon that was
                      # intersected, break out and return
                      if ls.touches(shore_segment):
                          break
  
                  return {'point': Point(inter.x, inter.y, 0), 'feature': shore_segment or None}
          return None