aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--README.md9
-rw-r--r--angleclass.cpp42
-rw-r--r--angleclass.h22
-rw-r--r--anglerange.cpp227
-rw-r--r--anglerange.h31
-rw-r--r--angleset.cpp188
-rw-r--r--angleset.h91
-rw-r--r--main.cpp393
9 files changed, 745 insertions, 262 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 888ad9f..5add3ab 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,8 +3,8 @@ cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
-SET(CMAKE_CXX_FLAGS "-Wall ${CMAKE_CXX_FLAGS} -std=c++11")
-SET(CMAKE_CXX_FLAGS_DEBUG "-Wall ${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
+SET(CMAKE_CXX_FLAGS "-Wall ${CMAKE_CXX_FLAGS} -std=c++11 -DNDEBUG")
+SET(CMAKE_CXX_FLAGS_DEBUG "-Wall ${CMAKE_CXX_FLAGS_DEBUG} -std=c++11 -O0")
IF(UNIX)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} m)
diff --git a/README.md b/README.md
index a8ca74c..e14ca93 100644
--- a/README.md
+++ b/README.md
@@ -62,6 +62,15 @@ Both points together made writing the correct conditions for upper and lower bou
of the result ranges a pain, and I'm pretty certain there might still be the one or the other
bug hidden.
+##Compilation
+The easiest way to compile this program is by using the included cmake file. Simply run cmake,
+followed by make. The default build should use sane CFLAGS, and have the NDEBUG macro defined.
+
+If you, for whatever reason, prefer to compile manually, just link all the
+.cpp files together in one executable. If you don't want to waste a lot of processor cycles,
+make sure to define the NDEBUG macro, as otherwise some quite CPU-heavy assertion checks are in
+place. For most compilers this can be done by passing the "-DNDEBUG" command line argument.
+
##Usage
Using this program is quite easy: Just supply the input as command line parameters in this order:
a1, a2, alpha, b1min, b1max, b2min, b2max, betamin, betamax
diff --git a/angleclass.cpp b/angleclass.cpp
index e1981d1..8f30d69 100644
--- a/angleclass.cpp
+++ b/angleclass.cpp
@@ -52,58 +52,58 @@ void angleclass::setval(const double setme)
value=shiftinrange(setme);
}
-double angleclass::getval()
+double angleclass::getval() const
{
return(value);
}
-angleclass angleclass::operator *(angleclass other)
+angleclass angleclass::operator *(const angleclass other) const
{
- return(angleclass(value*other.getval()));
+ return(angleclass(value*other.value));
}
-angleclass angleclass::operator-(angleclass other)
+angleclass angleclass::operator-(const angleclass other) const
{
- return(angleclass(value-other.getval()));
+ return(angleclass(value-other.value));
}
-angleclass angleclass::operator+(angleclass other)
+angleclass angleclass::operator+(const angleclass other) const
{
- return(angleclass(value+other.getval()));
+ return(angleclass(value+other.value));
}
-angleclass angleclass::operator/(angleclass other)
+angleclass angleclass::operator/(const angleclass other) const
{
- return(angleclass(value/other.getval()));
+ return(angleclass(value/other.value));
}
-bool angleclass::operator<(angleclass other)
+bool angleclass::operator<(const angleclass other) const
{
- return(value<other.getval());
+ return(value<other.value);
}
-bool angleclass::operator>(angleclass other)
+bool angleclass::operator>(const angleclass other) const
{
- return(value>other.getval());
+ return(value>other.value);
}
-bool angleclass::operator<=(angleclass other)
+bool angleclass::operator<=(const angleclass other) const
{
- return(value<=other.getval());
+ return(value<=other.value);
}
-bool angleclass::operator>=(angleclass other)
+bool angleclass::operator>=(const angleclass other) const
{
- return(value>=other.getval());
+ return(value>=other.value);
}
-bool angleclass::operator==(angleclass other)
+bool angleclass::operator==(const angleclass other) const
{
- return(value==other.getval());
+ return(value==other.value);
}
-bool angleclass::operator!=(angleclass other)
+bool angleclass::operator!=(const angleclass other) const
{
- return(value!=other.getval());
+ return(value!=other.value);
}
diff --git a/angleclass.h b/angleclass.h
index 5b2e99e..8135c0a 100644
--- a/angleclass.h
+++ b/angleclass.h
@@ -39,19 +39,19 @@ public:
angleclass(const double setme);
void setval(const double setme);
- double getval();
+ double getval() const;
- angleclass operator+(angleclass other);
- angleclass operator-(angleclass other);
- angleclass operator*(angleclass other);
- angleclass operator/(angleclass other);
+ angleclass operator+(const angleclass other) const;
+ angleclass operator-(const angleclass other) const;
+ angleclass operator*(const angleclass other) const;
+ angleclass operator/(const angleclass other) const;
//beware: these only compare the numeric value of the angle.
- bool operator<(angleclass other);
- bool operator>(angleclass other);
- bool operator<=(angleclass other);
- bool operator>=(angleclass other);
- bool operator==(angleclass other);
- bool operator!=(angleclass other);
+ bool operator<(const angleclass other) const;
+ bool operator>(const angleclass other) const;
+ bool operator<=(const angleclass other) const;
+ bool operator>=(const angleclass other) const;
+ bool operator==(const angleclass other) const;
+ bool operator!=(const angleclass other) const;
};
#endif // ANGLECLASS_H
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));
+}
diff --git a/anglerange.h b/anglerange.h
index ab98cbc..6d6d286 100644
--- a/anglerange.h
+++ b/anglerange.h
@@ -38,14 +38,22 @@
#define ANGLERANGE_H
#include "angleclass.h"
+#include <stdexcept>
class anglerange
{
+public:
+ typedef enum sorttype {SRT_LOWER,SRT_UPPER,SRT_SIZE} sorttype;
private:
angleclass lowerborder;
angleclass upperborder;
bool upperset;
bool lowerset;
+ bool fullcircle;
+ sorttype sortby; //for comparison operators
+ //default value: SRT_SIZE
+ //lower means sort by lower border, upper sort by upper border, and size sort by (upper-lower)
+ //only size cares about zero-crossing, the others just compare numeric values.
public:
//Default constructor: Both limits 0.0, marked as empty
anglerange();
@@ -54,9 +62,18 @@ public:
void setupper(const angleclass &newupper);
void setempty(); //marks the range as empty.
+ //to change sort field
+ void setsorttype(const sorttype value);
+ const sorttype getsorttype();
+
bool isempty() const; //returns true when the range is empty (or when one limit isn't set)
- angleclass getlower() const; //warning: Does not check if empty
- angleclass getupper() const; //warning: Does not check if empty
+ angleclass getlower() const; //warning: Does not check if empty, does not check if circle
+ angleclass getupper() const; //warning: Does not check if empty, does not check if circle
+ bool isinside(const angleclass &val) const; //check if angleclas val is in the range.
+
+ //to deal with full circles:
+ void setcircle(bool value);
+ bool iscircle() const;
//this function calculates the overlap between this anglerange and another one, returning it as
//a new anglerange.
@@ -66,6 +83,16 @@ public:
//if they are disjoint, an empty range is given back.
anglerange combine(const anglerange &other);
+ bool operator<(const anglerange &other) const;
+ bool operator>(const anglerange &other) const;
+ bool operator<=(const anglerange &other) const;
+ bool operator>=(const anglerange &other) const;
+
+ //these operators don't use sort order. They really compare by element!
+ //also: Two empty ranges are considered equal!
+ bool operator==(const anglerange &other) const;
+ bool operator!=(const anglerange &other) const;
+
};
#endif // ANGLERANGE_H
diff --git a/angleset.cpp b/angleset.cpp
new file mode 100644
index 0000000..fc759b8
--- /dev/null
+++ b/angleset.cpp
@@ -0,0 +1,188 @@
+/*
+ * LatticeMatch calculator - class used for angles
+ * Copyright (C) 2015 Andreas Grois
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ * This class extends anglerange with the ability to deal with disjoint ranges.
+ *
+ * The internal storage isn't exposed, and there is no way to address an individual sub-range.
+ * The reason for this is that the functions to add or remove ranges will resort the contents
+ * of the internal storage arbitrarily.
+ *
+ * This class is part of the LatticeMatch program.
+ *
+ * To contact the author either use electronic mail: Andreas Grois <andreas.grois@jku.at>
+ * or write to:
+ * Andreas Grois, Institute for Semiconductor and SolidState physics, Johannes Kepler University,
+ * Altenbergerstraße 69, 4040 Linz, AUSTRIA
+ */
+
+#include "angleset.h"
+
+angleset::angleset()
+{
+ //storage should be initialized as an empty vector, all we need here is:
+ consistent=true;
+}
+
+angleset::angleset(const anglerange &firstrange)
+{
+ assert(storage.size()==0);
+ if(!firstrange.isempty())
+ {
+ storage.push_back(firstrange);
+ storage[0].setsorttype(anglerange::SRT_LOWER);
+ }
+ consistent=true;
+}
+
+angleset::angleset(const angleclass &firstlower, const angleclass &firstupper)
+{
+ assert(storage.size()==0);
+ storage.push_back(anglerange(firstlower,firstupper));
+ storage[0].setsorttype(anglerange::SRT_LOWER);
+ consistent=true;
+}
+
+void angleset::reserve(size_t n)
+{
+ storage.reserve(n);
+}
+
+void angleset::combine()
+{
+ //the following should hopefully also work when storage is empty.
+ if(storage.size()>=2){ //only do something if there are at least two elements
+ for(std::vector<anglerange>::iterator curpos=storage.end()-2; //second last element
+ curpos>=storage.begin(); //learned the hard way, that for an empty vector .begin() returns (unsigned)0, so .begin()-2>.begin()...
+ curpos--){
+ std::vector<anglerange>::iterator compare = storage.end()-1;
+ while(compare!=curpos)
+ {
+ anglerange tmp = curpos->combine(*compare);
+ if(!(tmp.isempty()))
+ {
+ *curpos=tmp;
+ compare--; //I'm not certain if it's necessary to first decrement before deleting,
+ //but better safe than sorry.
+ storage.erase(compare+1);
+ }
+ else
+ compare--;
+ }
+ }
+ }
+ consistent=true;
+}
+
+bool angleset::isempty() const
+{
+ return(storage.empty());
+}
+
+bool angleset::iscircle()
+{
+ if(!consistent)
+ combine();
+ //if only one element in storage should be a full circle, combine will reduce storage to a single element vector.
+ if(!storage.empty())
+ {
+ return(storage.front().iscircle());
+ }
+ else{
+ return(false);
+ }
+}
+
+void angleset::add(const anglerange &value)
+{
+ //quick and dirty: We add the range, sort through, and combine if necessarry.
+ //this means: we *should not reuse* this function for adding anglesets.
+ if(!value.isempty())
+ {
+ storage.push_back(value);
+ storage.back().setsorttype(anglerange::SRT_LOWER);
+ combine();
+ }
+}
+
+void angleset::add(const angleset &value)
+{
+ storage.reserve(storage.size()+value.storage.size());
+ storage.insert(storage.end(),value.storage.begin(),value.storage.end());
+ //if value is a valid angleset, sort order is set to SRT_LOWER for all fields.
+ combine();
+}
+
+void angleset::add(const double &lower, const double &upper)
+{
+ storage.push_back(anglerange(lower,upper));
+ storage.back().setsorttype(anglerange::SRT_LOWER);
+ combine();
+}
+
+
+angleset angleset::overlap(const anglerange &other)
+{
+ if(!consistent)
+ combine();
+ angleset retval;
+ for_each(
+ storage.begin(),
+ storage.end(),
+ [&](anglerange i)
+ {
+ retval.add(i.overlap(other)); //given that add checks if the value passed to it is empty: this should work?!?
+ }
+ );
+ return(retval);
+}
+
+angleset angleset::overlap(const angleset &other)
+{
+ //just add the overlap of each anglerange in other ;-)
+ angleset retval;
+ for_each(
+ other.storage.begin(),
+ other.storage.end(),
+ [&](anglerange i)
+ {
+ retval.add(overlap(i));
+ }
+ );
+ return(retval);
+}
+
+std::vector<anglerange> angleset::getranges()
+{
+ return storage;
+}
+
+const std::vector<anglerange>& angleset::getrangesref()
+{
+ return storage;
+}
+
+void angleset::clear()
+{
+ storage.clear();
+}
+
+void angleset::sort()
+{
+ std::sort(storage.begin(),storage.end());
+}
diff --git a/angleset.h b/angleset.h
new file mode 100644
index 0000000..781a499
--- /dev/null
+++ b/angleset.h
@@ -0,0 +1,91 @@
+/*
+ * LatticeMatch calculator - class used for angles
+ * Copyright (C) 2015 Andreas Grois
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ * This class extends anglerange with the ability to deal with disjoint ranges.
+ *
+ * The internal storage isn't exposed, and there is no way to address an individual sub-range.
+ * The reason for this is that the functions to add or remove ranges will resort the contents
+ * of the internal storage arbitrarily.
+ *
+ * This class is part of the LatticeMatch program.
+ *
+ * To contact the author either use electronic mail: Andreas Grois <andreas.grois@jku.at>
+ * or write to:
+ * Andreas Grois, Institute for Semiconductor and SolidState physics, Johannes Kepler University,
+ * Altenbergerstraße 69, 4040 Linz, AUSTRIA
+ */
+
+#ifndef ANGLESET_H
+#define ANGLESET_H
+#include <vector>
+#include <cassert>
+#include <algorithm>
+#include "anglerange.h"
+
+class angleset
+{
+private:
+ std::vector<anglerange> storage;
+ bool consistent;
+ void combine();
+public:
+ angleset();
+ angleset(const anglerange &firstrange);
+ angleset(const angleclass &firstlower, const angleclass &firstupper);
+
+ //returns if the set is empty. Currently this means: internal storage is an empty vector.
+ bool isempty() const;
+ bool iscircle();//returns true when the whole angleset is a circle.
+
+ //add or remove single ranges
+ void add(const anglerange &value);
+ //void remove(const anglerange &value); //not implemented yet
+ void add(const double &lower, const double &upper);
+ //void remove(const double &lower, const double &upper); //not implemented yet
+
+ //here it gets interesting: add or remove complete sets.
+ void add(const angleset &value);
+ //void remove(const angleset &value); //not implemented yet
+
+ //in planning: add_deferred functions, that set consistent to false, and do not call combine() at the end.
+ //but for this of course each and every other function has to check for consistency
+
+ //having this return a new angleset is not consistent with the above add/remove functions, but it
+ //is consistent to older code in anglerange.h
+ angleset overlap(const anglerange &other);
+ angleset overlap(const angleset &other);
+
+ void reserve(size_t n); //just forwards storage's reserve function.
+
+ //empties the range
+ void clear();
+
+ //sorts the range
+ void sort();
+
+ //*generates* a new vector consisting of non-overlapping, unique angleranges.
+ std::vector<anglerange> getranges();
+ //gives you a reference to the internal storage, but const
+ //reference, to keep this relatively fast, const so you don't accidentally modify it.
+ //If the internal storage format changes, this might be changed to give a copy instead.
+ const std::vector<anglerange>& getrangesref(); //I hope this does what I think it does...
+
+};
+
+#endif // ANGLESET_H
diff --git a/main.cpp b/main.cpp
index 51e9506..0f3f62e 100644
--- a/main.cpp
+++ b/main.cpp
@@ -68,7 +68,7 @@
#include <cmath>
#include <cstdio>
#include <algorithm>
-#include "anglerange.h"
+#include "angleset.h"
using namespace std;
@@ -87,7 +87,7 @@ int main(int argc, char* argv[])
{
//read in command line arguments
double commargs[9], swapper;
- unsigned int i,j;
+ unsigned int i;
for(i=1;i<(unsigned)argc;i++)
{
//what is this stringstreams stuff everyone is hyped about?!?
@@ -139,16 +139,16 @@ int main(int argc, char* argv[])
//solutions run from -maxn to maxn, and from -maxm to maxm.
//Due to the ambiguity of asin, two solutions exist for each value of n and m
//This means, that (2*maxn+1)*2 solutions exist, the same for m.
- anglerange pxranges[4*maxn+2];
- anglerange qxranges[4*maxm+2];
+ angleset pxranges;
+ pxranges.reserve(4*maxn+2); //reserve memory, so adding stuff is faster...
+ angleset qxranges;
+ qxranges.reserve(4*maxm+2);
//up to now it was more or less dull C code. Now comes the first real difference:
//As asin changes sign together with its argument, one has to treat positive and negative n differently
//first the special case n=0:
- pxranges[0].setlower(commargs[ALPHA]);
- pxranges[0].setupper(commargs[ALPHA]);
- pxranges[1].setlower(commargs[ALPHA] - M_PI);
- pxranges[1].setupper(commargs[ALPHA] - M_PI);
+ pxranges.add(commargs[ALPHA],commargs[ALPHA]);
+ pxranges.add(commargs[ALPHA] - M_PI, commargs[ALPHA] - M_PI);
//now the slightly more difficult case: n>0
for(i=1;i<=maxn;i++){
//while factoring out the asin doesn't improve performance much - it's only used twice, it improves readability, as the important thing in the formulas below
@@ -159,37 +159,57 @@ int main(int argc, char* argv[])
//we need to consider that sin(alpha) can be negative. In that case the sign of the asin will change as well.
if(asina1b1min>=0)
{
- pxranges[2*i].setlower(commargs[ALPHA] - asina1b1min);
- pxranges[2*i].setupper(commargs[ALPHA] - asina1b1max);
- pxranges[2*i+1].setlower(commargs[ALPHA] - M_PI + asina1b1max);
- pxranges[2*i+1].setupper(commargs[ALPHA] - M_PI + asina1b1min);
+ pxranges.add(
+ commargs[ALPHA] - asina1b1min,
+ commargs[ALPHA] - asina1b1max
+ );
+ pxranges.add(
+ commargs[ALPHA] - M_PI + asina1b1max,
+ commargs[ALPHA] - M_PI + asina1b1min
+ );
//and the most difficult case: n<0
//here the arcsin is negative. as i is positive, I'll just change the sign in front of the arcsin.
- pxranges[2*i+2*maxn].setlower(commargs[ALPHA] + asina1b1max);
- pxranges[2*i+2*maxn].setupper(commargs[ALPHA] + asina1b1min);
- pxranges[2*i+2*maxn+1].setlower(commargs[ALPHA] - M_PI - asina1b1min);
- pxranges[2*i+2*maxn+1].setupper(commargs[ALPHA] - M_PI - asina1b1max);
+ pxranges.add(
+ commargs[ALPHA] + asina1b1max,
+ commargs[ALPHA] + asina1b1min
+ );
+ pxranges.add(
+ commargs[ALPHA] - M_PI - asina1b1min,
+ commargs[ALPHA] - M_PI - asina1b1max
+ );
}
else
{
//just as above, but with upper and lower limits switched
- pxranges[2*i].setlower(commargs[ALPHA] - asina1b1max);
- pxranges[2*i].setupper(commargs[ALPHA] - asina1b1min);
- pxranges[2*i+1].setlower(commargs[ALPHA] - M_PI + asina1b1min);
- pxranges[2*i+1].setupper(commargs[ALPHA] - M_PI + asina1b1max);
+ pxranges.add(
+ commargs[ALPHA] - asina1b1max,
+ commargs[ALPHA] - asina1b1min
+ );
+ pxranges.add(
+ commargs[ALPHA] - M_PI + asina1b1min,
+ commargs[ALPHA] - M_PI + asina1b1max
+ );
//n<0
- pxranges[2*i+2*maxn].setlower(commargs[ALPHA] + asina1b1min);
- pxranges[2*i+2*maxn].setupper(commargs[ALPHA] + asina1b1max);
- pxranges[2*i+2*maxn+1].setlower(commargs[ALPHA] - M_PI - asina1b1max);
- pxranges[2*i+2*maxn+1].setupper(commargs[ALPHA] - M_PI - asina1b1min);
+ pxranges.add(
+ commargs[ALPHA] + asina1b1min,
+ commargs[ALPHA] + asina1b1max
+ );
+ pxranges.add(
+ commargs[ALPHA] - M_PI - asina1b1max,
+ commargs[ALPHA] - M_PI - asina1b1min
+ );
}
}
//same nonsense for qxranges
//first the easy part: m=0;
- qxranges[0].setlower(commargs[ALPHA] - commargs[BETAMAX]);
- qxranges[0].setupper(commargs[ALPHA] - commargs[BETAMIN]);
- qxranges[1].setlower(commargs[ALPHA] - commargs[BETAMAX] - M_PI);
- qxranges[1].setupper(commargs[ALPHA] - commargs[BETAMIN] - M_PI);
+ qxranges.add(
+ commargs[ALPHA] - commargs[BETAMAX],
+ commargs[ALPHA] - commargs[BETAMIN]
+ );
+ qxranges.add(
+ commargs[ALPHA] - commargs[BETAMAX] - M_PI,
+ commargs[ALPHA] - commargs[BETAMIN] - M_PI
+ );
//now the slightly more difficult case: m>0;
for(i=1;i<=maxm;i++){
//also here, the asin values are factored out for improved readability.
@@ -198,60 +218,63 @@ int main(int argc, char* argv[])
//same here: keep in mind that sin(alpha) can be negative:
if(asina1b2min>=0)
{
- qxranges[2*i].setlower(commargs[ALPHA] - commargs[BETAMAX] - asina1b2min);
- qxranges[2*i].setupper(commargs[ALPHA] - commargs[BETAMIN] - asina1b2max);
- qxranges[2*i+1].setlower(commargs[ALPHA] - commargs[BETAMAX] - M_PI + asina1b2max);
- qxranges[2*i+1].setupper(commargs[ALPHA] - commargs[BETAMIN] - M_PI + asina1b2min);
+ qxranges.add(
+ commargs[ALPHA] - commargs[BETAMAX] - asina1b2min,
+ commargs[ALPHA] - commargs[BETAMIN] - asina1b2max
+ );
+ qxranges.add(
+ commargs[ALPHA] - commargs[BETAMAX] - M_PI + asina1b2max,
+ commargs[ALPHA] - commargs[BETAMIN] - M_PI + asina1b2min
+ );
//and last, but not leasst, the most difficult, m<0 - here the arcsin is negative;
//as i is positive, I'll just change the sign in front of the arcsin.
- qxranges[2*i+2*maxm].setlower(commargs[ALPHA] - commargs[BETAMAX] + asina1b2max);
- qxranges[2*i+2*maxm].setupper(commargs[ALPHA] - commargs[BETAMIN] + asina1b2min);
- qxranges[2*i+1+2*maxm].setlower(commargs[ALPHA] - commargs[BETAMAX] - M_PI - asina1b2min);
- qxranges[2*i+1+2*maxm].setupper(commargs[ALPHA] - commargs[BETAMIN] - M_PI - asina1b2max);
+ qxranges.add(
+ commargs[ALPHA] - commargs[BETAMAX] + asina1b2max,
+ commargs[ALPHA] - commargs[BETAMIN] + asina1b2min
+ );
+ qxranges.add(
+ commargs[ALPHA] - commargs[BETAMAX] - M_PI - asina1b2min,
+ commargs[ALPHA] - commargs[BETAMIN] - M_PI - asina1b2max
+ );
}
else
{
- qxranges[2*i].setlower(commargs[ALPHA] - commargs[BETAMAX] - asina1b2max);
- qxranges[2*i].setupper(commargs[ALPHA] - commargs[BETAMIN] - asina1b2min);
- qxranges[2*i+1].setlower(commargs[ALPHA] - commargs[BETAMAX] - M_PI + asina1b2min);
- qxranges[2*i+1].setupper(commargs[ALPHA] - commargs[BETAMIN] - M_PI + asina1b2max);
+ qxranges.add(
+ commargs[ALPHA] - commargs[BETAMAX] - asina1b2max,
+ commargs[ALPHA] - commargs[BETAMIN] - asina1b2min
+ );
+ qxranges.add(
+ commargs[ALPHA] - commargs[BETAMAX] - M_PI + asina1b2min,
+ commargs[ALPHA] - commargs[BETAMIN] - M_PI + asina1b2max
+ );
//m<0
- qxranges[2*i+2*maxm].setlower(commargs[ALPHA] - commargs[BETAMAX] + asina1b2min);
- qxranges[2*i+2*maxm].setupper(commargs[ALPHA] - commargs[BETAMIN] + asina1b2max);
- qxranges[2*i+1+2*maxm].setlower(commargs[ALPHA] - commargs[BETAMAX] - M_PI - asina1b2max);
- qxranges[2*i+1+2*maxm].setupper(commargs[ALPHA] - commargs[BETAMIN] - M_PI - asina1b2min);
- }
- }
- //Now the real big change from the plain C version: Using the anglerange class to generate a list
- //of overlaps instead of just outputting all of them.
-
- std::vector<anglerange> xoverlaps; //keep this, as the overlap between this and yoverlaps gives coincident results
- for(i=0;i<4*maxn+2;i++)
- {
- for(j=0;j<4*maxm+2;j++)
- {
- anglerange tmp = pxranges[i].overlap(qxranges[j]);
- if(!(tmp.isempty()))
- {
- xoverlaps.push_back(tmp);
- }
+ qxranges.add(
+ commargs[ALPHA] - commargs[BETAMAX] + asina1b2min,
+ commargs[ALPHA] - commargs[BETAMIN] + asina1b2max
+ );
+ qxranges.add(
+ commargs[ALPHA] - commargs[BETAMAX] - M_PI - asina1b2max,
+ commargs[ALPHA] - commargs[BETAMIN] - M_PI - asina1b2min
+ );
}
}
+ //Calculate the overlap between these two:
+ angleset xoverlaps=pxranges.overlap(qxranges);
//ok, same thing for qy, py:
//I know that this is wasteful regarding RAM, but well, we're still talking about bytes, not about megabytes ;-)
unsigned int maxo, maxp;
maxo=fabs(commargs[B1MAX]/(commargs[A2]*sin(commargs[ALPHA])));
maxp=fabs(commargs[B2MAX]/(commargs[A2]*sin(commargs[ALPHA])));
- anglerange qyranges[4*maxo+2];
- anglerange pyranges[4*maxp+2];
+ angleset qyranges;
+ qyranges.reserve(4*maxo+2);
+ angleset pyranges;
+ pyranges.reserve(4*maxp+2);
//now let's start with qyranges. As previously we need to consider the "sign" of o,p, and sin(alpha)
//first: o=0
- qyranges[0].setlower(0.0);
- qyranges[0].setupper(0.0);
- qyranges[1].setlower(M_PI);
- qyranges[1].setupper(M_PI);
+ qyranges.add(0.0,0.0);
+ qyranges.add(M_PI,M_PI);
for(i=1;i<=maxo;i++)
{
//also here: factor out the asin for improved readability.
@@ -261,36 +284,56 @@ int main(int argc, char* argv[])
if(asina2b1max>=0)
{
//case: o>0
- qyranges[2*i].setlower(asina2b1max);
- qyranges[2*i].setupper(asina2b1min);
- qyranges[2*i+1].setlower(M_PI - asina2b1min);
- qyranges[2*i+1].setupper(M_PI - asina2b1max);
+ qyranges.add(
+ asina2b1max,
+ asina2b1min
+ );
+ qyranges.add(
+ M_PI - asina2b1min,
+ M_PI - asina2b1max
+ );
//case: o<0
- qyranges[2*i+2*maxo].setlower( -asina2b1min);
- qyranges[2*i+2*maxo].setupper( -asina2b1max);
- qyranges[2*i+1+2*maxo].setlower(M_PI + asina2b1max);
- qyranges[2*i+1+2*maxo].setupper(M_PI + asina2b1min);
+ qyranges.add(
+ -asina2b1min,
+ -asina2b1max
+ );
+ qyranges.add(
+ M_PI + asina2b1max,
+ M_PI + asina2b1min
+ );
}
else
{
//case: o>0
- qyranges[2*i].setlower(asina2b1min);
- qyranges[2*i].setupper(asina2b1max);
- qyranges[2*i+1].setlower(M_PI - asina2b1max);
- qyranges[2*i+1].setupper(M_PI - asina2b1min);
+ qyranges.add(
+ asina2b1min,
+ asina2b1max
+ );
+ qyranges.add(
+ M_PI - asina2b1max,
+ M_PI - asina2b1min
+ );
//case: o<0
- qyranges[2*i+2*maxo].setlower( -asina2b1max);
- qyranges[2*i+2*maxo].setupper( -asina2b1min);
- qyranges[2*i+1+2*maxo].setlower(M_PI + asina2b1min);
- qyranges[2*i+1+2*maxo].setupper(M_PI + asina2b1max);
+ qyranges.add(
+ -asina2b1max,
+ -asina2b1min
+ );
+ qyranges.add(
+ M_PI + asina2b1min,
+ M_PI + asina2b1max
+ );
}
}
//that was too easy. Probably it's buggy as hell...
//now to py
- pyranges[0].setlower( -commargs[BETAMAX]);
- pyranges[0].setupper( -commargs[BETAMIN]);
- pyranges[1].setlower(M_PI - commargs[BETAMAX]);
- pyranges[1].setupper(M_PI - commargs[BETAMIN]);
+ pyranges.add(
+ -commargs[BETAMAX],
+ -commargs[BETAMIN]
+ );
+ pyranges.add(
+ M_PI - commargs[BETAMAX],
+ M_PI - commargs[BETAMIN]
+ );
for(i=1;i<=maxp;i++)
{
//and again: readability
@@ -299,156 +342,66 @@ int main(int argc, char* argv[])
if(asina2b2max>=0)
{
//case: p>0
- pyranges[2*i].setlower(asina2b2max - commargs[BETAMAX]);
- pyranges[2*i].setupper(asina2b2min - commargs[BETAMIN]);
- pyranges[2*i+1].setlower(M_PI - asina2b2min - commargs[BETAMAX]);
- pyranges[2*i+1].setupper(M_PI - asina2b2max - commargs[BETAMIN]);
+ pyranges.add(
+ asina2b2max - commargs[BETAMAX],
+ asina2b2min - commargs[BETAMIN]
+ );
+ pyranges.add(
+ M_PI - asina2b2min - commargs[BETAMAX],
+ M_PI - asina2b2max - commargs[BETAMIN]
+ );
//case: p<0
- pyranges[2*i+2*maxp].setlower( -asina2b2min - commargs[BETAMAX]);
- pyranges[2*i+2*maxp].setupper( -asina2b2max - commargs[BETAMIN]);
- pyranges[2*i+1+2*maxp].setlower(M_PI + asina2b2max - commargs[BETAMAX]);
- pyranges[2*i+1+2*maxp].setupper(M_PI + asina2b2min - commargs[BETAMIN]);
+ pyranges.add(
+ -asina2b2min - commargs[BETAMAX],
+ -asina2b2max - commargs[BETAMIN]
+ );
+ pyranges.add(
+ M_PI + asina2b2max - commargs[BETAMAX],
+ M_PI + asina2b2min - commargs[BETAMIN]
+ );
}
else
{
//ok, here the asin is of opposite sign!
//case p>0
- pyranges[2*i].setlower(asina2b2min - commargs[BETAMAX]);
- pyranges[2*i].setupper(asina2b2max - commargs[BETAMIN]);
- pyranges[2*i+1].setlower(M_PI - asina2b2max - commargs[BETAMAX]);
- pyranges[2*i+1].setupper(M_PI - asina2b2min - commargs[BETAMIN]);
+ pyranges.add(
+ asina2b2min - commargs[BETAMAX],
+ asina2b2max - commargs[BETAMIN]
+ );
+ pyranges.add(
+ M_PI - asina2b2max - commargs[BETAMAX],
+ M_PI - asina2b2min - commargs[BETAMIN]
+ );
//case: p<0
- pyranges[2*i+2*maxp].setlower( -asina2b2max - commargs[BETAMAX]);
- pyranges[2*i+2*maxp].setupper( -asina2b2min - commargs[BETAMIN]);
- pyranges[2*i+1+2*maxp].setlower(M_PI + asina2b2min - commargs[BETAMAX]);
- pyranges[2*i+1+2*maxp].setupper(M_PI + asina2b2max - commargs[BETAMIN]);
+ pyranges.add(
+ -asina2b2max - commargs[BETAMAX],
+ -asina2b2min - commargs[BETAMIN]
+ );
+ pyranges.add(
+ M_PI + asina2b2min - commargs[BETAMAX],
+ M_PI + asina2b2max - commargs[BETAMIN]
+ );
}
}
//99 bottles of bugs on the wall, 99 bottles of bugs. You get one down and fix it up, 99 bottles of bugs...
//100 bottles of bugs on the wall, 100 bottles of bugs....
- std::vector<anglerange> yoverlaps;
- for(i=0;i<4*maxo+2;i++)
- {
- for(j=0;j<4*maxp+2;j++)
- {
- anglerange tmp = qyranges[i].overlap(pyranges[j]);
- if(!(tmp.isempty()))
- {
- yoverlaps.push_back(tmp);
- }
- }
- }
-
- //to be a commensurate match, an angle has to be in both, x- and yoverlaps
- std::vector<anglerange> commensurate;
- for(i=0;i<xoverlaps.size();i++)
- {
- for(j=0;j<yoverlaps.size();j++)
- {
- anglerange tmp = xoverlaps[i].overlap(yoverlaps[j]);
- if(!(tmp.isempty()))
- {
- commensurate.push_back(tmp);
- }
- }
- }
-/*
- cout << "Possible coincident lattice matches with px, qx:" << std::endl;
- for(i=0;i<xoverlaps.size();i++)
- {
- cout << (xoverlaps.at(i)).getlower().getval()*180/M_PI << " " << (xoverlaps.at(i)).getupper().getval()*180/M_PI << std::endl;
- }
- cout << "Possible coincident lattice matches with qy, py:" << std::endl;
- for(i=0;i<yoverlaps.size();i++)
- {
- cout << (yoverlaps.at(i)).getlower().getval()*180/M_PI << " " << (yoverlaps.at(i)).getupper().getval()*180/M_PI << std::endl;
- }
-*/
- //to make the output more readable, combine the ranges.
- //first: copy xranges and yranges together:
- std::vector<anglerange> ranges;
- ranges.reserve(xoverlaps.size()+yoverlaps.size()+1);
- ranges.insert(ranges.end(),xoverlaps.begin(),xoverlaps.end());
- ranges.insert(ranges.end(),yoverlaps.begin(),yoverlaps.end());
- if(ranges.size()>1) //combining elements only makes sense, if there are at least 2 elements to combine...
- {
- bool stop;
- do
- {
- i=0;
- stop=false;
- do
- {
- j=i+1;
- do
- {
- anglerange tmp = ranges.at(i).combine(ranges.at(j));
- if(!(tmp.isempty()))
- {
- stop=true;
- ranges.push_back(tmp);
- ranges.erase(ranges.begin()+j);
- ranges.erase(ranges.begin()+i);
- }
- j++;
- }
- while(!stop && j<ranges.size());
- i++;
- }
- while(!stop && i<ranges.size()-1); //the -1 is there, as for i=ranges.size() there is no valid j any more.
- }
- while(stop); //yes, here is stop, not !stop, as stop means: stop to iterate over elements, go back to main loop, which should only terminate, if the internal loops finished.
- }
-
- //the same thing for commensurate...
- if(commensurate.size()>1)
- {
- bool stop;
- do
- {
- i=0;
- stop=false;
- do
- {
- j=i+1;
- do
- {
- anglerange tmp = commensurate.at(i).combine(commensurate.at(j));
- if(!(tmp.isempty()))
- {
- stop=true;
- commensurate.push_back(tmp);
- commensurate.erase(commensurate.begin()+j);
- commensurate.erase(commensurate.begin()+i);
- }
- j++;
- }
- while(!stop && j<commensurate.size());
- i++;
- }
- while(!stop && i<commensurate.size()-1); //the -1 is there, as for i=commensurate.size() there is no valid j any more.
- }
- while(stop); //yes, here is stop, not !stop, as stop means: stop to iterate over elements, go back to main loop, which should only terminate, if the internal loops finished.
- }
+ angleset yoverlaps = pyranges.overlap(qyranges);
- //again,for readability: sort the ranges by their lower limit:
- {
- std::sort(ranges.begin(),ranges.end(),[](const anglerange &a,const anglerange &b){return(a.getlower()<b.getlower());});
- std::sort(commensurate.begin(),commensurate.end(),[](const anglerange &a,const anglerange &b){return(a.getlower()<b.getlower());});
- }
+ angleset coincident;
+ coincident=xoverlaps;
+ coincident.add(yoverlaps);
+ //to be a commensurate match, an angle has to be in both, x- and yoverlaps
+ angleset commensurate = xoverlaps.overlap(yoverlaps);
- cout << "Possible coincident lattice matches:" << std::endl;
- for(i=0;i<ranges.size();i++)
- {
- cout << (ranges.at(i)).getlower().getval()*180/M_PI << " " << (ranges.at(i)).getupper().getval()*180/M_PI << std::endl;
- }
- cout << "Possible commensurate lattice matches:" << std::endl;
- for(i=0;i<commensurate.size();i++)
- {
- cout << (commensurate.at(i)).getlower().getval()*180/M_PI << " " << (commensurate.at(i)).getupper().getval()*180/M_PI << std::endl;
- }
+ //quick and dirrrty
+ coincident.sort();
+ commensurate.sort();
+ cout << "Coincident Matches:\n";
+ for_each(coincident.getrangesref().begin(),coincident.getrangesref().end(),[](anglerange i) {cout << i.getlower().getval()*180/M_PI << " " << i.getupper().getval()*180/M_PI << "\n"; });
+ cout << "Commensurate Matches:\n";
+ for_each(commensurate.getrangesref().begin(),commensurate.getrangesref().end(),[](anglerange i) {cout << i.getlower().getval()*180/M_PI << " " << i.getupper().getval()*180/M_PI << "\n"; });
}
}