/* * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES) * * This file is part of Orfeo Toolbox * * https://www.orfeo-toolbox.org/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef otbPolygon_hxx #define otbPolygon_hxx #include "otbPolygon.h" namespace otb { template void Polygon::AddVertex(const ContinuousIndexType& vertex) { Superclass::AddVertex(vertex); m_AreaIsValid = false; } /** * Check whether point is strictly inside the polygon. * \param point The point to check. * \return True if the point is inside the polygon. */ template bool Polygon::IsInside(VertexType point) const { double x = point[0]; double y = point[1]; unsigned int crossingCount = 0; VertexListConstIteratorType it = this->GetVertexList()->Begin(); double xa = it.Value()[0]; double ya = it.Value()[1]; ++it; while (it != this->GetVertexList()->End()) { double xb = it.Value()[0]; double yb = it.Value()[1]; if (std::abs(xb - xa) < m_Epsilon) { if (ya > yb && xa > x && y >= yb && y < ya) { ++crossingCount; } else if (ya < yb && xa > x && y >= ya && y < yb) { ++crossingCount; } } else if (std::abs(yb - ya) >= m_Epsilon) { double xcross = xa + (xb - xa) * (y - ya) / (yb - ya); if (ya > yb && xcross > x && y >= yb && y < ya) { ++crossingCount; } else if (ya < yb && xcross > x && y >= ya && y < yb) { ++crossingCount; } } xa = xb; ya = yb; ++it; } double xb = this->GetVertexList()->Begin().Value()[0]; double yb = this->GetVertexList()->Begin().Value()[1]; if (std::abs(xb - xa) < m_Epsilon) { if (ya > yb && xa > x && y >= yb && y < ya) { ++crossingCount; } else if (ya < yb && xa > x && y >= ya && y < yb) { ++crossingCount; } } else if (std::abs(yb - ya) >= m_Epsilon) { double xcross = xa + (xb - xa) * (y - ya) / (yb - ya); if (ya > yb && xcross > x && y >= yb && y < ya) { ++crossingCount; } else if (ya < yb && xcross > x && y >= ya && y < yb) { ++crossingCount; } } // std::cout<<"Crossing count: "< bool Polygon::IsOnEdge(VertexType point) const { // std::cout<<"Checking point "<GetVertexList()->Begin(); double xa = it.Value()[0]; double ya = it.Value()[1]; double xbegin = xa; double ybegin = ya; ++it; while (!resp && it != this->GetVertexList()->End()) { xb = it.Value()[0]; yb = it.Value()[1]; if (std::abs(xb - xa) >= m_Epsilon) { double cd = (yb - ya) / (xb - xa); double oo = (ya - cd * xa); double xmin = std::min(xa, xb); double xmax = std::max(xa, xb); if ((std::abs(y - cd * x - oo) < m_Epsilon) && (x <= xmax) && (x >= xmin)) { // std::cout<<"Case 1: Point is on segment "< "<= ymin)) { resp = true; // std::cout<<"Case 2: Point is on segment "< "<= m_Epsilon) { double cd = (yb - ya) / (xb - xa); double oo = (ya - cd * xa); double xmin = std::min(xa, xb); double xmax = std::max(xa, xb); if ((std::abs(y - cd * x - oo) < m_Epsilon) && (x <= xmax) && (x >= xmin)) { resp = true; // std::cout<<"Case 1: Point is on segment "< "<= ymin)) { resp = true; // std::cout<<"Case 2: Point is on segment "< "< unsigned int Polygon::NbCrossing(VertexType a, VertexType b) const { unsigned int resp = 0; VertexListConstIteratorType it = this->GetVertexList()->Begin(); VertexListConstIteratorType it_end = this->GetVertexList()->End(); VertexType current = it.Value(); VertexType first = current; ++it; while (it != it_end) { // std::cout<<"Testing Is crossing "< "< "< bool Polygon::IsCrossing(VertexType a1, VertexType a2, VertexType b1, VertexType b2) const { 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 (std::abs(a1[0] - a2[0]) < m_Epsilon && std::abs(b1[0] - b2[0]) < m_Epsilon) { resp = false; } else if (std::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; resp = (xbmin < a1[0] && xbmax > a1[0] && yamin < ycross && yamax > ycross); } else if (std::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; resp = (xamin < b1[0] && xamax > b1[0] && ybmin < ycross && ybmax > ycross); } else { 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) { double xcross = (oo2 - oo1) / (cd1 - cd2); resp = (xamin < xcross && xbmin < xcross && xamax > xcross && xbmax > xcross); } } return resp; } /** * Check whether 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 bool Polygon::IsTouching(VertexType a1, VertexType a2, VertexType b1, VertexType b2) const { 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 (std::abs(a1[0] - a2[0]) < m_Epsilon && std::abs(b1[0] - b2[0]) < m_Epsilon) { resp = (std::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 (std::abs(a1[0] - a2[0]) < m_Epsilon) { double cd2 = (b2[1] - b1[1]) / (b2[0] - b1[0]); double oo2 = b1[1] - cd2 * b1[0]; if (std::abs(a1[1] - cd2 * a1[0] - oo2) < m_Epsilon) { resp = (a1[0] >= xbmin && a1[0] <= xbmax); } else if (std::abs(a2[1] - cd2 * a2[0] - oo2) < m_Epsilon) { resp = (a2[0] >= xbmin && a2[0] <= xbmax); } } else if (std::abs(b1[0] - b2[0]) < m_Epsilon) { double cd1 = (a2[1] - a1[1]) / (a2[0] - a1[0]); double oo1 = a1[1] - cd1 * a1[0]; if (std::abs(b1[1] - cd1 * b1[0] - oo1) < m_Epsilon) { resp = (b1[0] >= xamin && b1[0] <= xamax); } else if (std::abs(b2[1] - cd1 * b2[0] - oo1) < m_Epsilon) { resp = (b2[0] >= xamin && b2[0] <= xamax); } } else { 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 (std::abs(cd1 - cd2) < m_Epsilon && std::abs(oo1 - oo2) < m_Epsilon) { resp = ((xamin <= xbmax && xamin >= xbmin) || (xamax <= xbmax && xamax >= xbmin) || (xbmin <= xamax && xbmin >= xamin) || (xbmax <= xamax && xbmax >= xamin)); } else { if (std::abs(a1[1] - cd2 * a1[0] - oo2) < m_Epsilon) { resp = (a1[0] >= xbmin && a1[0] <= xbmax); } else if (std::abs(a2[1] - cd2 * a2[0] - oo2) < m_Epsilon) { resp = (a2[0] >= xbmin && a2[0] <= xbmax); } if (std::abs(b1[1] - cd1 * b1[0] - oo1) < m_Epsilon) { resp = (b1[0] >= xamin && b1[0] <= xamax); } else if (std::abs(b2[1] - cd1 * b2[0] - oo1) < m_Epsilon) { resp = (b2[0] >= xamin && b2[0] <= xamax); } } } return resp; } /** * Area computation (for non convex polygons as well) */ template void Polygon::ComputeArea() const { VertexListConstIteratorType it = this->GetVertexList()->Begin(); if (this->GetVertexList()->Size() > 2) { double area = 0.0; VertexType origin = it.Value(); ++it; VertexType pt1 = it.Value(); VertexType pt2 = it.Value(); while (it != this->GetVertexList()->End()) { pt1 = pt2; pt2 = it.Value(); double vector1x = pt1[0] - origin[0]; double vector1y = pt1[1] - origin[1]; double vector2x = pt2[0] - origin[0]; double vector2y = pt2[1] - origin[1]; double crossProdduct = vector1x * vector2y - vector2x * vector1y; area += crossProdduct; ++it; } m_Area = fabs(area / 2.0); } else // if there is strictly less than 3 points, surface is 0 { m_Area = 0.0; } m_AreaIsValid = true; } /** * Get surface */ template double Polygon::GetArea() const { if (!m_AreaIsValid) { ComputeArea(); } return m_Area; } /** * Length computation (difference with path is in the last addition) */ template double Polygon::GetLength() const { double length = 0.0; VertexListConstIteratorType it = this->GetVertexList()->Begin(); VertexType origin = it.Value(); if (this->GetVertexList()->Size() > 1) { VertexType pt1 = it.Value(); // just init, won't be used like that VertexType pt2 = it.Value(); ++it; while (it != this->GetVertexList()->End()) { 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]); } length += std::sqrt(accum); ++it; } // Adding the last segment (between first and last point) double accum = 0.0; for (int i = 0; i < 2; ++i) { accum += (origin[i] - pt2[i]) * (origin[i] - pt2[i]); } length += std::sqrt(accum); } else // if there is strictly less than 2 points, length is 0 { length = 0.0; } return length; } template void Polygon::Modified() const { Superclass::Modified(); m_AreaIsValid = false; } /** * PrintSelf Method */ template void Polygon::PrintSelf(std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf(os, indent); } } // End namespace otb #endif