/*
Copyrigth 2015, D. Morozov, M. Kerber, A. Nigmetov
This file is part of GeomBottleneck.
GeomBottleneck is free software: you can redistribute it and/or modify
it under the terms of the Lesser GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
GeomBottleneck is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Lesser GNU General Public License for more details.
You should have received a copy of the Lesser GNU General Public License
along with GeomBottleneck. If not, see .
*/
#include
#include
#include "def_debug_bt.h"
#include "basic_defs_bt.h"
namespace geom_bt {
// Point
bool Point::operator==(const Point& other) const
{
return ((this->x == other.x) and (this->y == other.y));
}
bool Point::operator!=(const Point& other) const
{
return !(*this == other);
}
#ifndef FOR_R_TDA
std::ostream& operator<<(std::ostream& output, const Point p)
{
output << "(" << p.x << ", " << p.y << ")";
return output;
}
std::ostream& operator<<(std::ostream& output, const PointSet& ps)
{
output << "{ ";
for(auto& p : ps) {
output << p << ", ";
}
output << "\b\b }";
return output;
}
#endif
double sqrDist(const Point& a, const Point& b)
{
return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
}
double dist(const Point& a, const Point& b)
{
return sqrt(sqrDist(a, b));
}
// DiagramPoint
// compute l-inf distance between two diagram points
double distLInf(const DiagramPoint& a, const DiagramPoint& b)
{
if ( DiagramPoint::DIAG == a.type &&
DiagramPoint::DIAG == b.type ) {
// distance between points on the diagonal is 0
return 0.0;
}
// otherwise distance is a usual l-inf distance
return std::max(fabs(a.getRealX() - b.getRealX()), fabs(a.getRealY() - b.getRealY()));
}
bool DiagramPoint::operator==(const DiagramPoint& other) const
{
assert(this->id >= MinValidId);
assert(other.id >= MinValidId);
bool areEqual{ this->id == other.id };
assert(!areEqual or ((this->x == other.x) and (this->y == other.y) and (this->type == other.type)));
return areEqual;
}
bool DiagramPoint::operator!=(const DiagramPoint& other) const
{
return !(*this == other);
}
#ifndef FOR_R_TDA
std::ostream& operator<<(std::ostream& output, const DiagramPoint p)
{
if ( p.type == DiagramPoint::DIAG ) {
output << "(" << p.x << ", " << p.y << ", " << 0.5 * (p.x + p.y) << ", " << p.id << " DIAG )";
} else {
output << "(" << p.x << ", " << p.y << ", " << p.id << " NORMAL)";
}
return output;
}
std::ostream& operator<<(std::ostream& output, const DiagramPointSet& ps)
{
output << "{ ";
for(auto pit = ps.cbegin(); pit != ps.cend(); ++pit) {
output << *pit << ", ";
}
output << "\b\b }";
return output;
}
#endif
DiagramPoint::DiagramPoint(double xx, double yy, Type ttype, IdType uid) :
x(xx),
y(yy),
type(ttype),
id(uid)
{
if ( yy == xx and ttype != DiagramPoint::DIAG)
throw std::runtime_error("Point on the main diagonal must have DIAG type");
}
void DiagramPointSet::insert(const DiagramPoint p)
{
points.insert(p);
if (p.id > maxId) {
maxId = p.id + 1;
}
}
// erase should be called only for the element of the set
void DiagramPointSet::erase(const DiagramPoint& p, bool doCheck)
{
auto it = points.find(p);
if (it != points.end()) {
points.erase(it);
} else {
assert(!doCheck);
}
}
void DiagramPointSet::reserve(const size_t newSize)
{
points.reserve(newSize);
}
void DiagramPointSet::erase(const std::unordered_set::const_iterator it)
{
points.erase(it);
}
void DiagramPointSet::clear()
{
points.clear();
}
size_t DiagramPointSet::size() const
{
return points.size();
}
bool DiagramPointSet::empty() const
{
return points.empty();
}
bool DiagramPointSet::hasElement(const DiagramPoint& p) const
{
return points.find(p) != points.end();
}
void DiagramPointSet::removeDiagonalPoints()
{
if (isLinked) {
auto ptIter = points.begin();
while(ptIter != points.end()) {
if (ptIter->isDiagonal()) {
ptIter = points.erase(ptIter);
} else {
ptIter++;
}
}
isLinked = false;
}
}
// preprocess diagrams A and B by adding projections onto diagonal of points of
// A to B and vice versa. NB: ids of points will be changed!
void addProjections(DiagramPointSet& A, DiagramPointSet& B)
{
IdType uniqueId {MinValidId + 1};
DiagramPointSet newA, newB;
// copy normal points from A to newA
// add projections to newB
for(auto& pA : A) {
if (pA.isNormal()) {
DiagramPoint dpA {pA.getRealX(), pA.getRealY(), DiagramPoint::NORMAL, uniqueId++};
DiagramPoint dpB {0.5*(pA.getRealX() +pA.getRealY()), 0.5 *(pA.getRealX() +pA.getRealY()), DiagramPoint::DIAG, uniqueId++};
newA.insert(dpA);
newB.insert(dpB);
}
}
for(auto& pB : B) {
if (pB.isNormal()) {
DiagramPoint dpB {pB.getRealX(), pB.getRealY(), DiagramPoint::NORMAL, uniqueId++};
DiagramPoint dpA {0.5*(pB.getRealX() +pB.getRealY()), 0.5 *(pB.getRealX() +pB.getRealY()), DiagramPoint::DIAG, uniqueId++};
newB.insert(dpB);
newA.insert(dpA);
}
}
A = newA;
B = newB;
A.isLinked = true;
B.isLinked = true;
}
}