Skip Menu |

This queue is for tickets about the Collision-2D CPAN distribution.

Report information
The Basics
Id: 60586
Status: open
Priority: 0/
Queue: Collision-2D

People
Owner: Nobody in particular
Requestors: smueller [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: (no value)
Fixed in: (no value)



Subject: Implement polygon collisions using Math::Clipper
Hi, out of idle curiosity, I wrapped a simple C++ library for polygon clipping (i.e. polygon intersections and thus collision detection) for Perl yesterday. The result is on github (in account my "tsee") and on CPAN as Math::Clipper. Right now, Math::Clipper takes its arguments as nested array references (see docs), but ideally, Collision::2D would be able to pass polygons as opaque and efficient C/XS objects. I'm all open for adding an interface to Math::Clipper to do this, but I'm afraid there'd be a circular dependency between the two modules. Ideas and patches welcome. Also, I haven't thought about how polygon-circle intersections (or collisions) could be efficiently implemented. If the circle is small vs. the polygon, checking all the polygon points is not enough for concave polygons. Best regards, Steffen
Hi, Steffen. Nice portfolio :) Anyways, perhaps the words we use are ambiguous. In the Collision::2D docs, 'intersection' is synonymous with 'static collision', where 'collision' mostly means 'continuous collision' or 'dynamic collision', where there is an additional time dimension. Unless Math::Clipper can somehow clip polyhedrons, I have a hard time seeing how it can detect continuous collisions. I do appreciate the offer, though. I don't think circle-polygon static collisions are that difficult. Try drawing a ray from the center of the circle to infinity. If the number of edges that it hits is odd, the center of the circle is inside the poly. If the circle is outside, then check if any edges intersect with the circle, and check if some corner is in the circle. Dynamic collisions would not be any more complicated, if/when there is a line-segment type. Zach
Hi Zach, thanks for your quick response. Your suggestion about circle-polynomial collisions makes perfect sense. Unfortunately, the note about intersections vs. collisions seems quite valid as well. The one thing I probably don't understand sufficiently is the "interval" parameter of the dynamic collision detection. It's not very clearly documented and I had interpreted it as a time step for iterating dynamic collisions. Without looking at the implementation, I assumed that it did something like while (!intersection(@obj)) {time += step; kinematics(@obj)} with an appropriate stop condition. Maybe you could add an explanation of the interval parameter to the docs? Or did I just miss it? Reading the ::Collision docs, it refers to the exact time of collision, so it can't be doing just what I wrote above. Thanks for your patience! Best regards, Steffen PS: If I wrote an XSUB constructor that can handle named arguments, would you be open for converting the pure_perl_new(%hash) => _xsub_new(@list) double-call to a single XS constructor? It seems an easy performance win for cases with lots of objects. But maybe I should fire up a profiler before I do premature optimization...
Subject: Re: [rt.cpan.org #60586] Implement polygon collisions using Math::Clipper
Date: Sun, 29 Aug 2010 04:00:41 -0400
To: bug-Collision-2D [...] rt.cpan.org
From: Zach Morgan <zpmorgan [...] gmail.com>
I'm sorry Steffen, I somehow missed this message earlier. It seems that you have the wrong idea about continuous collision detection. It is much more precise than a series of static collision tests. For example, if you fling a particle at a wall, and you know its precise velocity & location at t=0, then it is trivial to determine when it will collide with the wall. If this is implemented using a bunch of static tests, it will be slower than necessary, and you wouldn't know the precise moment of collision. 'interval' is the maximum time component that you're interested in. If you'd like explanations for how I handled the various types of collisions, I'd be happy to explain it. I mostly just worked it out with basic geometrical equations. Also, about the constructor, wouldn't an xsub constructor with named arguments still use a hash? Do you think it would boost performance much? I think that converting some of the point collision routines would be a much bigger gain. (some collision tests are broken down into multiple point collision tests) Thanks, Zach On 8/22/10, Steffen Mueller via RT <bug-Collision-2D@rt.cpan.org> wrote: Show quoted text
> Queue: Collision-2D > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=60586 > > > Hi Zach, > > thanks for your quick response. Your suggestion about circle-polynomial > collisions makes perfect sense. > > Unfortunately, the note about intersections vs. collisions seems quite > valid as well. The one thing I probably don't understand sufficiently is > the "interval" parameter of the dynamic collision detection. It's not > very clearly documented and I had interpreted it as a time step for > iterating dynamic collisions. Without looking at the implementation, I > assumed that it did something like > > while (!intersection(@obj)) {time += step; kinematics(@obj)} > > with an appropriate stop condition. > > Maybe you could add an explanation of the interval parameter to the > docs? Or did I just miss it? Reading the ::Collision docs, it refers to > the exact time of collision, so it can't be doing just what I wrote above. > > Thanks for your patience! > > Best regards, > Steffen > > PS: If I wrote an XSUB constructor that can handle named arguments, > would you be open for converting the pure_perl_new(%hash) => > _xsub_new(@list) double-call to a single XS constructor? It seems an > easy performance win for cases with lots of objects. But maybe I should > fire up a profiler before I do premature optimization... >
RT-Send-CC: zpmorgan [...] gmail.com
Hi Zach, On Sun Aug 29 04:00:53 2010, zpmorgan@gmail.com wrote: Show quoted text
> I'm sorry Steffen, I somehow missed this message earlier.
No worries. Show quoted text
> It seems that you have the wrong idea about continuous collision > detection.
Indeed, I originally had the wrong idea. Show quoted text
> If you'd like explanations for how I handled the various types of > collisions, I'd be happy to explain it. I mostly just worked it out > with basic geometrical equations.
That's fine. I think I could do the math, too. And I always have the code to look at. Show quoted text
> Also, about the constructor, wouldn't an xsub constructor with named > arguments still use a hash? Do you think it would boost performance > much? I think that converting some of the point collision routines > would be a much bigger gain. (some collision tests are broken down > into multiple point collision tests)
Hmm. The constructor could still use a hash. Or it could walk the arguments doign flip/flop with the expected key/value pairs. The big win would be eliminating the extra entersub call of the Perl function wrapper. Furthermore, calling XSUBs is faster than ordinary subs, so you win some more. Below is the code (from Class::XSAccessor) that implements a plain dumb constructor a la "return bless {@_}=>$class" for a Perl-hash based object. You'd want to either create a hash (without blessing it) and then hv_fetch from there to get the values for the C object or, as I wrote above, just walk the argument list doing strEQ in an if or even using a static hash map/switch for the keyname => struct member conversion. Naturally, these constructors could be generated from a list of valid keys and struct member names using macros. void constructor(class, ...) SV* class; PREINIT: int iStack; HV* hash; SV* obj; const char* classname; PPCODE: if (sv_isobject(class)) { classname = sv_reftype(SvRV(class), 1); } else { if (!SvPOK(class)) croak("Need an object or class name as first argument to the constructor."); classname = SvPV_nolen(class); } hash = (HV *)sv_2mortal((SV *)newHV()); obj = sv_bless( newRV_inc((SV*)hash), gv_stashpv(classname, 1) ); if (items > 1) { if (!(items % 2)) croak("Uneven number of arguments to constructor."); for (iStack = 1; iStack < items; iStack += 2) { HE *he; he = hv_store_ent(hash, ST(iStack), newSVsv(ST(iStack+1)), 0); if (!he) { croak("Failed to write value to hash."); } } } PUSHs(sv_2mortal(obj)); Back to the original topic. I believe I figured out an algorithm that'll detect polygon-polygon collision (yes, the dynamic type). I haven't really done the math with pencil and paper, but it should be around O(n*m) where n/m are the number of vertexes in the two polygons that are involved. First, we boost the scene so that one of the polygons is at rest (O(n+m)). To determine whether the polygons will collide at all, we orthogonally project the vertexes of both polygons on the line that is orthogonal to the direction of movement of the moving polygon (O(n+m) again). For each polygon, we find the outermost points on the line. Then, if the two line segments intersect, the polygons will collide (unless the direction of movement is going away from the second polygon). So this should be O(n) overall. Then, do get the actual collision, we use that one of the polygons isn't moving. The collision must happen between one of the vertexes of either of the polygons with an edge of the respective other polygon. So we use the line trajectory of each vertex in the moving polygon and calculate the intersection point with each edge (or the line it's in) of the static polygon. We verify that the point is within the edge. If so, we get the collision time. Repeat with switched roles. Then we calculate the minimum of the collision times. This part should be O(n*m). Of course, the difficult bit is always handling all the edge cases such as head-on vertex-vertex collision. It doesn't seem like I'll get the time to implement this any time soon, but I thought I'd put this out there regardless. Cheers, Steffen
RT-Send-CC: zpmorgan [...] gmail.com
Arg. The code was mangled. The original is here: http://cpansearch.perl.org/src/SMUELLER/Class-XSAccessor-1.07_02/XS/Hash.xs