Skip to content
Snippets Groups Projects
otbPolygon.txx 14.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*=========================================================================
    
    
      Program:   ORFEO Toolbox
      Language:  C++
      Date:      $Date$
      Version:   $Revision$
    
      Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
    
      See OTBCopyright.txt for details.
    
         This software is distributed WITHOUT ANY WARRANTY; without even
         the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
    
         PURPOSE.  See the above copyright notices for more information.
    
    
    =========================================================================*/
    
    #ifndef __otbPolygon_txx
    #define __otbPolygon_txx
    
    
    template<class TValue>
    void
    Polygon<TValue>
    
    OTB Bot's avatar
    OTB Bot committed
    ::AddVertex(const ContinuousIndexType& vertex)
    
    {
      Superclass::AddVertex(vertex);
    
    OTB Bot's avatar
    OTB Bot committed
      m_AreaIsValid = false;
    
    /**
     * Check wether point is strictly inside the polygon.
     * \param point The point to check.
     * \return True if the point is inside the polygon.
     */
    
    ::IsInside(VertexType point) const
    
    OTB Bot's avatar
    OTB Bot committed
      double                      x = point[0];
      double                      y = point[1];
      unsigned int                crossingCount = 0;
    
      VertexListConstIteratorType it = this->GetVertexList()->Begin();
    
    OTB Bot's avatar
    OTB Bot committed
      double                      xa = it.Value()[0];
      double                      ya = it.Value()[1];
    
      while (it != this->GetVertexList()->End())
    
    OTB Bot's avatar
    OTB Bot committed
        {
    
        double xb = it.Value()[0];
        double yb = it.Value()[1];
    
    OTB Bot's avatar
    OTB Bot committed
        if (vcl_abs(xb - xa) < m_Epsilon)
    
    OTB Bot's avatar
    OTB Bot committed
          if (ya > yb && xa > x && y >= yb && y < ya)
            {
    
            ++crossingCount;
    
    OTB Bot's avatar
    OTB Bot committed
            }
          else if (ya < yb && xa > x && y >= ya && y < yb)
            {
    
            ++crossingCount;
    
    OTB Bot's avatar
    OTB Bot committed
            }
    
    OTB Bot's avatar
    OTB Bot committed
        else if (vcl_abs(yb - ya) >= m_Epsilon)
    
    OTB Bot's avatar
    OTB Bot committed
          double xcross = xa + (xb - xa) * (y - ya) / (yb - ya);
    
          if (ya > yb && xcross > x && y >= yb && y < ya)
            {
    
            ++crossingCount;
    
    OTB Bot's avatar
    OTB Bot committed
            }
          else if (ya < yb && xcross > x && y >= ya && y < yb)
            {
    
            ++crossingCount;
    
    OTB Bot's avatar
    OTB Bot committed
            }
    
        xa = xb;
        ya = yb;
        ++it;
    
    OTB Bot's avatar
    OTB Bot committed
        }
    
      double xb = this->GetVertexList()->Begin().Value()[0];
      double yb = this->GetVertexList()->Begin().Value()[1];
    
    OTB Bot's avatar
    OTB Bot committed
      if (vcl_abs(xb - xa) < m_Epsilon)
    
    OTB Bot's avatar
    OTB Bot committed
        if (ya > yb && xa > x && y >= yb && y < ya)
          {
    
          ++crossingCount;
    
    OTB Bot's avatar
    OTB Bot committed
          }
        else if (ya < yb && xa > x && y >= ya && y < yb)
          {
    
          ++crossingCount;
    
    OTB Bot's avatar
    OTB Bot committed
          }
    
    OTB Bot's avatar
    OTB Bot committed
      else if (vcl_abs(yb - ya) >= m_Epsilon)
    
    OTB Bot's avatar
    OTB Bot committed
        double xcross = xa + (xb - xa) * (y - ya) / (yb - ya);
    
        if (ya > yb && xcross > x && y >= yb && y < ya)
          {
    
          ++crossingCount;
    
    OTB Bot's avatar
    OTB Bot committed
          }
        else if (ya < yb && xcross > x && y >= ya && y < yb)
          {
    
          ++crossingCount;
    
    OTB Bot's avatar
    OTB Bot committed
          }
    
      //std::cout<<"Crossing count: "<<crossingCount<<std::endl;
    
    OTB Bot's avatar
    OTB Bot committed
      return (crossingCount % 2 == 1);
    
    }
    
    /**
     * Check wether point is strictly on the edge of the polygon.
     * \param point The point to check.
     * \return True if the point is on the edge of the polygon.
     */
    template<class TValue>
    
    ::IsOnEdge(VertexType point) const
    
    {
      //std::cout<<"Checking point "<<point<<std::endl;
    
    OTB Bot's avatar
    OTB Bot committed
      bool                        resp = false;
      double                      x = point[0];
      double                      y = point[1];
      double                      xb, yb;
    
      VertexListConstIteratorType it = this->GetVertexList()->Begin();
    
    OTB Bot's avatar
    OTB Bot committed
      double                      xa = it.Value()[0];
      double                      ya = it.Value()[1];
      double                      xbegin = xa;
      double                      ybegin = ya;
    
      while (!resp && it != this->GetVertexList()->End())
    
    OTB Bot's avatar
    OTB Bot committed
        {
    
        xb = it.Value()[0];
        yb = it.Value()[1];
    
    OTB Bot's avatar
    OTB Bot committed
        if (vcl_abs(xb - xa) >= m_Epsilon)
    
    OTB Bot's avatar
    OTB Bot committed
          double cd = (yb - ya) / (xb - xa);
          double oo = (ya - cd * xa);
          double xmin = std::min(xa, xb);
          double xmax = std::max(xa, xb);
          if ((vcl_abs(y - cd * x - oo) < m_Epsilon)
              && (x <= xmax)
              && (x >= xmin))
            {
    
            //std::cout<<"Case 1: Point is on segment "<<xa<<", "<<ya<<" <-> "<<xb<<", "<<yb<<std::endl;
            resp = true;
    
    OTB Bot's avatar
    OTB Bot committed
            }
    
    OTB Bot's avatar
    OTB Bot committed
          double ymin = std::min(ya, yb);
          double ymax = std::max(ya, yb);
          if ((vcl_abs(x - xa) < m_Epsilon)
              && (y <= ymax)
              && (y >= ymin))
            {
    
            resp = true;
            //std::cout<<"Case 2: Point is on segment "<<xa<<", "<<ya<<" <-> "<<xb<<", "<<yb<<std::endl;
    
    OTB Bot's avatar
    OTB Bot committed
            }
    
        xa = xb;
        ya = yb;
        ++it;
    
    OTB Bot's avatar
    OTB Bot committed
        }
    
    OTB Bot's avatar
    OTB Bot committed
      if (vcl_abs(xb - xa) >= m_Epsilon)
        {
        double cd = (yb - ya) / (xb - xa);
    
        double oo = (ya - cd * xa);
    
    OTB Bot's avatar
    OTB Bot committed
        double xmin = std::min(xa, xb);
        double xmax = std::max(xa, xb);
    
    OTB Bot's avatar
    OTB Bot committed
        if ((vcl_abs(y - cd * x - oo) < m_Epsilon)
            && (x <= xmax)
            && (x >= xmin))
          {
    
          resp = true;
          //std::cout<<"Case 1: Point is on segment "<<xa<<", "<<ya<<" <-> "<<xb<<", "<<yb<<std::endl;
    
    OTB Bot's avatar
    OTB Bot committed
          }
    
    OTB Bot's avatar
    OTB Bot committed
        double ymin = std::min(ya, yb);
        double ymax = std::max(ya, yb);
        if ((vcl_abs(x - xa) <= m_Epsilon)
            && (y <= ymax)
            && (y >= ymin))
          {
    
          resp = true;
          //std::cout<<"Case 2: Point is on segment "<<xa<<", "<<ya<<" <-> "<<xb<<", "<<yb<<std::endl;
    
    OTB Bot's avatar
    OTB Bot committed
          }
    
        }
      //std::cout<<"Result: "<<resp<<std::endl;
      return resp;
    }
    /**
     * Returns the number of crossings of the polygon with a given segment.
     * \param a First point of the segment,
     * \param b Second point of the segment,
     * \return the number of strict crossings of segment [ab] with the polygon.
     */
    
    template<class TValue>
    unsigned int
    
    ::NbCrossing(VertexType a, VertexType b) const
    
    OTB Bot's avatar
    OTB Bot committed
      unsigned int                resp = 0;
    
      VertexListConstIteratorType it = this->GetVertexList()->Begin();
      VertexListConstIteratorType it_end = this->GetVertexList()->End();
    
    OTB Bot's avatar
    OTB Bot committed
      VertexType                  current = it.Value();
      VertexType                  first = current;
    
    OTB Bot's avatar
    OTB Bot committed
      while (it != it_end)
    
    OTB Bot's avatar
    OTB Bot committed
        //std::cout<<"Testing Is crossing "<<a<<" "<<b<<current<<it.Value()<<" = "<<IsCrossing(a, b, current, it.Value())<<std::endl;
    
    OTB Bot's avatar
    OTB Bot committed
        if (IsCrossing(a, b, current, it.Value()))
          {
    
    OTB Bot's avatar
    OTB Bot committed
          }
    
        current = it.Value();
        ++it;
    
    OTB Bot's avatar
    OTB Bot committed
        }
    
    OTB Bot's avatar
    OTB Bot committed
      //std::cout<<"Testing Is crossing "<<a<<" "<<b<<current<<first<<" = "<<IsCrossing(a, b, current, first)<<std::endl;
    
    OTB Bot's avatar
    OTB Bot committed
      if (IsCrossing(a, b, current, first))
        {
    
    OTB Bot's avatar
    OTB Bot committed
        }
    
      return resp;
    }
    /**
     * Returns the number of touchings without crossing of the polygon with a given segment.
     * \param a First point of the segment,
     * \param b Second point of the segment,
     * \return the number of touchings without crossing of segment [ab] with the polygon.
     */
    template<class TValue>
    
    ::NbTouching(VertexType a, VertexType b) const
    
    OTB Bot's avatar
    OTB Bot committed
      unsigned int                resp = 0;
    
      VertexListConstIteratorType it = this->GetVertexList()->Begin();
      VertexListConstIteratorType it_end = this->GetVertexList()->End();
    
    OTB Bot's avatar
    OTB Bot committed
      VertexType                  current = it.Value();
      VertexType                  first = current;
    
    OTB Bot's avatar
    OTB Bot committed
      while (it != it_end)
    
    OTB Bot's avatar
    OTB Bot committed
        //std::cout<<"IsTouching "<<a<<" "<<b<<", "<<current<<" "<<it.Value()<<" -> "<<IsTouching(a, b, current, it.Value())<<std::endl;
    
    OTB Bot's avatar
    OTB Bot committed
        if (IsTouching(a, b, current, it.Value()))
          {
    
    OTB Bot's avatar
    OTB Bot committed
          }
    
        current = it.Value();
        ++it;
    
    OTB Bot's avatar
    OTB Bot committed
        }
    
    OTB Bot's avatar
    OTB Bot committed
      //std::cout<<"IsTouching "<<a<<" "<<b<<", "<<current<<" "<<first<<" -> "<<IsTouching(a, b, current, first)<<std::endl;
    
    OTB Bot's avatar
    OTB Bot committed
      if (IsTouching(a, b, current, first))
        {
    
    OTB Bot's avatar
    OTB Bot committed
        }
    
      return resp;
    }
    /**
     * Check wether two segments [a1a2] and [b1b2] are strictly crossing.
     * \param a1 First point of the first segment,
     * \param a1 Second point of the first segment,
     * \param a1 First point of the second segment,
     * \param a1 Second point of the second segment.
     * \return True if the two segments are strictly crossing.
     */
    template<class TValue>
    
    ::IsCrossing(VertexType a1, VertexType a2, VertexType b1, VertexType b2) const
    
    OTB Bot's avatar
    OTB Bot committed
      bool   resp = false;
      double xbmin = std::min(b1[0], b2[0]);
      double xbmax = std::max(b1[0], b2[0]);
      double ybmin = std::min(b1[1], b2[1]);
      double ybmax = std::max(b1[1], b2[1]);
      double xamin = std::min(a1[0], a2[0]);
      double xamax = std::max(a1[0], a2[0]);
      double yamin = std::min(a1[1], a2[1]);
      double yamax = std::max(a1[1], a2[1]);
      if (vcl_abs(a1[0] - a2[0]) < m_Epsilon && vcl_abs(b1[0] - b2[0]) < m_Epsilon)
        {
    
        resp = false;
    
    OTB Bot's avatar
    OTB Bot committed
        }
      else if (vcl_abs(a1[0] - a2[0]) < m_Epsilon)
        {
    
        double cd2 = (b2[1] - b1[1]) / (b2[0] - b1[0]);
        double oo2 = b1[1] - cd2 * b1[0];
        double ycross = cd2 * a1[0] + oo2;
    
    OTB Bot's avatar
    OTB Bot committed
        resp = (xbmin <a1[0] && xbmax> a1[0]
                && yamin <ycross && yamax> ycross);
        }
      else if (vcl_abs(b1[0] - b2[0]) < m_Epsilon)
        {
    
        double cd1 = (a2[1] - a1[1]) / (a2[0] - a1[0]);
        double oo1 = a1[1] - cd1 * a1[0];
        double ycross = cd1 * b1[0] + oo1;
    
    OTB Bot's avatar
    OTB Bot committed
        resp = (xamin <b1[0] && xamax> b1[0]
                && ybmin <ycross && ybmax> ycross);
        }
    
    OTB Bot's avatar
    OTB Bot committed
        {
    
        double cd1 = (a2[1] - a1[1]) / (a2[0] - a1[0]);
        double oo1 = a1[1] - cd1 * a1[0];
        double cd2 = (b2[1] - b1[1]) / (b2[0] - b1[0]);
        double oo2 = b1[1] - cd2 * b1[0];
        if (cd1 != cd2)
    
    OTB Bot's avatar
    OTB Bot committed
          {
    
          double xcross = (oo2 - oo1) / (cd1 - cd2);
    
    OTB Bot's avatar
    OTB Bot committed
          resp = (xamin <xcross  && xbmin <xcross
    
    OTB Bot's avatar
    OTB Bot committed
                          &&   xamax> xcross  && xbmax> xcross);
    
    OTB Bot's avatar
    OTB Bot committed
          }
    
        }
      return resp;
    }
    /**
     * Check wether two segments[a1a2] and [b1b2] are touching without crossing.
     * \param a1 First point of the first segment,
     * \param a1 Second point of the first segment,
     * \param a1 First point of the second segment,
     * \param a1 Second point of the second segment.
     * \return True if the two segments are touching without crossing.
     */
    
    template<class TValue>
    bool
    
    OTB Bot's avatar
    OTB Bot committed
    ::IsTouching(VertexType a1, VertexType a2, VertexType b1, VertexType b2) const
    
    OTB Bot's avatar
    OTB Bot committed
      bool   resp = false;
      double xbmin = std::min(b1[0], b2[0]);
      double xbmax = std::max(b1[0], b2[0]);
      double ybmin = std::min(b1[1], b2[1]);
      double ybmax = std::max(b1[1], b2[1]);
      double xamin = std::min(a1[0], a2[0]);
      double xamax = std::max(a1[0], a2[0]);
      double yamin = std::min(a1[1], a2[1]);
      double yamax = std::max(a1[1], a2[1]);
      if (vcl_abs(a1[0] - a2[0]) < m_Epsilon && vcl_abs(b1[0] - b2[0]) < m_Epsilon)
        {
        resp = (vcl_abs(a1[0] - b1[0]) < m_Epsilon)
               && ((a1[1] <= ybmax && a1[1] >= ybmin)
                   ||  (a2[1] <= ybmax && a2[1] >= ybmin)
                   ||  (b1[1] <= yamax && b1[1] >= yamin)
                   ||  (b2[1] <= yamax && b2[1] >= yamin));
        }
      else if (vcl_abs(a1[0] - a2[0]) < m_Epsilon)
        {
    
        double cd2 = (b2[1] - b1[1]) / (b2[0] - b1[0]);
        double oo2 = b1[1] - cd2 * b1[0];
    
    
    OTB Bot's avatar
    OTB Bot committed
        if (vcl_abs(a1[1] - cd2 * a1[0] - oo2) < m_Epsilon)
          {
          resp = (a1[0] >= xbmin && a1[0] <= xbmax);
          }
        else if (vcl_abs(a2[1] - cd2 * a2[0] - oo2) < m_Epsilon)
          {
          resp = (a2[0] >= xbmin && a2[0] <= xbmax);
          }
    
    OTB Bot's avatar
    OTB Bot committed
      else if (vcl_abs(b1[0] - b2[0]) < m_Epsilon)
    
        double cd1 = (a2[1] - a1[1]) / (a2[0] - a1[0]);
        double oo1 = a1[1] - cd1 * a1[0];
    
    
    OTB Bot's avatar
    OTB Bot committed
        if (vcl_abs(b1[1] - cd1 * b1[0] - oo1) < m_Epsilon)
          {
          resp = (b1[0] >= xamin && b1[0] <= xamax);
          }
        else if (vcl_abs(b2[1] - cd1 * b2[0] - oo1) < m_Epsilon)
          {
          resp = (b2[0] >= xamin && b2[0] <= xamax);
          }
    
    OTB Bot's avatar
    OTB Bot committed
        {
    
        double cd1 = (a2[1] - a1[1]) / (a2[0] - a1[0]);
        double oo1 = a1[1] - cd1 * a1[0];
        double cd2 = (b2[1] - b1[1]) / (b2[0] - b1[0]);
        double oo2 = b1[1] - cd2 * b1[0];
    
    OTB Bot's avatar
    OTB Bot committed
        if (vcl_abs(cd1 - cd2) < m_Epsilon && vcl_abs(oo1 - oo2) < m_Epsilon)
    
    OTB Bot's avatar
    OTB Bot committed
          resp = ((xamin <= xbmax && xamin >= xbmin)
                  ||   (xamax <= xbmax && xamax >= xbmin)
                  ||   (xbmin <= xamax && xbmin >= xamin)
                  ||   (xbmax <= xamax && xbmax >= xamin));
    
    OTB Bot's avatar
    OTB Bot committed
        else
    
    OTB Bot's avatar
    OTB Bot committed
          if (vcl_abs(a1[1] - cd2 * a1[0] - oo2) < m_Epsilon)
            {
            resp = (a1[0] >= xbmin && a1[0] <= xbmax);
            }
          else if (vcl_abs(a2[1] - cd2 * a2[0] - oo2) < m_Epsilon)
            {
            resp = (a2[0] >= xbmin && a2[0] <= xbmax);
            }
          if (vcl_abs(b1[1] - cd1 * b1[0] - oo1) < m_Epsilon)
            {
            resp = (b1[0] >= xamin && b1[0] <= xamax);
            }
          else if (vcl_abs(b2[1] - cd1 * b2[0] - oo1) < m_Epsilon)
            {
            resp = (b2[0] >= xamin && b2[0] <= xamax);
            }
    
     * Area computation (for non convex polygons as well)
    
    Polygon<TValue>
    
      VertexListConstIteratorType it =  this->GetVertexList()->Begin();
    
    OTB Bot's avatar
    OTB Bot committed
      if (this->GetVertexList()->Size() > 2)
        {
        double     area = 0.0;
    
        VertexType origin = it.Value();
    
        VertexType pt1 = it.Value();
        VertexType pt2 = it.Value();
    
        while (it != this->GetVertexList()->End())
    
    OTB Bot's avatar
    OTB Bot committed
          {
          pt1 = pt2;
    
          double vector1x = pt1[0] - origin[0];
          double vector1y = pt1[1] - origin[1];
          double vector2x = pt2[0] - origin[0];
          double vector2y = pt2[1] - origin[1];
    
    OTB Bot's avatar
    OTB Bot committed
          double crossProdduct = vector1x * vector2y - vector2x * vector1y;
    
    OTB Bot's avatar
    OTB Bot committed
          }
    
    OTB Bot's avatar
    OTB Bot committed
        m_Area = fabs(area / 2.0);
    
    OTB Bot's avatar
    OTB Bot committed
        }
    
      else //if there is strictly less than 3 points, surface is 0
    
    OTB Bot's avatar
    OTB Bot committed
        {
    
    OTB Bot's avatar
    OTB Bot committed
        }
    
    }
    
    /**
     * Get surface
     */
    template<class TValue>
    
    OTB Bot's avatar
    OTB Bot committed
    double
    Polygon<TValue>
    ::GetArea() const
    
    OTB Bot's avatar
    OTB Bot committed
        {
    
    OTB Bot's avatar
    OTB Bot committed
        }
    
     * Length computation (difference with path is in the last addition)
    
    OTB Bot's avatar
    OTB Bot committed
    template <class TValue>
    
    double Polygon<TValue>
    ::GetLength() const
    
    OTB Bot's avatar
    OTB Bot committed
      double                      length = 0.0;
    
      VertexListConstIteratorType it =  this->GetVertexList()->Begin();
    
    OTB Bot's avatar
    OTB Bot committed
      if (this->GetVertexList()->Size() > 1)
        {
    
    OTB Bot's avatar
    OTB Bot committed
        VertexType pt1 = it.Value(); //just init, won't be used like that
    
        while (it != this->GetVertexList()->End())
    
    OTB Bot's avatar
    OTB Bot committed
          pt1 = pt2;
          pt2 = it.Value();
          double accum = 0.0;
          for (int i = 0; i < 2; ++i)
            {
            accum += (pt1[i] - pt2[i]) * (pt1[i] - pt2[i]);
            }
    
    OTB Bot's avatar
    OTB Bot committed
          }
    
        //Adding the last segment (between first and last point)
    
    OTB Bot's avatar
    OTB Bot committed
        double accum = 0.0;
        for (int i = 0; i < 2; ++i)
          {
          accum += (origin[i] - pt2[i]) * (origin[i] - pt2[i]);
          }
    
    OTB Bot's avatar
    OTB Bot committed
        }
    
      else //if there is strictly less than 2 points, length is 0
    
    OTB Bot's avatar
    OTB Bot committed
        {
    
    OTB Bot's avatar
    OTB Bot committed
        }
    
    OTB Bot's avatar
    OTB Bot committed
    void
    Polygon<TValue>
    
    ::Modified() const
    
    OTB Bot's avatar
    OTB Bot committed
      m_AreaIsValid = false;
    
    /**
     * PrintSelf Method
     */
    template<class TValue>
    void
    Polygon<TValue>
    ::PrintSelf(std::ostream& os, itk::Indent indent) const
    {
      Superclass::PrintSelf(os, indent);
    }