00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00024
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <iostream>
00028
00029 #include <QSet>
00030
00031 #include <QV2DMap>
00032 #include <qvmath.h>
00033
00034 #define SQRT2 1.414213562
00035 #define SIGNATURE(Point) ( (Point.x() + Point.y()) / SQRT2)
00036
00037 void QV2DMap::add(const QPointF &point)
00038 {
00039 insertMulti(SIGNATURE(point), point);
00040 }
00041
00042 QV2DMap::QV2DMap(const QList<QPointF> & points): QMap<double, QPointF>()
00043 {
00044 foreach(QPointF point, points)
00045 add(point);
00046 };
00047
00048 QPointF QV2DMap::getClosestPoint(const QPointF &point) const
00049 {
00050 const double point_signature = SIGNATURE(point);
00051
00052
00053
00054
00055
00056
00057 QMap<double, QPointF>::const_iterator pivot = lowerBound(SIGNATURE(point));
00058 if (pivot == constEnd())
00059 --pivot;
00060
00061 double best_distance = norm2(point - pivot.value());
00062 QPointF best_point = pivot.value();
00063
00064
00065 if (pivot != constBegin())
00066 for (QMap<double, QPointF>::const_iterator i = pivot; i != constBegin(); --i)
00067 {
00068 if (ABS(i.key() - point_signature) >= best_distance)
00069 break;
00070
00071 const double actualDistance = norm2(point - i.value());
00072 if (actualDistance < best_distance)
00073 {
00074 best_distance = actualDistance;
00075 best_point = i.value();
00076 }
00077 }
00078
00079
00080 for (QMap<double, QPointF>::const_iterator i = pivot + 1; i != constEnd(); ++i)
00081 {
00082 if (ABS(i.key() - point_signature) >= best_distance)
00083 break;
00084
00085 const double actualDistance = norm2(point - i.value());
00086 if (actualDistance < best_distance)
00087 {
00088 best_distance = actualDistance;
00089 best_point = i.value();
00090 }
00091 }
00092
00093 return best_point;
00094 }
00095
00096 QList<QPointF> QV2DMap::getClosestPoints(const QPointF &point, const int maxPoints) const
00097 {
00098 const double point_signature = SIGNATURE(point);
00099
00100
00101 if (size() == 0 || maxPoints <= 0)
00102 return QList<QPointF>();
00103
00104 if (size() <= maxPoints)
00105 return values();
00106
00107
00108 int t = 0;
00109 QMap<double, QPointF> closestPoints;
00110 for(QMap<double, QPointF>::const_iterator i = constBegin(); t < maxPoints; ++t, ++i)
00111 closestPoints.insertMulti(norm2(point - i.value()), i.value());
00112
00113
00114 double last_key = (--(closestPoints.end())).key();
00115
00116
00117 QMap<double, QPointF>::const_iterator pivot = lowerBound(SIGNATURE(point));
00118 if (pivot == constEnd())
00119 --pivot;
00120
00121
00122 if (pivot != constBegin())
00123 for (QMap<double, QPointF>::const_iterator i = pivot; i != constBegin(); --i)
00124 {
00125 if (ABS(i.key() - point_signature) >= last_key)
00126 break;
00127
00128 const double actualDistance = norm2(point - i.value());
00129 if (actualDistance < last_key)
00130 {
00131 closestPoints.take(last_key);
00132 closestPoints.insertMulti(actualDistance, i.value());
00133 last_key = (--(closestPoints.end())).key();
00134 }
00135 }
00136
00137
00138 for (QMap<double, QPointF>::const_iterator i = pivot + 1; i != constEnd(); ++i)
00139 {
00140 if (ABS(i.key() - point_signature) >= last_key)
00141 break;
00142
00143 const double actualDistance = norm2(point - i.value());
00144 if (actualDistance < last_key)
00145 {
00146 closestPoints.take(last_key);
00147 closestPoints.insertMulti(actualDistance, i.value());
00148 last_key = (--(closestPoints.end())).key();
00149 }
00150 }
00151
00152 return closestPoints.values();
00153 }
00154
00155 QList<QPointF> QV2DMap::getClosestPoints2(const QPointF &point, const int n) const
00156 {
00157
00158 if (size() == 0 || n <= 0)
00159 return QList<QPointF>();
00160
00161 if (size() <= n)
00162 return values();
00163
00164 QMap<double, QPointF> closestPoints;
00165
00166
00167 foreach(QPointF actual, values())
00168 closestPoints.insertMulti(norm2(point - actual), actual);
00169
00170 return closestPoints.values().mid(0,n);
00171 }
00172
00173 void QV2DMap::test()
00174 {
00175 QSet<QPointF> sourcePointsTemp, destinationPointsTemp;
00176
00177 for (int i = 1; i <= 1000; i++)
00178 sourcePointsTemp.insert(QPointF(rand()%100, rand()%100));
00179
00180 for (int i = 1; i < 1000; i++)
00181 destinationPointsTemp.insert(QPointF(rand()%100, rand()%100));
00182
00183 QList<QPointF> sourcePoints = sourcePointsTemp.values(), destinationPoints = destinationPointsTemp.values();
00184
00185 QV2DMap m = destinationPoints;
00186
00187 for(int i = 0; i < sourcePoints.size(); i++)
00188 {
00189 const QPointF point = sourcePoints[i];
00190 const QList<QPointF> l1 = m.getClosestPoints(point, 50), l2 = m.getClosestPoints2(point, 50);
00191 const QSet<QPointF> temp1 = l1.toSet(), temp2 = l2.toSet();
00192
00193 if (l1.size() != l2.size())
00194 std::cout << "ERROR: different sizes for obtained lists" << std::endl;
00195
00196 bool cond = false;
00197 for(int j = 0; j < l1.size(); j++)
00198 if (ABS(norm2(l1[j] - point) - norm2(l2[j] - point)) > 0.00000001)
00199 cond = true;
00200
00201 if (cond)
00202 {
00203 std::cout << "Error: distances are different" << std::endl;
00204 std::cout << "Point("<< point.x() << ", " << point.y() << ")" << std::endl;
00205 std::cout << "l1 = " << std::endl;
00206 foreach (QPointF p, l1)
00207 std::cout << "\tPoint("<< p.x() << ", " << p.y() << ")\tdistance = " << norm2(p - point) << std::endl;
00208
00209 std::cout << "l2 = " << std::endl;
00210 foreach (QPointF p, l2)
00211 std::cout << "\tPoint("<< p.x() << ", " << p.y() << ")\tdistance = " << norm2(p - point) << std::endl;
00212
00213 }
00214 }
00215 }
00216