31 #define M_PI 3.14159265358979323846  
   79         stream << 
" dx " << segment.
dx << 
" dy " << segment.
dy << 
" r " << segment.
r << 
std::endl;
 
  107         for (
auto si2 = siStop; si2 != si1; --si2) {
 
  110     sort(DecreasingLength); 
 
  132         if (a_pair.first->s1rank != rank1 || a_pair.second->s1rank != rank2) 
continue;
 
  136         if (matchList->size() == 0)
 
  137             matchList->push_back(
StarMatch(
transform.apply(*(a_pair.first->s1)), *(a_pair.second->s1),
 
  138                                            a_pair.first->s1, a_pair.second->s1));
 
  140         matchList->push_back(
StarMatch(
transform.apply(*(a_pair.first->s2)), *(a_pair.second->s2),
 
  141                                        a_pair.first->s2, a_pair.second->s2));
 
  174     int nBinsAngle = 180; 
 
  175     double angleOffset = 
M_PI / nBinsAngle;
 
  178     Histo2d histo(nBinsR, minRatio, maxRatio, nBinsAngle, -
M_PI - angleOffset, 
M_PI - angleOffset);
 
  183     for (segi1 = sList1.
begin(); segi1 != sList1.
end(); ++segi1) {
 
  185         if (seg1->
r == 0) 
continue;
 
  186         for (segi2 = sList2.
begin(); segi2 != sList2.
end(); ++segi2) {
 
  194             if (
ratio > maxRatio) 
continue;
 
  195             if (
ratio < minRatio) 
break; 
 
  212         double ratioMax, angleMax;
 
  213         double maxContent = histo.
maxBin(ratioMax, angleMax);
 
  214         histo.
fill(ratioMax, angleMax, -maxContent);
 
  217             LOGLS_DEBUG(_log, 
" valMax " << maxContent << 
" ratio " << ratioMax << 
" angle " << angleMax);
 
  219         minRatio = ratioMax - binr / 2;
 
  220         maxRatio = ratioMax + binr / 2;
 
  221         double minAngle = angleMax - bina / 2;
 
  222         double maxAngle = angleMax + bina / 2;
 
  228         for (segi1 = sList1.
begin(); segi1 != sList1.
end(); ++segi1) {
 
  230             if (seg1->
r == 0) 
continue;
 
  231             for (segi2 = sList2.
begin(); segi2 != sList2.
end(); ++segi2) {
 
  234                 if (
ratio > maxRatio) 
continue;
 
  235                 if (
ratio < minRatio)
 
  239                 if (angle < minAngle || angle > maxAngle) 
continue;
 
  244         for (
int iteration = 0; iteration < conditions.
maxTrialCount; iteration++) {
 
  246             double maxval = historank.
maxBin(dr1, dr2);
 
  248             historank.
fill(dr1, dr2, -maxval);
 
  250             a_list->refineTransform(conditions.
nSigmas);  
 
  254     Solutions.
sort(DecreasingQuality);
 
  260         LOGLS_DEBUG(_log, 
"Best solution " << best->computeResidual() << 
" npairs " << best->size());
 
  262         LOGLS_DEBUG(_log, 
"Chi2 " << best->getChi2() << 
',' << 
" Number of solutions " << Solutions.
size());
 
  278                                                               const MatchConditions &conditions) {
 
  279     if (list1.size() <= 4 || list2.size() <= 4) {
 
  280         LOGL_FATAL(_log, 
"ListMatchupRotShift_New : (at least) one of the lists is too short.");
 
  284     SegmentList sList1(list1, conditions.nStarsList1, 
transform);
 
  285     SegmentList sList2(list2, conditions.nStarsList2, AstrometryTransformIdentity());
 
  293     int nBinsAngle = 180; 
 
  294     double angleOffset = 
M_PI / nBinsAngle;
 
  295     double minRatio = conditions.minSizeRatio();
 
  296     double maxRatio = conditions.maxSizeRatio();
 
  297     SparseHisto4d histo(nBinsR, minRatio, maxRatio, nBinsAngle, -
M_PI - angleOffset, 
M_PI - angleOffset,
 
  298                         conditions.nStarsList1, 0., conditions.nStarsList1, conditions.nStarsList2, 0.,
 
  299                         conditions.nStarsList2, sList1.size() * sList2.size());
 
  302     Segment *seg1, *seg2;
 
  305     for (segi1 = sList1.begin(); segi1 != sList1.end(); ++segi1) {
 
  307         if (seg1->r == 0) 
continue;
 
  308         for (segi2 = sList2.begin(); segi2 != sList2.end(); ++segi2) {
 
  315             ratio = seg2->r / seg1->r;
 
  316             if (ratio > maxRatio) 
continue;
 
  317             if (ratio < minRatio) 
break; 
 
  318             angle = seg1->relativeAngle(seg2);
 
  320             histo.fill(ratio, 
angle, seg1->s1rank + 0.5, seg2->s1rank + 0.5);
 
  331     int oldMaxContent = 0;
 
  333     for (
int i = 0; i < 4 * conditions.maxTrialCount;
 
  337         int maxContent = histo.maxBin(pars);
 
  338         if (maxContent == 0) 
break;
 
  339         if (conditions.printLevel >= 1) {
 
  340             LOGLS_DEBUG(_log, 
"ValMax " << maxContent << 
" ratio " << pars[0] << 
" angle " << pars[1]);
 
  347             if (maxContent < oldMaxContent && i >= conditions.maxTrialCount) 
break;
 
  349         oldMaxContent = maxContent;
 
  351         int rank1L1 = int(pars[2]);
 
  352         int rank1L2 = int(pars[3]);
 
  353         double minAngle, maxAngle;
 
  354         histo.binLimits(pars, 0, minRatio, maxRatio);
 
  355         histo.binLimits(pars, 1, minAngle, maxAngle);
 
  359         for (segi1 = sList1.begin(); segi1 != sList1.end(); ++segi1) {
 
  361             if (seg1->s1rank != rank1L1) 
continue;
 
  362             if (seg1->r == 0) 
continue;
 
  363             for (segi2 = sList2.begin(); segi2 != sList2.end(); ++segi2) {
 
  365                 if (seg2->s1rank != rank1L2) 
continue;
 
  367                 if (a_list->size() == 0)
 
  368                     a_list->push_back(StarMatch(*(seg1->s1), *(seg2->s1), seg1->s1, seg2->s1));
 
  369                 ratio = seg2->r / seg1->r;
 
  370                 if (ratio > maxRatio) 
continue;
 
  371                 if (ratio < minRatio)
 
  373                 angle = seg1->relativeAngle(seg2);
 
  375                 if (angle < minAngle || angle > maxAngle) 
continue;
 
  381                 a_list->push_back(StarMatch(*(seg1->s2), *(seg2->s2), seg1->s2, seg2->s2));
 
  387         if (
int(a_list->size()) != maxContent + 1) {
 
  388             LOGLS_ERROR(_log, 
"There is an internal inconsistency in ListMatchupRotShift.");
 
  390             LOGLS_ERROR(_log, 
"matches->size() = " << a_list->size());
 
  392         a_list->refineTransform(conditions.nSigmas);
 
  396     if (Solutions.size() == 0) {
 
  397         LOGLS_ERROR(_log, 
"Error In ListMatchup : not a single pair match.");
 
  398         LOGLS_ERROR(_log, 
"Probably, the relative scale of lists is not within bounds.");
 
  399         LOGLS_ERROR(_log, 
"min/max ratios: " << minRatio << 
' ' << maxRatio);
 
  403     Solutions.sort(DecreasingQuality);
 
  405     best.
swap(*Solutions.begin());
 
  407     Solutions.pop_front();
 
  408     if (conditions.printLevel >= 1) {
 
  409         LOGLS_INFO(_log, 
"Best solution " << best->computeResidual() << 
" npairs " << best->size());
 
  411         LOGLS_INFO(_log, 
"Chi2 " << best->getChi2() << 
", Number of solutions " << Solutions.size());
 
  418                                                           const MatchConditions &conditions) {
 
  419     if (conditions.algorithm == 1)
 
  420         return ListMatchupRotShift_Old(list1, list2, 
transform, conditions);
 
  422         return ListMatchupRotShift_New(list1, list2, 
transform, conditions);
 
  445                     "unflipped Residual " << unflipped->computeResidual() << 
" nused " << unflipped->size());
 
  446         LOGLS_DEBUG(_log, 
"flipped Residual " << flipped->computeResidual() << 
" nused " << flipped->size());
 
  448     if (DecreasingQuality(flipped, unflipped)) {
 
  466     int ncomb = list1.size() * list2.size();
 
  467     if (!ncomb) 
return nullptr;
 
  472         nx = (int)sqrt(ncomb);
 
  474     Histo2d histo(nx, -maxShift, maxShift, nx, -maxShift, maxShift);
 
  478     for (s1 = list1.begin(); s1 != list1.end(); ++s1) {
 
  479         transform.apply((*s1)->x, (*s1)->y, x1, y1);
 
  480         for (s2 = list2.begin(); s2 != list2.end(); ++s2) {
 
  481             histo.fill((*s2)->x - x1, (*s2)->y - y1);
 
  484     double dx = 0, dy = 0;
 
  485     histo.maxBin(dx, dy);
 
  494                                                             double maxShift, 
double binSize) {
 
  497         int ncomb = list1.
size() * list2.
size();
 
  501             nx = (int)
sqrt(
double(ncomb));
 
  504         nx = int(2 * maxShift / binSize + 0.5);
 
  506     Histo2d histo(nx, -maxShift, maxShift, nx, -maxShift, maxShift);
 
  507     double binSizeNew = 2 * maxShift / nx;
 
  512     for (s1 = list1.
begin(); s1 != list1.
end(); ++s1) {
 
  513         transform.apply((*s1)->x, (*s1)->y, x1, y1);
 
  517             histo.
fill(s2->x - x1, s2->y - y1);
 
  522     for (
int i = 0; i < 4; ++i) {
 
  523         double dx = 0, dy = 0;
 
  528         auto raw_matches = 
listMatchCollect(list1, list2, newGuess.get(), binSizeNew);
 
  530         raw_matches->applyTransform(*matches, &
transform);
 
  531         matches->setTransformOrder(1);
 
  532         matches->refineTransform(3.);
 
  535     Solutions.
sort(DecreasingQuality);
 
  538                     std::dynamic_pointer_cast<const AstrometryTransformLinear>(
 
  539                             Solutions.
front()->getTransform()))));
 
  548                                                      const AstrometryTransform *guess, 
const double maxDist) {
 
  552         const Point *p1 = (*si);
 
  553         const Point p2 = guess->apply(*p1);
 
  554         const BaseStar *neighbour = list2.findClosest(p2);
 
  555         if (!neighbour) 
continue;
 
  556         double distance = p2.Distance(*neighbour);
 
  558             matches->push_back(StarMatch(*p1, *neighbour, *si, neighbour));
 
  560             matches->back().distance = 
distance;
 
  578         if (!neighbour) 
continue;
 
  581             matches->push_back(
StarMatch(*p1, *neighbour, p1, neighbour));
 
  583             matches->back().distance = 
distance;
 
  586     matches->setTransform(guess);
 
  595                                              const AstrometryTransform *guess, 
const double maxDist) {
 
  596     const AstrometryTransform *bestTransform = guess;
 
  600         m->setTransform(bestTransform);
 
  601         m->refineTransform(3.);
 
  602         LOGLS_INFO(_log, 
"Iterating: resid " << 
m->computeResidual() << 
" size " << 
m->size());
 
  604             (prevMatch && 
m->computeResidual() < prevMatch->computeResidual() * 0.999 && 
m->Chi2() > 0)) {
 
  606             bestTransform = prevMatch->Transform();
 
  616                                                 const double maxDist) {
 
  622         if (!neighbour) 
continue;
 
  623         double distance = p1->Distance(*neighbour);
 
  625             matches->push_back(
StarMatch(*p1, *neighbour, p1, neighbour));
 
  627             matches->back().distance = 
distance;
 
  631     matches->setTransform(std::make_shared<AstrometryTransformIdentity>());
 
  636 static bool is_transform_ok(
const StarMatchList *match, 
double pixSizeRatio2, 
const size_t nmin) {
 
  637     if ((fabs(fabs(std::dynamic_pointer_cast<const AstrometryTransformLinear>(match->getTransform())
 
  642         (match->size() > nmin))
 
  645     match->printTransform();
 
  650 static double transform_diff(
const BaseStarList &List, 
const AstrometryTransform *T1,
 
  651                              const AstrometryTransform *T2) {
 
  657         const BaseStar &s = **it;
 
  658         T1->transformPosAndErrors(s, tf1);
 
  660         double dx = tf1.x - tf2.x;
 
  661         double dy = tf1.y - tf2.y;
 
  662         diff2 += (tf1.vy * dx * dx + tf1.vx * dy * dy - 2 * tf1.vxy * dx * dy) /
 
  663                  (tf1.vx * tf1.vy - tf1.vxy * tf1.vxy);
 
  666     if (count) 
return diff2 / double(count);
 
  670 static double median_distance(
const StarMatchList *match, 
const AstrometryTransform *
transform) {
 
  671     size_t nstars = match->size();
 
  674     for (
auto it = match->begin(); it != match->end(); ++it, ++ir)
 
  675         *ir = 
sqrt(
transform->apply(it->point1).computeDist2(it->point2));
 
  676     sort(resid.begin(), resid.end());
 
  677     return (nstars & 1) ? resid[nstars / 2] : (resid[nstars / 2 - 1] + resid[nstars / 2]) * 0.5;
 
  689     LOGLS_INFO(_log, 
"listMatchCombinatorial: find match between " << list1.
size() << 
" and " << list2.
size()
 
  697     if (is_transform_ok(match.get(), pixSizeRatio2, nmin))
 
  698         transform = match->getTransform()->clone();
 
  700         LOGL_ERROR(_log, 
"listMatchCombinatorial: direct transform failed, trying reverse");
 
  702         if (is_transform_ok(match.get(), pixSizeRatio2, nmin))
 
  712             LOGL_DEBUG(_log, 
" listMatchCombinatorial: found the following transform.");
 
  716         LOGL_ERROR(_log, 
"listMatchCombinatorial: failed to find a transform");
 
  722                                                      const int maxOrder) {
 
  728     const double brightDist = 2.;  
 
  729     const double fullDist = 4.;    
 
  730     const double nSigmas = 3.;     
 
  731     const size_t nStars = 500;     
 
  748     LOGLS_INFO(_log, 
"listMatchRefine: start: med.resid " << median_distance(fullMatch.get(), 
transform.get())
 
  749                                                           << 
" #match " << fullMatch->size());
 
  752         auto curTransform = brightMatch->getTransform()->clone();
 
  756             brightMatch->setTransformOrder(
order);
 
  757             brightMatch->refineTransform(nSigmas);
 
  758             transDiff = transform_diff(list1, brightMatch->getTransform().get(), curTransform.get());
 
  759             curTransform = brightMatch->getTransform()->clone();
 
  760             brightMatch = 
listMatchCollect(list1, list2, curTransform.get(), brightDist);
 
  761         } 
while (brightMatch->size() > nstarmin && transDiff > 0.05 && ++
iter < 5);
 
  763         double prevChi2 = curChi2;
 
  764         curChi2 = 
computeChi2(*brightMatch, *curTransform) / brightMatch->size();
 
  768                                                    << median_distance(fullMatch.get(), curTransform.get())
 
  769                                                    << 
" #match " << fullMatch->size());
 
  770         if (((prevChi2 - curChi2) > 0.01 * curChi2) && curChi2 > 0) {
 
  771             LOGLS_INFO(_log, 
" listMatchRefine: order " << 
order << 
" was a better guess.");
 
  772             transform = brightMatch->getTransform()->clone();
 
  774         nstarmin = brightMatch->getTransform()->getNpar();
 
  775     } 
while (++
order <= maxOrder);
 
Fast locator in starlists.
 
table::Key< double > angle
 
Combinatorial searches for linear transformations to go from list1 to list2.
 
LSST DM logging module built on log4cxx.
 
#define LOG_GET(logger)
Returns a Log object associated with logger.
 
#define LOGL_INFO(logger, message...)
Log a info-level message using a varargs/printf style interface.
 
#define LOGLS_INFO(logger, message)
Log a info-level message using an iostream-based interface.
 
#define LOGLS_ERROR(logger, message)
Log a error-level message using an iostream-based interface.
 
#define LOGL_ERROR(logger, message...)
Log a error-level message using a varargs/printf style interface.
 
#define LOGLS_DEBUG(logger, message)
Log a debug-level message using an iostream-based interface.
 
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
 
#define LOGL_FATAL(logger, message...)
Log a fatal-level message using a varargs/printf style interface.
 
Iterator meant to traverse objects within some limiting distance.
 
This is an auxillary class for matching objects from starlists.
 
std::shared_ptr< const BaseStar > findClosest(const Point &where, const double maxDist, bool(*SkipIt)(const BaseStar &)=nullptr) const
Find the closest with some rejection capability.
 
Iterator beginScan(const Point &where, double maxDist) const
 
double maxBin(double &x, double &y) const
 
void binWidth(double &Hdx, double &Hdy) const
 
void fill(float x, float y, float weight=1.)
 
double Distance(const Point &other) const
 
SegmentList(const BaseStarList &list, const int nStar, const AstrometryTransform &transform=AstrometryTransformIdentity())
 
void cutTail(const int nKeep)
cuts the end of the std::list
 
void copyTo(StarList< Star > ©) const
clears copy and makes a copy of the std::list to copy
 
void fluxSort()
a model routine to sort the std::list
 
A hanger for star associations.
 
StarList< BaseStar > BaseStarList
 
std::list< std::unique_ptr< StarMatchList > > SolList
 
std::unique_ptr< StarMatchList > listMatchCollect(const BaseStarList &list1, const BaseStarList &list2, const AstrometryTransform *guess, const double maxDist)
assembles star matches.
 
std::unique_ptr< AstrometryTransform > listMatchCombinatorial(const BaseStarList &list1, const BaseStarList &list2, const MatchConditions &conditions=MatchConditions())
 
std::unique_ptr< AstrometryTransform > compose(AstrometryTransform const &left, AstrometryTransform const &right)
Returns a pointer to a composition of transforms, representing left(right()).
 
std::list< Segment >::iterator SegmentIterator
 
std::list< Segment >::const_iterator SegmentCIterator
 
SegmentPairList::const_iterator SegmentPairListCIterator
 
SegmentPairList::iterator SegmentPairListIterator
 
BaseStarList::const_iterator BaseStarCIterator
 
std::unique_ptr< AstrometryTransform > listMatchRefine(const BaseStarList &list1, const BaseStarList &list2, std::unique_ptr< AstrometryTransform > transform, const int maxOrder=3)
 
std::list< SegmentPair > SegmentPairList
 
double computeChi2(const StarMatchList &L, const AstrometryTransform &transform)
the actual chi2
 
std::unique_ptr< StarMatchList > matchSearchRotShift(BaseStarList &list1, BaseStarList &list2, const MatchConditions &conditions)
searches a geometrical transformation that goes from list1 to list2.
 
std::unique_ptr< StarMatchList > matchSearchRotShiftFlip(BaseStarList &list1, BaseStarList &list2, const MatchConditions &conditions)
same as above but searches also a flipped solution.
 
std::unique_ptr< AstrometryTransformLinear > listMatchupShift(const BaseStarList &list1, const BaseStarList &list2, const AstrometryTransform &transform, double maxShift, double binSize=0)
searches for a 2 dimensional shift using a very crude histogram method.
 
A base class for image defects.
 
Segment push_back(Segment ... args)
 
Segment sort(Segment ... args)
 
Parameters to be provided to combinatorial searches.
 
double maxSizeRatio() const
 
double minSizeRatio() const
 
std::shared_ptr< const BaseStar > s1
 
friend std::ostream & operator<<(std::ostream &stream, const Segment &segment)
 
Segment(std::shared_ptr< const BaseStar > star1, std::shared_ptr< const BaseStar > star2, const int star1Rank, const AstrometryTransform &transform)
 
std::shared_ptr< const BaseStar > s2
 
double relativeAngle(Segment *other)
 
SegmentPair(Segment *f, Segment *s)