Хорошо, много вещей, чтобы упомянуть здесь ...
Для вашего первого кода, НИКОГДА НЕ ИСПОЛЬЗУЙТЕ API Contacts.People.XX
, если серьезно, для чего угодно, убедитесь, что вы ничего не импортируете из People
или не используете какой-либо из его API, это очень очень старый API, который был устарел много лет назад и даже не поддерживается некоторыми устройствами.
Относительно вашего второго кода, множества ошибок и проблем, которые я попытался исправить в своем коде ниже, но специально для вашего требования к производительности, обратите внимание, что вам не нужно applyBatch
для каждого контакта, если вы Создайте много контактов одновременно, можно поместить множество операций в ops
ArrayList
и применить их все за один раз - намного быстрее!
Примечания:
ACCOUNT_TYPE
/ ACCOUNT_NAME
чем-то связанным с вашим приложением. Я добавил к этому коду два постоянных значения MY_ACCOUNT_TYPE
/ MY_ACCOUNT_NAME
, которые вам нужно будет определить.
ArrayList<ContentProviderOperation> ops = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
createContact(ops, name, phone);
if (i % 100 == 0) { // experiment with different batch sizes to achieve best performance times
try {
contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
} catch (RemoteException | OperationApplicationException e) {
Log.e(TAG, "error applying batch: ", e);
}
ops = new ArrayList<>();
}
}
private void createContact(ArrayList<ContentProviderOperation> ops, String name, String phone) {
ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
.withValue(RawContacts.ACCOUNT_TYPE, MY_ACCOUNT_TYPE)
.withValue(RawContacts.ACCOUNT_NAME, MY_ACCOUNT_NAME).build());
int indexOfRawContactIdOperation = ops.size() - 1;
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, indexOfRawContactIdOperation)
.withValue(ContactsContract.Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
.withValue(StructuredName.DISPLAY_NAME, name)
.build());
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, indexOfRawContactIdOperation)
.withValue(ContactsContract.Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
.withValue(Phone.NUMBER, number)
.withValue(Phone.TYPE, Phone.TYPE_MOBILE).build());
}
С неотсортированным списком Вы не будете действительно знать, какие точки включать в каждый сегмент, таким образом, я предполагаю, Вы могли просто пойти с самой близкой точкой.
Один путь мог состоять в том, чтобы выбрать стартовую точку наугад и выбрать самую близкую точку как следующий вопрос на каждом шаге. Добавьте первые две точки к набору S.
Соответствуйте строке к точкам в S, пока RMS не превышает некоторое значение, затем очистите S и запустите новую строку.
Пересечение последовательных строк было бы конечными точками сегментов.
Интерполяция Bezier может соответствовать Вашей проблеме.
Это не обращается к упорядочиванию точек в путь, однако; существует много подходов для рассмотрения:
Если Ваши точки друг близко к другу, Вы можете нормальные "прямые" строки (ортогональные строки). Используя нормальные алгоритмы сглаживания. Вы видите мир, как являющийся плоским.
Если они далеко друг от друга, необходимо компенсировать округление земли, при помощи больших кругов для навигации от точка-точка. Иначе Ваши прямые линии сделают более длинный путь.
Это - Ваш выбор, если точка слишком далека для создания прямых линий.
Далее необходимо знать, должны ли Вы "посетить" каждую точку или просто должны пойти рядом, и как около той близости.
Если необходимо отправить курс (курсы) в плоскость, поставку или другого путешественника, вероятно, необходимо посетить каждую точку. Если Вы получаете данные GPS из объекта, Вы, вероятно, просто хотите вывести курс на печать об экране и удалить шум.
После наблюдения Ваших редактирований: Если это - объект, перемещающий некоторую переправу, Вы хотите вывестись на печать, Вы могли бы хотеть сглаживать направление и скорость вместо значений x/y. (Создание Ваших измеренных значений (x) имеет фиксированный и увеличивающийся Y-интервал, делает сглаживание намного легче.)
Вот эвристический взлом, который мог бы решить проблему упорядочивания для данных, если
Продолжите двигаться как это:
Теперь у Вас есть новый список точек q1.. qn, которые заказаны.
Первое, что пришло на ум, очень грубо, и только работает при довольно хороших условиях...
Самопересечение поведения может, вероятно, быть улучшено путем требования на шаге (5), чтобы новая спроектированная строка легла в некотором максимальном углу предыдущего.
Проблема с Кривой Безье, это, на самом деле не идет, хотя точки, которые Вы выбрали и даже при том, что образцы точек искажены немного; кривая Безье могла бы на самом деле быть милями прочь.
Лучшее приближение и решение, которое, кажется, напоминает исходное изображение путь лучше, являются Шлицом Catmull-Rom, потому что это действительно работает хотя все точки в кривой.
Мой подход должен был бы сначала отсортировать Ваш список точек, затем использовать кривую Безье.
Прием является, конечно, сортировкой. Запустите с одной случайной точки и найдите ближайшую точку. Предположите, что эти два соединены. С теми двумя конечными точками найдите ближайшие точки им. Предположите, что тот с меньшим расстоянием до он - конечная точка, подключен к той точке. Повторитесь, пока все точки не будут соединены.
Я предполагаю, что существуют все еще некоторые проблемы с этим подходом, но возможно можно использовать его в качестве начальной точки (предназначенная игра слов).
Править: Можно несколько раз делать это с различными начальными точками и затем видеть, где результаты отличаются. Это, по крайней мере, вселяет в Вас некоторую веру, какие точки подключены друг к другу.
Совершенно другой подход, который не требует другого ограничения, но деталей, может зависеть от Вашего приложения. Это sghould работают лучше всего, если у Вас есть "плотное облако точек" вокруг пути.
Используйте функцию "стоимости", которая определяет различие между кривой и облаком точек. Используйте параметрическую кривую и стандартный алгоритм оптимизации. - ИЛИ - Начинают с прямой кривой от запуска заканчиваться, затем использовать генетический алгоритм для изменения его.
Типичная функция стоимости состояла бы в том, чтобы взять наименьшее расстояние между каждой точкой и кривой, и суммировать квадраты.
У меня есть недостаточно опыта предложить оптимизацию или генетический алгоритм, но я уверен, что это может быть сделано :)
Я мог вообразить генетический алгоритм следующим образом: путь будет создан из Waypoints. Запустите с помещения N waypoints в прямой строке от запуска для окончания. (N может быть выбран в зависимости от проблемы). Мутации могли быть:
Необходимо будет включать общую длину в функцию стоимости. Разделение не могло бы быть необходимо, или возможно x ("шанс разделения"), возможно, должен был бы уменьшиться, поскольку больше waypoints представлено. Вы можете или не можете хотеть подавать заявку (2) к запуску - и конечная точка.
Была бы забава попробовать это...
Я беру его, что "неотсортированный список" означает, что, в то время как Ваш набор точек завершен, Вы не знаете то, что приказывает, чтобы они были перемещены через?
Нормально распределенный шум должен быть в основном проигнорирован. Нам не дают абсолютно никакой информации, которая позволяет нам предпринимать любую попытку восстановить исходный, нешумный путь. Таким образом, я думаю лучшее, которое мы можем сделать, предполагают, что точки корректны.
На данном этапе задача состоит из, "находят лучший путь через ряд точек", с "лучшим" оставил неопределенным. Я сделал на скорую руку некоторый код, который пытается заказать ряд точек в евклидово пространстве, предпочитая упорядочивания, которые приводят к более прямым строкам. В то время как метрику было легко реализовать, я не мог думать о хорошем способе улучшить упорядочивание на основе этого, таким образом, я просто случайным образом подкачиваю точки, ища лучшее расположение.
Так, вот некоторый код Схемы PLT, который делает это.
#lang scheme
(require (only-in srfi/1 iota))
; a bunch of trig
(define (deg->rad d)
(* pi (/ d 180)))
(define (rad->deg r)
(* 180 (/ r pi)))
(define (euclidean-length v)
(sqrt (apply + (map (lambda (x) (expt x 2)) v))))
(define (dot a b)
(apply + (map * a b)))
(define (angle-ratio a b)
(/ (dot a b)
(* (euclidean-length a) (euclidean-length b))))
; given a list of 3 points, calculate the likelihood of the
; angle they represent. straight is better.
(define (probability-triple a b c)
(let ([av (map - a b)]
[bv (map - c b)])
(cos (/ (- pi (abs (acos (angle-ratio av bv)))) 2))))
; makes a random 2d point. uncomment the bit for a 3d point
(define (random-point . x)
(list (/ (random 1000) 100)
(/ (random 1000) 100)
#;(/ (random 1000) 100)))
; calculate the likelihood of an entire list of points
(define (point-order-likelihood lst)
(if (null? (cdddr lst))
1
(* (probability-triple (car lst)
(cadr lst)
(caddr lst))
(point-order-likelihood (cdr lst)))))
; just print a list of points
(define (print-points lst)
(for ([p (in-list lst)])
(printf "~a~n"
(string-join (map number->string
(map exact->inexact p))
" "))))
; attempts to improve upon a list
(define (find-better-arrangement start
; by default, try only 10 times to find something better
[tries 10]
; if we find an arrangement that is as good as one where
; every segment bends by 22.5 degrees (which would be
; reasonably gentle) then call it good enough. higher
; cut offs are more demanding.
[cut-off (expt (cos (/ pi 8))
(- (length start) 2))])
(let ([vec (list->vector start)]
; evaluate what we've started with
[eval (point-order-likelihood start)])
(let/ec done
; if the current list exceeds the cut off, we're done
(when (> eval cut-off)
(done start))
; otherwise, try no more than 'tries' times...
(for ([x (in-range tries)])
; pick two random points in the list
(let ([ai (random (vector-length vec))]
[bi (random (vector-length vec))])
; if they're the same...
(when (= ai bi)
; increment the second by 1, wrapping around the list if necessary
(set! bi (modulo (add1 bi) (vector-length vec))))
; take the values from the two positions...
(let ([a (vector-ref vec ai)]
[b (vector-ref vec bi)])
; swap them
(vector-set! vec bi a)
(vector-set! vec ai b)
; make a list out of the vector
(let ([new (vector->list vec)])
; if it evaluates to better
(when (> (point-order-likelihood new) eval)
; start over with it
(done (find-better-arrangement new tries cut-off)))))))
; we fell out the bottom of the search. just give back what we started with
start)))
; evaluate, display, and improve a list of points, five times
(define points (map random-point (iota 10)))
(define tmp points)
(printf "~a~n" (point-order-likelihood tmp))
(print-points tmp)
(set! tmp (find-better-arrangement tmp 10))
(printf "~a~n" (point-order-likelihood tmp))
(print-points tmp)
(set! tmp (find-better-arrangement tmp 100))
(printf "~a~n" (point-order-likelihood tmp))
(print-points tmp)
(set! tmp (find-better-arrangement tmp 1000))
(printf "~a~n" (point-order-likelihood tmp))
(print-points tmp)
(set! tmp (find-better-arrangement tmp 10000))
(printf "~a~n" (point-order-likelihood tmp))
(print-points tmp)
Кажется знанием 'золотой кривой' от ответов до вопросов я предложил бы найти Кривую Безье 'золотой кривой', как предложено @jamesh и потянуть это.
Сколько точек Вы имеете?
Кривая Безье, как упомянуто, является хорошей идеей, если у Вас есть comparedly немного точек. Если у Вас есть много точек, buiding кластеры, как предложено dmckee.
Однако Вам также нужно другое ограничение для определения порядка точек. Было много хороших предложений для того, как к выбрал точки, но если Вы не представляете другое ограничение, любой дает возможное решение.
Возможные ограничения я могу думать:
Во всех случаях для встречи ограничения, вероятно, необходимо протестировать все перестановки последовательности. Если Вы запускаете с "хорошего предположения", Вы, cayn завершают другие быстро.