7#include "starcorrespondence.h"
10#include "ekos_guide_debug.h"
17int StarCorrespondence::findClosestStar(
double x,
double y,
const QList<Edge> sortedStars,
18 double maxDistance,
double *distance)
const
20 if (x < -maxDistance || y < -maxDistance ||
21 x > imageWidth + maxDistance || y > imageWidth + maxDistance)
24 const int size = sortedStars.
size();
29 const int coarseIncrement = size / 10;
30 if (coarseIncrement > 1)
32 for (
int i = 0; i < size; i += coarseIncrement)
34 if (sortedStars[i].x < x - maxDistance)
44 double bestSquaredDistance = maxDistance * maxDistance;
45 for (
int i = startPoint; i < size; ++i)
47 auto &star = sortedStars[i];
48 if (star.x < x - maxDistance)
continue;
49 if (star.x > x + maxDistance)
break;
50 const double xDiff = star.x - x;
51 const double yDiff = star.y - y;
52 const double squaredDistance = xDiff * xDiff + yDiff * yDiff;
53 if (squaredDistance <= bestSquaredDistance)
56 bestSquaredDistance = squaredDistance;
59 if (distance !=
nullptr) *
distance = sqrt(bestSquaredDistance);
72 sortedToOriginal->
clear();
76 for (
int i = 0; i < stars.
size(); ++i)
77 rx.
push_back(std::pair<int, float>(i, stars[i].x));
78 std::sort(rx.
begin(), rx.
end(), [](
const std::pair<int, float> &a,
const std::pair<int, double> &b)
80 return a.second < b.second;
82 for (
int i = 0; i < stars.
size(); ++i)
84 sortedStars->
append(stars[ rx[i].first ]);
91StarCorrespondence::StarCorrespondence(
const QList<Edge> &stars,
int guideStar)
93 initialize(stars, guideStar);
96StarCorrespondence::StarCorrespondence()
101void StarCorrespondence::initialize(
const QList<Edge> &stars,
int guideStar)
103 qCDebug(KSTARS_EKOS_GUIDE) <<
"StarCorrespondence initialized with " << stars.
size() << guideStar;
105 guideStarIndex = guideStar;
106 float guideX = references[guideStarIndex].x;
107 float guideY = references[guideStarIndex].y;
108 guideStarOffsets.clear();
109 referenceSums.clear();
110 referenceNumPixels.clear();
114 const int numRefs = references.
size();
115 for (
int i = 0; i < numRefs; ++i)
117 const auto &ref = references[i];
118 guideStarOffsets.push_back(Offsets(ref.x - guideX, ref.y - guideY));
119 referenceSums.push_back(ref.sum);
120 referenceNumPixels.push_back(ref.numPixels);
123 initializeAdaptation();
128void StarCorrespondence::reset()
131 guideStarOffsets.clear();
132 referenceSums.clear();
133 referenceNumPixels.clear();
139 int *numFound,
int *numNotFound,
double minFraction)
const
142 constexpr double missingRefStarCost = 100;
144 constexpr double distanceWeight = 1.0;
155 int bestCost = offsets.
size() * missingRefStarCost * (1 - minFraction);
158 if (stars.
size() < minFraction * offsets.
size())
163 const int numStars = stars.
size();
164 int bestStarIndex = -1, bestNumFound = 0, bestNumNotFound = 0;
165 for (
int starIndex = 0; starIndex < numStars; ++starIndex)
167 const float starX = stars[starIndex].x;
168 const float starY = stars[starIndex].y;
172 int numFound = 0, numNotFound = 0;
173 for (
int offsetIndex = 0; offsetIndex < offsets.
size(); ++offsetIndex)
176 if (offsetIndex == guideStarIndex)
continue;
179 if (cost > bestCost)
break;
183 const auto &offset = offsets[offsetIndex];
185 const int closestIndex = findClosestStar(starX + offset.
x, starY + offset.
y,
186 stars, maxDistance, &distance);
187 if (closestIndex < 0)
190 cost += missingRefStarCost;
198 mapping[closestIndex] = offsetIndex;
204 bestStarIndex = starIndex;
205 bestNumFound = numFound;
206 bestNumNotFound = numNotFound;
209 for (
int i = 0; i < mapping.size(); ++i)
210 (*starMap)[i] = mapping[i];
211 (*starMap)[starIndex] = guideStarIndex;
214 *numFound = bestNumFound;
215 *numNotFound = bestNumNotFound;
216 return bestStarIndex;
221 int targetStar)
const
224 int xOffset = offsets[targetStar].x;
225 int yOffset = offsets[targetStar].y;
226 for (
int i = 0; i < offsets.
size(); ++i)
230 (*targetOffsets)[i] = Offsets(0, 0);
234 const double x = offsets[i].x - xOffset;
235 const double y = offsets[i].y - yOffset;
236 (*targetOffsets)[i] = Offsets(x, y);
247 inventedStar.invalidate();
250 float refSum = 0, origSum = 0, refNumPixels = 0, origNumPixels = 0;
251 for (
int i = 0; i < starMap.
size(); ++i)
253 int reference = starMap[i];
256 xPositions.
push_back(stars[i].x - offsets[reference].x);
257 yPositions.
push_back(stars[i].y - offsets[reference].y);
260 refSum += stars[i].sum;
261 refNumPixels += stars[i].numPixels;
262 origSum += referenceSums[reference];
263 origNumPixels += referenceNumPixels[reference];
266 float inventedSum = 0;
267 float inventedNumPixels = 0;
268 if (origSum > 0 && origNumPixels > 0)
271 inventedSum = (refSum / origSum) * referenceSums[guideStarIndex];
272 inventedNumPixels = (refNumPixels / origNumPixels) * referenceNumPixels[guideStarIndex];
275 if (xPositions.
size() == 0)
280 std::sort(xPositions.
begin(), xPositions.
end(), [] (
double d1,
double d2)
284 std::sort(yPositions.
begin(), yPositions.
end(), [] (
double d1,
double d2)
288 const int num = xPositions.
size();
289 double xVal = 0, yVal = 0;
292 const int middle = num / 2;
293 xVal = (xPositions[middle - 1] + xPositions[middle]) / 2.0;
294 yVal = (yPositions[middle - 1] + yPositions[middle]) / 2.0;
298 const int middle = num / 2;
299 xVal = xPositions[middle];
300 yVal = yPositions[middle];
302 inventedStar.x = xVal - offset.x;
303 inventedStar.y = yVal - offset.y;
304 inventedStar.sum = inventedSum;
305 inventedStar.numPixels = inventedNumPixels;
315 for (
int i = 0; i < sortedStarMap.
size(); ++i)
316 (*starMap)[sortedToOriginal[i]] = sortedStarMap[i];
320Edge StarCorrespondence::find(
const QList<Edge> &stars,
double maxDistance,
323 m_NumReferencesFound = 0;
326 foundStar.invalidate();
327 if (!initialized)
return foundStar;
328 int numFound = 0, numNotFound = 0;
334 sortByX(stars, &sortedStars, &sortedToOriginal);
336 const bool alwaysInvent = Options::alwaysInventGuideStar() &&
337 stars.
size() >= minFraction * guideStarOffsets.size();
338 if (!alwaysInvent && Options::alwaysInventGuideStar())
339 qCDebug(KSTARS_EKOS_GUIDE)
340 <<
QString(
"Could not use AlwaysInvent--too few stars: %1 < %2 * %3 (%4)").
arg(stars.
size())
341 .
arg(minFraction, 0,
'f', 2).
arg(guideStarOffsets.size()).
arg(minFraction * guideStarOffsets.size(), 0,
'f', 1);
342 const bool canInvent = allowMissingGuideStar && stars.
size() >= minFraction * guideStarOffsets.size();
346 alwaysInvent ? -1 : findInternal(sortedStars, maxDistance, &sortedStarMap, guideStarIndex,
347 guideStarOffsets, &numFound, &numNotFound, minFraction);
349 if (!alwaysInvent && bestStarIndex > -1)
352 bestStarIndex = sortedToOriginal[bestStarIndex];
353 unmapStarMap(sortedStarMap, sortedToOriginal, starMap);
355 foundStar = stars[bestStarIndex];
356 qCDebug(KSTARS_EKOS_GUIDE)
357 <<
"StarCorrespondence found guideStar at " << bestStarIndex <<
"found/not"
358 << numFound << numNotFound;
359 m_NumReferencesFound = numFound;
361 else if (alwaysInvent || canInvent)
368 qCDebug(KSTARS_EKOS_GUIDE)
369 <<
"Trying to invent. StarCorrespondence did NOT find guideStar. Found/not"
370 << numFound << numNotFound <<
"minFraction" << minFraction <<
"maxDistance" << maxDistance;
372 qCDebug(KSTARS_EKOS_GUIDE)
373 <<
"Using AlwaysInvent. #stars" << stars.
size() <<
"minFraction" << minFraction <<
"maxDistance" << maxDistance;
375 int bestNumFound = 0;
376 int bestNumNotFound = 0;
378 bestInvented.invalidate();
387 for (
int gStarIndex = 0; gStarIndex < guideStarOffsets.size(); gStarIndex++)
389 if (!alwaysInvent && gStarIndex == guideStarIndex)
392 makeOffsets(guideStarOffsets, &gStarOffsets, gStarIndex);
394 int detectedStarIndex = findInternal(sortedStars, maxDistance, &newStarMap,
395 gStarIndex, gStarOffsets,
396 &numFound, &numNotFound, minFraction);
397 if (detectedStarIndex >= 0 && numFound > bestNumFound)
399 Edge invented = inventStarPosition(sortedStars, newStarMap, gStarOffsets,
400 guideStarOffsets[gStarIndex]);
401 if (invented.x < 0 || invented.y < 0)
404 bestInvented = invented;
405 bestNumFound = numFound;
406 bestNumNotFound = numNotFound;
407 sortedStarMap = newStarMap;
411 if (numNotFound <= 1 || bestNumFound >= 7)
415 if (bestNumFound > 0)
418 unmapStarMap(sortedStarMap, sortedToOriginal, starMap);
419 qCDebug(KSTARS_EKOS_GUIDE)
420 <<
"StarCorrespondence found guideStar (invented) at "
421 << bestInvented.x << bestInvented.y <<
"found/not" << bestNumFound << bestNumNotFound;
422 m_NumReferencesFound = bestNumFound;
424 if (alwaysInvent && adapt)
425 adaptOffsets(stars, *starMap, bestInvented.x, bestInvented.y);
429 else qCDebug(KSTARS_EKOS_GUIDE) <<
"StarCorrespondence could not invent guideStar.";
431 else qCDebug(KSTARS_EKOS_GUIDE) <<
"StarCorrespondence could not find guideStar.";
433 if (adapt && (bestStarIndex != -1))
434 adaptOffsets(stars, *starMap, foundStar.x, foundStar.y);
442void StarCorrespondence::initializeAdaptation()
445 const double timeConstant = 25.0;
446 alpha = 1.0 / pow(timeConstant, 0.865);
449 originalGuideStarOffsets = guideStarOffsets;
452void StarCorrespondence::adaptOffsets(
const QList<Edge> &stars,
const QVector<int> &starMap,
double x,
double y)
454 const int numStars = stars.
size();
455 if (starMap.
size() != numStars)
457 qCDebug(KSTARS_EKOS_GUIDE) <<
"Adapt error: StarMap size != stars.size()" << starMap.
size() << numStars;
461 for (
int i = 0; i < numStars; ++i)
465 const int refIndex = starMap[i];
466 if (refIndex == -1 || refIndex == guideStarIndex)
469 if ((refIndex >= references.
size()) || (refIndex < 0))
471 qCDebug(KSTARS_EKOS_GUIDE) <<
"Adapt error: bad refIndex[" << i <<
"] =" << refIndex;
476 const double xOffset = stars[i].x - x;
477 const double yOffset = stars[i].y - y;
478 const double currentXOffset = guideStarOffsets[refIndex].x;
479 const double currentYOffset = guideStarOffsets[refIndex].y;
480 const double newXOffset = alpha * xOffset + (1 - alpha) * currentXOffset;
481 const double newYOffset = alpha * yOffset + (1 - alpha) * currentYOffset;
485 constexpr double maxMovement = 2.5;
486 if ((fabs(newXOffset - originalGuideStarOffsets[refIndex].x) < maxMovement) &&
487 (fabs(newYOffset - originalGuideStarOffsets[refIndex].y) < maxMovement))
489 guideStarOffsets[refIndex].x = newXOffset;
490 guideStarOffsets[refIndex].y = newYOffset;
KOSM_EXPORT double distance(const std::vector< const OSM::Node * > &path, Coordinate coord)
void append(QList< T > &&value)
void push_back(parameter_type value)
void resize(qsizetype size)
qsizetype size() const const
QString arg(Args &&... args) const const