00001 /* 00002 * Copyright (c) 2004 CSIRO ICT Centre 00003 * 00004 * $Id: IndexedActiveList.cpp 587 2004-12-03 15:06:33Z nch $ 00005 */ 00006 00007 /* IndexedActiveList implements an ActiveList with a data 00008 * structure that is very efficient for: 00009 * - adding objects in order of declination; 00010 * - removing all objects up to a given declination limit; and 00011 * - reporting all objects that fall within a given right 00012 * ascension range. 00013 */ 00014 00015 #include <algorithm> 00016 00017 #include "ActiveList.h" 00018 #include "ActiveObject.h" 00019 #include "ALStructure.h" 00020 #include "IndexedActiveList.h" 00021 #include "Object.h" 00022 #include "ObjectPairConsumer.h" 00023 #include "ObjectConsumer.h" 00024 #include "Profiler.h" 00025 00026 00027 IndexedActiveList::IndexedActiveList() 00028 : ActiveList() 00029 { 00030 activeStructure = new ALStructure(); 00031 } 00032 00033 IndexedActiveList::~IndexedActiveList() 00034 { 00035 profiler = 0; 00036 delete activeStructure; 00037 } 00038 00039 00040 void IndexedActiveList::pushBack(Object const * object, bool matchedPreviously) 00041 { 00042 activeStructure->add(new ActiveObject(object, matchedPreviously)); 00043 } 00044 00045 // a little care is needed to avoid ending up with 00046 // an invalid objecter. 00047 ALElement * IndexedActiveList::remove(ALElement * i) 00048 { 00049 ALElement * tempI = i; 00050 i = i->getPrevDec(); 00051 activeStructure->remove(tempI); 00052 if (i == 0) 00053 i = activeStructure->getDecHead(); 00054 else 00055 i = i->getNextDec(); 00056 00057 return i; 00058 } 00059 00060 void IndexedActiveList::deletePriorObjects(double boundary, 00061 ObjectConsumer * uActiveCons) 00062 { 00063 // start at the object with lowest declination. 00064 ALElement * i = activeStructure->getDecHead(); 00065 00066 // for as long as we haven't reached the end of the list. 00067 while (i != activeStructure->getTail()) 00068 { 00069 // examine a object. 00070 ActiveObject * activeObject = i->getContent(); 00071 Object const * object = activeObject->getObject(); 00072 if (object->getDec() < boundary) 00073 { 00074 // the object's declination is less that the bound, 00075 // so remove it. 00076 00077 // if the object has never appeared in a candidate pair, 00078 // then report it unmatched. 00079 if (!(activeObject->isMatched())) 00080 uActiveCons->report(object); 00081 00082 i = remove(i); 00083 delete object; 00084 delete activeObject; 00085 } 00086 else 00087 { 00088 // this object is past the boundary, 00089 // and so will every subsequent object be. 00090 // So break out now. 00091 break; 00092 } 00093 } 00094 } 00095 00096 /* Find all objects in the active list that are near a test object. 00097 * By the time we get to this object, we already know that all 00098 * the objects in the active list are nearby in the declination 00099 * dimension, so we only need to check for proximity in right 00100 * ascension. */ 00101 00102 bool IndexedActiveList::testObject(Object const * testObject, 00103 double upperLimitOnDistance, 00104 ObjectPairConsumer * matchedConsumer) 00105 { 00106 if (profiler != 0) 00107 { 00108 profiler->registerActiveListSize(activeStructure->getSize()); 00109 } 00110 00111 bool testObjectMatched = false; 00112 00113 // compute an upper bound on the distance away in ra of a matching object 00114 double upperLimitOnRaDistance = Object::computeRACorrection( 00115 upperLimitOnDistance, 00116 testObject->getDec()); 00117 00118 // compute a lower bound on right ascension. 00119 double lowerBound = testObject->getRa() - upperLimitOnRaDistance; 00120 00121 // compute an upper bound on right ascension. 00122 double upperBound = testObject->getRa() + upperLimitOnRaDistance; 00123 00124 // adjust bounds as required 00125 if (lowerBound < 0.0) 00126 lowerBound += 360.0; 00127 else if (lowerBound > 360.0) 00128 lowerBound -= 360.0; 00129 00130 if (upperBound < 0.0) 00131 upperBound += 360.0; 00132 else if (upperBound > 360.0) 00133 upperBound -= 360.0; 00134 00135 // We're about to walk from the lower bound to the 00136 // upper bound, reporting all objects encountered. 00137 // Decide if our walk will need to wrap around at the 00138 // prime meridian. 00139 bool wrap = (upperBound < lowerBound); 00140 00141 // find the starting object for our walk. 00142 ALElement * i = activeStructure->findLeastGE(lowerBound); 00143 00144 while (true) 00145 { 00146 if (i == activeStructure->getTail()) 00147 { 00148 // We're at the end of the list. 00149 // Do we stop or wrap? 00150 if (wrap) 00151 { 00152 // Wrap around to the start of the list, 00153 // but turn wrap off so that we don't risk 00154 // wrapping around again (and again and again...) 00155 i = activeStructure->getRaHead(); 00156 wrap = false; 00157 continue; 00158 } 00159 else 00160 { 00161 // we're at the end of the list but we 00162 // shouldn't wrap. So stop. 00163 break; 00164 } 00165 } 00166 else 00167 { 00168 // Examine the current object, and decide whether 00169 // to report it and continue, or stop. 00170 ActiveObject * activeObject = i->getContent(); 00171 Object const * matchingObject = activeObject->getObject(); 00172 00173 // if we haven't reached the upper bound, or if we 00174 // need to walk until we wrap around at the prime 00175 // meridian, then report this object and continue 00176 // walking. 00177 00178 if ((matchingObject->getRa() <= upperBound) || (wrap)) 00179 { 00180 if (matchedConsumer->report(testObject, matchingObject)) 00181 { 00182 testObjectMatched = true; 00183 activeObject->markMatched(); 00184 } 00185 00186 i = i->getNextRa(); 00187 } 00188 else 00189 { 00190 // we're past the upper bound and we're not wrapping, 00191 // so stop. 00192 break; 00193 } 00194 } 00195 } 00196 00197 return testObjectMatched; 00198 } 00199 00200 /* clear out the active list, reporting things unmatched if 00201 * necessary. */ 00202 void IndexedActiveList::clear(ObjectConsumer * uActiveCons) 00203 { 00204 // start at the head. 00205 ALElement * i = activeStructure->getDecHead(); 00206 00207 // until we get to the end of the list. 00208 while (i != activeStructure->getTail()) 00209 { 00210 // if the object has never been matched, report it unmatched. 00211 ActiveObject * activeObject = i->getContent(); 00212 Object const * object = activeObject->getObject(); 00213 if (!(activeObject->isMatched())) 00214 uActiveCons->report(object); 00215 00216 i = remove(i); 00217 delete object; 00218 delete activeObject; 00219 } 00220 } 00221 00222 /* clean up the active list, then announce completion */ 00223 void IndexedActiveList::finished(ObjectConsumer * uActiveCons) 00224 { 00225 clear(uActiveCons); 00226 } 00227 00228 bool IndexedActiveList::isEmpty() 00229 { 00230 return (activeStructure->getSize() == 0); 00231 } 00232 00233 ActiveObject * IndexedActiveList::popFront() 00234 { 00235 ActiveObject * active = activeStructure->getDecHead()->getContent(); 00236 remove(activeStructure->getDecHead()); 00237 00238 return active; 00239 }