aboutsummaryrefslogtreecommitdiff
path: root/anglerange.cpp
diff options
context:
space:
mode:
authorAndreas Grois <andreas.grois@jku.at>2015-11-10 13:39:56 +0100
committerAndreas Grois <andreas.grois@jku.at>2015-11-10 13:39:56 +0100
commitfc46d20e8411fe4b67269733f69d8a9dded4a42f (patch)
treea3de639d552dd78ecdebc8cac8d703e3eb6bad4b /anglerange.cpp
parent4aa67d78e9238a65eb94a762328465e2541fd4c4 (diff)
Add angle sets (disjoint ranges) - initial support
By adding a new angleset class, things get much easier to read. Also, the part of the previous commit that dealt with combining the individual ranges was kind of stupid. Things missing: o) functions to remove angle ranges from a set o) deferred add functions, that allow adding multiple ranges without calling the O(n²) function angleset::combine() in between.
Diffstat (limited to 'anglerange.cpp')
-rw-r--r--anglerange.cpp227
1 files changed, 221 insertions, 6 deletions
diff --git a/anglerange.cpp b/anglerange.cpp
index 7dda2e9..c62f760 100644
--- a/anglerange.cpp
+++ b/anglerange.cpp
@@ -43,6 +43,8 @@ anglerange::anglerange()
upperborder = angleclass(0.0);
upperset = false;
lowerset = false;
+ fullcircle= false;
+ sortby = SRT_SIZE;
}
anglerange::anglerange(const angleclass &lower, const angleclass &upper)
@@ -51,6 +53,8 @@ anglerange::anglerange(const angleclass &lower, const angleclass &upper)
upperborder = upper;
upperset = true;
lowerset = true;
+ fullcircle = false;
+ sortby = SRT_SIZE;
}
bool anglerange::isempty() const
@@ -84,17 +88,81 @@ void anglerange::setempty()
{
upperset = false;
lowerset = false;
- lowerborder = 0.0;
- upperborder = 0.0;
+ fullcircle = false;
+// lowerborder = 0.0;
+// upperborder = 0.0;
+//commented out, as users (I) should not rely on this.
+}
+
+void anglerange::setsorttype(const anglerange::sorttype value)
+{
+ sortby=value;
+}
+
+const anglerange::sorttype anglerange::getsorttype()
+{
+ return(sortby);
+}
+
+bool anglerange::iscircle() const
+{
+ return(fullcircle && !isempty());
+}
+
+void anglerange::setcircle(bool value)
+{
+ if(value)
+ {
+ lowerset=true;
+ upperset=true;
+ lowerborder=0.0;
+ upperborder=0.0;
+ }
+ fullcircle=value;
+}
+
+bool anglerange::isinside(const angleclass &val) const
+{
+ if(isempty())
+ {
+ return(false);
+ }
+ else
+ {
+ if(fullcircle)
+ {
+ return(true);
+ }
+ else if(lowerborder>upperborder)
+ {
+ return((val>=lowerborder || val<=upperborder));
+ }
+ else
+ {
+ return(val>=lowerborder && val<=upperborder);
+ }
+ }
}
anglerange anglerange::overlap(const anglerange &other)
{
//storage for the return value:
anglerange retval; //anglerange constructor without arguments: emtpy range [0:0]
+ retval.setsorttype(sortby); //return value inherits current sorttype.
//first: if one of the input ranges is empty, don't do anything, leave retval empty!
+
if(!(isempty()) && !(other.isempty()))
{
+ //special treatment if one of the ranges is a full circle:
+ if(fullcircle)
+ {
+ retval = other;
+ retval.setsorttype(sortby);
+ }
+ else if(other.fullcircle)
+ {
+ retval = *this;
+ }
//Here we need to take care to always follow the counter-clockwise convention.
//This leaves us with four possibilities:
//a) Both ranges contain the zero-line
@@ -103,7 +171,7 @@ anglerange anglerange::overlap(const anglerange &other)
//d) Both ranges are regular.
//first check if this range contains the zero-line
- if(lowerborder>upperborder)
+ else if(lowerborder>upperborder)
{
//ok, this range is around zero. Let's check the other one too:
if(other.getlower()>other.getupper())
@@ -174,8 +242,19 @@ anglerange anglerange::overlap(const anglerange &other)
anglerange anglerange::combine(const anglerange &other)
{
anglerange retval;
+ retval.setsorttype(sortby); //return value inherits current sorttype.
//check if any of the ranges is empty. If yes: return an empty range as well.
if(!(isempty()) && !(other.isempty())){
+ //again: special treatment if one of the ranges is a full circle:
+ if(fullcircle)
+ {
+ retval = *this;
+ }
+ if(other.fullcircle)
+ {
+ retval = other;
+ retval.setsorttype(sortby);
+ }
//Here we need to take care to always follow the counter-clockwise convention.
//This leaves us with four possibilities:
//a) Both ranges contain the zero-line
@@ -184,14 +263,23 @@ anglerange anglerange::combine(const anglerange &other)
//d) Both ranges are regular.
//first check if this range contains the zero-line
- if(lowerborder>upperborder)
+ else if(lowerborder>upperborder)
{
//ok, this range is around zero. Let's check the other one too:
if(other.getlower()>other.getupper())
{
//ok, both ranges contain the zero-line.
- retval.setlower(fmin(lowerborder.getval(),other.getlower().getval()));
- retval.setupper(fmax(upperborder.getval(),other.getupper().getval()));
+ //let's see if the result is a full circle
+ if(lowerborder<=other.upperborder || other.lowerborder <=upperborder)
+ {
+ //full circle
+ retval.setcircle(true);
+ }
+ else
+ {
+ retval.setlower(fmin(lowerborder.getval(),other.getlower().getval()));
+ retval.setupper(fmax(upperborder.getval(),other.getupper().getval()));
+ }
}
else
{
@@ -203,6 +291,11 @@ anglerange anglerange::combine(const anglerange &other)
retval.setlower(lowerborder);
retval.setupper(upperborder);
}
+ //again: check if result is a full circle
+ else if(other.lowerborder<=upperborder && other.upperborder>=lowerborder)
+ {
+ retval.setcircle(true);
+ }
else if(other.getupper()>=lowerborder) //not >, as per definition upperborder is inside range
{
retval.setlower(other.getlower());
@@ -226,6 +319,11 @@ anglerange anglerange::combine(const anglerange &other)
retval.setlower(other.getlower());
retval.setupper(other.getupper());
}
+ //full circle?
+ else if(lowerborder <= other.getupper() && upperborder >= other.getlower())
+ {
+ retval.setcircle(true);
+ }
else if(lowerborder <= other.getupper())
{
retval.setlower(other.getlower());
@@ -239,6 +337,7 @@ anglerange anglerange::combine(const anglerange &other)
}
else //both ranges regular
{
+ //this also means: none of them contains zero, the result cannot be a full circle
//check if there's an overlap
double curmax = fmin(other.getupper().getval(),upperborder.getval());
double curmin = fmax(other.getlower().getval(),lowerborder.getval());
@@ -252,3 +351,119 @@ anglerange anglerange::combine(const anglerange &other)
}
return(retval);
}
+
+bool anglerange::operator<(const anglerange &other) const
+{
+ if(isempty() || other.isempty())
+ {
+ return(false);
+ }
+ else
+ {
+ switch(sortby)
+ {
+ case SRT_LOWER:
+ return(lowerborder < other.lowerborder);
+ break;
+ case SRT_UPPER:
+ return(upperborder < other.upperborder);
+ break;
+ case SRT_SIZE:
+ //I know that this if elseif thing can be written as a single statement. This is for readability.
+ if(other.fullcircle)
+ {
+ return(!fullcircle);
+ }
+ else if(fullcircle)
+ {
+ return(false);
+ }
+ else
+ {
+ //angleclass takes care of zero crossing. C++ is awesome.
+ return(upperborder - lowerborder < other.upperborder - other.lowerborder);
+ }
+ break;
+ default:
+ throw std::out_of_range("Invalid sort field set for anglerange! Go, debug.\n");
+ }
+ }
+}
+
+bool anglerange::operator>(const anglerange &other) const
+{
+ //as == doesn't care about sort order but fully compares, we have to implement two sort operators fully...
+ if(isempty() || other.isempty())
+ {
+ return(false);
+ }
+ else
+ {
+ switch(sortby)
+ {
+ case SRT_LOWER:
+ return(lowerborder > other.lowerborder);
+ break;
+ case SRT_UPPER:
+ return(upperborder > other.upperborder);
+ break;
+ case SRT_SIZE:
+ if(fullcircle)
+ {
+ return(!other.fullcircle);
+ }
+ else if(other.fullcircle)
+ {
+ return(false);
+ }
+ else
+ {
+ //angleclass takes care of zero crossing. C++ is awesome.
+ return(upperborder - lowerborder > other.upperborder - other.lowerborder);
+ }
+ break;
+ default:
+ throw std::out_of_range("Invalid sort field set for anglerange! Go, debug.\n");
+ }
+ }
+}
+
+bool anglerange::operator<=(const anglerange &other) const
+{
+ if(isempty() || other.isempty())
+ {
+ return(false);
+ }
+ else
+ {
+ return(!(operator>(other)));
+ }
+}
+bool anglerange::operator>=(const anglerange &other) const
+{
+ if(isempty() || other.isempty())
+ {
+ return(false);
+ }
+ else
+ {
+ return(!(operator<(other)));
+ }
+}
+
+
+bool anglerange::operator==(const anglerange &other) const
+{
+ if(!(isempty()) && !(other.isempty()))
+ {
+ //both ranges set, we need to compare field by field
+ return( (lowerborder == other.lowerborder) && (upperborder == other.upperborder) );
+ }
+ else
+ return(isempty() && other.isempty());
+}
+bool anglerange::operator!=(const anglerange &other) const
+{
+ //needn't check for isempty here, as == already checks for it.
+ return(!operator==(other));
+}