Nearest Neighbor Algo
Community Forums/General Help/Nearest Neighbor Algo
| ||
Anyone know much about this algo. I need to create a function that can take a list of entities and report the x closest entities to the source entity. the ent fields represent Blitz3D entities. Example : Type FieldObjects field ent End type Type ReportedObjects Field ent end type Function NearestEnt(sourceent,num_objects) ;algo here creates new ReportedObject type for each ;reported object, up to num_objects of them using the list ;of Fieldobjects as possible candidates end function I have looked at a few artciles about nearest neighbor algo, but the ones ive read so far i couldnt get my head around. I need the "Nearest Neighbor algo for dummies" version of the arcticle :) |
| ||
You could iterate through all entities and work out the relative distance for each:dist = ((x2-x1) * (x2-x1)) + ((y2-y1) * (y2-y1)) + ((z2-z1) * (z2-z1))If you just want to know which is nearest, you don't need to waste time calculating the square root (which would give the actual distance). Use the above algo, and the one with the smallest result, is the nearest. |
| ||
thanks for the input.. heres what ive come up with, feel free to improve on it and share :) Its not the speedy algo I was trying to learn, i gave up on that :);multi dx light system for tiny tanks. build 1.0 Type dxlightpos Field x#,y#,z# Field r,g,b Field range Field dist# Field followent ;not used yet End Type ;using 7 lights, one is reserverd for sunlight Dim dxlight(7) Function initlights() ;called between maps, remove lightpositions Delete Each dxlightpos For i=1 To 7 If dxlight(i)=0 Then dxlight(i)=CreateLight(2) PositionEntity dxlight(i),9000,-9000,9000 LightRange dxlight(i),1 Next End Function Function removelights() ;called on game exit remove all Delete Each dxlightpos For i=1 To 7 If dxlight(i)<>0 Then FreeEntity dxlight(i) dxlight(i)=0 EndIf Next End Function ;have not speed tested this yet, but I see no reason to call it every frame, once every 300ms should be smooth enough Function UpdateLights(source,numberof=7) For dxl.dxlightpos=Each dxlightpos dxl\dist#=distance(dxl\x,dxl\y,dxl\z,EntityX(source,1),EntityY(source,1),EntityZ(source,1)) Next bestdist#=99999999 Sorted=0 While Sorted=0 amlower=0 For dxl.dxlightpos =Each dxlightpos If dxl\dist<bestdist Then amlower=1 Insert dxl.dxlightpos Before First dxlightpos bestdist=dxl\dist Exit EndIf Next If amlower=0 Then sorted=1 Wend i=0 For dxl.dxlightpos=Each dxlightpos i=i+1 LightColor dxlight(i),dxl\r,dxl\g,dxl\b LightRange dxlight(i),dxl\range PositionEntity dxlight(i),dxl\x,dxl\y,dxl\z If i=numberof Then Exit Next End Function |
| ||
Where's your Distance() function? Assuming that's all in order, just time the function over a million or so iterations to work out how fast it is. 8 loops per call probably won't even register 1ms so I think you'll be safe at that. |
| ||
sorry, take your pickFunction Distance#( x#, y#, z#, x2#, y2#, z2# ) value#=Sqr((x#-x2#)*(x#-x2#)+(y#-y2#)*(y#-y2#)+(z#-z2#)*(z#-z2#)) Return value# End Function Function DistanceF#( x#, y#, z#, x2#, y2#, z2# ) value#=(x#-x2#)*(x#-x2#)+(y#-y2#)*(y#-y2#)+(z#-z2#)*(z#-z2#) Return value# End Function The actual number of light positions to check is unlimited, its only 7 active at any one time. Proper light placement vs lightrange should be able to create a well lit scene i think. edit: somthing is not quite right, i can see visually that im closer to certain lights but they dont activate until im much close than I should be. |
| ||
You might have to Abs() each subtraction cos it might screw up if any negative values are in there?value#=Abs((x#-x2#)*(x#-x2#))+Abs((y#-y2#)*(y#-y2#))+Abs((z#-z2#)*(z#-z2#)) Another possibility is that the float the result is stored in, is overflowing. Depends on your game scale. If you only need to know which light is nearest, regardless of how far away it is, use your second function. If you also need to know the distance, use the first. |
| ||
thanks, i didnt catch the abs() however with that correction neither distance call is correcting the glitch. The test map is only 1200 blitz units across. centered at 0,0,0. Perhaps i misunderstood how insert works. Does it move the list object , and are there errors in doing this in a loop of the same list. |
| ||
Can't help with that one, I'm afraid. Blitz3D is all a bit alien to me these days. |
| ||
thats ok, thanks for the help anyway. I got it sorted. Punting the lower distance to the front was just the wrong way to go about it, caused some that should be near the front not to make it simply because the distance was higher than the one that previously made it to front. However moving the larger distance lights to the back seems to work fine. here it is;multi dx light system for tiny tanks. build 1.0 Type dxlightpos Field x#,y#,z# Field r,g,b Field range Field dist# Field followent ;not used yet End Type ;using 7 lights, one is reserverd for sunlight Dim dxlight(7) Function initlights() ;called between maps, remove lightpositions Delete Each dxlightpos For i=1 To 7 If dxlight(i)=0 Then dxlight(i)=CreateLight(2) PositionEntity dxlight(i),9000,-9000,9000 LightRange dxlight(i),0 Next End Function Function removelights() ;called on game exit remove all Delete Each dxlightpos For i=1 To 7 If dxlight(i)<>0 Then FreeEntity dxlight(i) dxlight(i)=0 EndIf Next End Function ;have not speed tested this yet, but I see no reason to call it every frame, once every 300ms should be smooth enough Function UpdateLights(source,numberof=7) For dxl.dxlightpos=Each dxlightpos dxl\dist#=Abs(distancef(dxl\x,dxl\y,dxl\z,EntityX(source,1),EntityY(source,1),EntityZ(source,1))) Next bestdist#=0 Sorted=0 While sorted=0 amhigher=0 For dxl.dxlightpos =Each dxlightpos If dxl\dist>bestdist Then amhigher=1 Insert dxl.dxlightpos After Last dxlightpos bestdist=dxl\dist EndIf Next If amhigher=0 Then sorted=1 Wend i=0 For dxl.dxlightpos=Each dxlightpos i=i+1 LightColor dxlight(i),dxl\r,dxl\g,dxl\b LightRange dxlight(i),dxl\range PositionEntity dxlight(i),dxl\x,dxl\y,dxl\z If i=numberof Then Exit Next End Function if anyone uses this you will need the distance functions I posted above |
| ||
hmm, I did some test out of curiosity...Graphics 640,480,0,2 b = MilliSecs() For i = 0 To 1000000 distance(123,234,243,654,5645,534) Next Print MilliSecs()-b b = MilliSecs() For i = 0 To 1000000 distancef(123,234,243,654,5645,534) Next Print MilliSecs()-b b = MilliSecs() For i = 0 To 1000000 quickdistance(123,234,243,654,5645,534) Next Print MilliSecs()-b Function Distance#( x#, y#, z#, x2#, y2#, z2# ) value#=Sqr((x#-x2#)*(x#-x2#)+(y#-y2#)*(y#-y2#)+(z#-z2#)*(z#-z2#)) Return value# End Function Function DistanceF#( x#, y#, z#, x2#, y2#, z2# ) value#=(x#-x2#)*(x#-x2#)+(y#-y2#)*(y#-y2#)+(z#-z2#)*(z#-z2#) Return value# End Function Function quickdistance(x#,y#,z#,xx#,yy#,zz#) Local dx# = x-xx Local dy# = y-yy Local dz# = z-zz Return (dx*dx + dy*dy + dz*dz) End Function WaitKey() I consistently get 130,100,100 respectively in b3d which makes sense but here is the odd part... taking out the graphics command, using the same code in bmax, I get 40,28, and 83 I dont see why the latter function is less efficient in bmax, it should be more efficient taking away 3 subtractions for each loop ... odd isnt it? |
| ||
Insert is pig slow. Insert will basically redirect the pointers from and the pointers to that object, from the one before and after. You can Insert BEFORE and insert AFTER. I'll have a lookie when i get home though. I've recently done stuff like this in my waypoint editor, so it's still fairly fresh in my mind. |
| ||
Totally off topic, but is it just me or are the times messed up? ... Gfk: 1 hour ago RifRaf: 1 hour ago Gfk: 32 minutes ago RifRaf: 29 minutes ago Nate the Great: 43 minutes ago Ross C: 6 hours ago |
| ||
Yup.. might explain the whole "active topics" going completely blank frequently too |
| ||
Happens on the first day of every month... |
| ||
Ah, that explains it. I forgot about that little "feature" of these forums. ;) Looks like it's fixed now. |
| ||
Why doesn't it just filter for messages posted in the last 48 hours or something? |
| ||
This old code arc post from me may be of intrest in speeding this up. It has distance aproximation functions that are faster then the ones you have posted. |
| ||
Am I missing something here, or has everyone COMPLETELY forgotten the EntityDistance() function... ? O.o |
| ||
here you go, i asked for this a few years back also Function NearestBall(refferenceEntity) Local ball.tBall Local nearestBall.tBall Local nearestDist# ;Assume first tBall instance is the nearest nearestBall = First tBall nearestDistance = EntityDistance(bat,nearestBall\entity) For ball = Each tBall If ball <> nearestBall dist = EntityDistance(refferenceEntity,ball\entity) If dist < nearestDist nearestBall = ball nearestDist = dist End If End If Next Return nearestBall\entity End Function if u need help with it let me know |