ID:272000
 
Would anyone tell me how can I create a proc that is similar to block() but returns an ellipse instead of a square?
DivineO'peanut wrote:
Would anyone tell me how can I create a proc that is similar to <code>block()</code> but returns an ellipse instead of a square?

It's not very efficient, but this will work:
#define EPSILON 0.1

/proc/ellipse(var/atom/A, var/atom/B)

var/list/result = block(A,B)

var/hw = (B.x-A.x)/2
var/hh = (B.y-A.y)/2

var/cx = A.x+hw
var/cy = A.y+hh

for(var/turf/T in result)
if( ( ((T.x-cx)/hw ) ** 2 + ((T.y-cy)/hh) **2 ) > (1+EPSILON) )
result -=T

return result

Note: This only works in 2D, so if A & B are in different Z-levels, you'll get a sort of elliptical cylinder returned. It's fairly easy extend to return a (3D) ellipsoid, if you need that.

You may wish to play with the value of EPSILON, which is sort-of how much the ellipse "bleeds" along its edge. A value of 0 is strictly correct, but this doesn't always look good for small sizes. It's currently set to 0.1, which looks good in most cases. A value of >0.4 returns something that's more like a rounded rectangle.

As I said, this routine isn't particularly efficient, so don't use it somewhere critical. A faster routine would calculate the endpoints of a y-slice through each row of the ellipse, and add all the turfs between those endpoints.

Late edit: The routine above will fail if A or B are horizontal or vertical wrt each other. So you should add checks for that.
In response to Hobnob
I toyed with this for a while, and the ellipses are pretty smooth. A value of 0.2 or 0.3 seems to work better for the EPSILON. Thanks a dozen! :-)
In response to Hobnob
How to use that? xD
I might need it ^^
In response to DivineO'peanut
Heh, I've been playing around with this ellipse thing, since I've never used them before. Here's a screenshot of a cross thing:



It could probably be made some other way, but somehow I came across that with the ellipse generator..
mob/proc/CrossThingy(n=20)
var/dist
while(dist<n)
dist++
for(var/turf/t in ellipse(locate(x-dist,y-dist,z),locate(x+dist,y+dist,z)))
if(get_dist(src,t)==dist)
var/obj/o=new(t)
o.icon='white.dmi'
In response to Kaiochao
White zone can be useful for shooter games ^^
In response to Ripiz
Yeah, that's what I was thinking.
In response to Kaiochao
It is, however, a horribly inefficient method.
In response to Garthor
Good, write your own.
In response to Kaiochao
Maybe he will.
In response to Obs
Can't wait! :D
In response to Kaiochao
Copying a bit of code from my cone() proc:

proc/cone2(atom/origin, dir, dist=9, step=3)
while(origin && !isturf(origin)) origin = origin.loc
//no handling for diagonal directions, not sure how tihs would apply in those cases
if(!origin || !dir || (dir&(dir-1))) return

. = list()

var/left = turn(dir, 90)
var/right = turn(dir, -90)
var/turf/T
for(var/diag = 0, diag <= dist, diag+=step)
for(var/forward = 0, forward < step, forward++)
T = origin
. += T
for(var/v = 0, v < diag*2/step, v++)
T = get_step(T,right)
. += T
origin = get_step(origin, dir)
if(!origin)
//we've run off the "front" of the map
break
origin = get_step(origin, left)
//if we've run off the edge of the map
if(!origin)
world << "!origin"
//work from the other direction
origin = get_step(T, dir|right)
//swap the directions (now left is right)
var/swap = left
left = right
right = swap


I also realized that my original cone() proc had a rather nasty error: it would stop the cone if the left side (but not the right side) went off the map. Also, it would return a bunch of nulls if it ran off the map.