I have a List L
with some terms like range(2,3),
where the first element is the term with the lowest Y, now I need to sort the other elements of the list L (the first element will remain unchanged), I need to sort them by polar angle in counterclockwise order. If polar angle of two points is same, then I need to put the nearest term first. I defined the predicate angle2d/2:
angle2d(A, B, R) :-
A =.. [_,Ax,Ay],
B =.. [_,Bx,By],
R is atan2((Ay-By),(Ax-Bx)).
that give me the counter clockwise angle between 2 points, but i didn't get how to create the predicate sort_list/2 that will sort my n-1 points (the first one element of the list will remain unchanged) by their counter clockwise angle with the first element (point) of the list.
As a general method for sorting by some weird custom criterion, first define you compare_custom/3
predicate, and then use it with a known sorting algorithm. In SWI you can use the predsort/3
predicate that is defined as following:
predsort(+Pred, +List, -Sorted)
Sorts similar to sort/2, but
determines the order of two terms by calling Pred(-Delta, +E1, +E2) .
This call must unify Delta with one of <, > or =. If the built-in
predicate compare/3
is used, the result is the same as sort/2. See
also keysort/2.
You should also take a look at the predefined compare/3
:
compare(?Order, @Term1, @Term2)
Determine or test the Order between
two terms in the standard order of terms. Order is one of <, > or =,
with the obvious meaning.
I did this:
sort_angle([], _).
sort_angle([_|[]], _).
sort_angle([_,_|[]], _).
sort_angle(List, SortedList) :-
predsort(sort_me,[_|List], SortedList).
sort_me(<, A, B) :- angle2d(H,A,X), angle2d(H,B,Y), X<Y.
sort_me(>, A, B) :- angle2d(H,A,X), angle2d(H,B,Y), X>Y.
sort_me(=, A, B) :- angle2d(H,A,X), angle2d(H,B, Y), X=Y.
But I don't know, in the sort_me predicate how to tell that H is the first element of my list... how can I tell it ?