leonardo ([info]leonardo_m) wrote,
@ 2008-03-28 03:56:00
Previous Entry  Add to memories!  Tell a Friend  Next Entry
Entry tags:c++, d language, python

Convex Hull in D
From Wikipedia I have found a link to simple C++ code to find the Convex Hull of points in 2D (about 795 lines with comments, and it crashes with n=10000 random integer 2D points):
http://www.microplop.com/assets_c/2007/11/convexhull.h
http://www.microplop.com/assets_c/2007/11/main.cpp

This is (nice) Python code written by David Eppstein (Mar 2002):
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/117225

And the following templated function is its translation to D (about 14 lines without comments):

/** Returns the array of the points on the convex hull of a list of 2D
points in O(n log n) time. A point is a static array of length 2. */
T[2][] convexHull2D(T)(T[2][] points) {
  // Andrew's monotone chain algorithm
  T[2][] U, L;
  // Return positive number if p-q-r are clockwise, neg if ccw, zero if colinear
  T orientation(T[2] p, T[2] q, T[2] r) {
    return (q[1]-p[1])*(r[0]-p[0]) - (q[0]-p[0])*(r[1]-p[1]);
  }
  foreach(p; points.sort) {
    while (U.length > 1 && orientation(U[$-2],U[$-1],p) <= 0)
      U.length = U.length - 1;
    while (L.length > 1 && orientation(L[$-2],L[$-1],p) >= 0)
      L.length = L.length - 1;
    U ~= p; L ~= p;
  }
  return U.length ? U[0 .. $-1] ~ L.reverse : U;
}

import std.stdio: writefln;
void main() {
  int[2][] points = [[2, 284], [12, 465], [339, 495], [641, 815], [171, 37],
                     [99, 694], [207, 633], [648, 855], [713, 300], [331, 563]];
  writefln(convexHull2D(points));
}

If you want to make it faster you can use my D libs and replace this line:
foreach(p; points.sort) {
With:
foreach(p; points.fastSort()) {
This convexHull2D() code isn't optimized for speed, but for small practical situations it's enough, it's able to find the convex hull of 1_000_000 float 2D points uniform in [0,1]^2 in 6.5 seconds (convex hull of 38 points) on a Pentium3 500 MHz.
On 200_000 2D points (double) it needs 1.5 seconds, while the same code in Python (a different dataset) needs 12.6 s and Psyco 5.2 s. This shows that in some situations D allows to write (templated) programs not much more complex than Python ones, despite running quite faster.

This page on Wikipedia shows another simpler way to speed up the code:
http://en.wikipedia.org/wiki/Convex_hull_algorithms

/>The idea is to quickly exclude many points that would not be part of the convex hull anyway. This method is based on the following idea. Find the two points with the lowest and highest x-coordinates, and the two points with the lowest and highest y-coordinates. (Each of these operations takes O(n).) These four points form a convex quadrilateral, and all points that lie in this quadrilateral (except for the four initially chosen vertices) are not part of the convex hull. Finding all of these points that lie in this quadrilateral is also O(n), and thus, the entire operation is O(n). Optionally, the points with smallest and largest sums of x- and y-coordinates as well as those with smallest and largest differences of x- and y-coordinates can also be added to the quadrilateral, thus forming an irregular convex octagon, whose insides can be safely discarded.<



(Read 7 comments) - (Post a new comment)

Re: Convex Hull
[info]zzzzrrr
2008-03-29 04:05 pm UTC (link)
"How can you tell how efficient it is? Have you tested it on your PC?"

No, I have not actually tested it, but since it's based on Andrew's monotone chain algorithm, I'm going to assume that Eppstein's implementation is functionally the same as the one I'm using...? In any case, the code looks much more compact and efficient.

I've taken a quick look trough your Big D library and you have a treasure trove of great code! Have you thought about moving it to www.dsource.org as a project?

I'm currently working on a 2D Rigid Body dynamics engine, and I was wondering if you may have some advice on how to implement a particular task...

You can find my project code and demo here: http://www.dsource.org/projects/blaze

Basically, I've added a continuous collision detection algorithm to my physics engine (see demo #9), and I need to create a list of potentially colliding objects and sort them by time of impact (TOI). Some objects may have more than one potential contact, and I need to prune away all the potential contacts from the list that have a greater TOI for each particular object.

For example, I have four rigid bodies A,B,C, and D. B may collide with either A,C, or D within the next frame. Contacts AB, BC, and BD have been added to the contact list with their TOI and contact information. I need to sort the list and prune away all the contacts with B that have a TOI greater than the smallest set. Also keep in mind that there will be other potential contact pairs in the list that also need to be sorted and pruned by TOI... such as AC, AD, CD, etc...

Do you have any advice for a quick "sort and prune" algorithm of this type?

Any help/suggestions you could contribute would be greatly appreciated!

Thanks,
Mason






(Reply to this) (Parent)(Thread)

Re: Convex Hull
[info]leonardo_m
2008-03-29 06:56 pm UTC (link)
your Big D library and you have a treasure trove of great code!

Thank you, I update it daily/weekly, I try to write good code, but the whole lib is a bit messy anyway. The things I may add in some of the next days: the missing set methods, better memory management of dynamic arrays, opCat() method among some lazy iterables (or maybe a simpler xchain()). Later I'll try to add a fast Deque data structure, at the moment it's half finished.


Have you thought about moving it to www.dsource.org as a project?

dsource maintainers have ignored my request twice.

For Blaze, I think you need a "priority queue" data structure, able to be filtered quickly, so it may be actually implemented as a B+ tree or something similar (but something simpler may be enough too). My future Deque will not help you much.

(Reply to this) (Parent)(Thread)

Re: Convex Hull
[info]zzzzrrr
2008-03-30 06:43 pm UTC (link)
Thanks a lot for the Priority Queue tip! I've done a little reading, it looks like exactly what I need! Much appreciated. Now the difficult/fun part will be to create an efficient implementation.

As for the dsource.org moderators not replaying to your requests, I would encourage you not to give up. Your library has a lot to offer for the D community! If you would like some help, let me know and I'll send off a few e-mails to draw attention to your requests.

Thanks,
Mason

(Reply to this) (Parent)


(Read 7 comments) - (Post a new comment)

Create an Account
Forgot your login or password?
Login w/ OpenID
English • Español • Deutsch • Русский…