Jump to content

Coordinate grid, pulling everything in distance with wrapping edges.


Recommended Posts

So say i have a 500 x 500 coordinate map with database entries for X and y

Note it goes from 0 to 499 each way.

 

I want users to be able to enter in a coordinate, and a distance, and be able to run a query to get everything in that square.

Honestly i have no idea how to get the edge wrapping down, and my brain is NOT working right now!

Say someone wants all coordinates within 30 squares of 490|200.

It would need to wrap over to x= 29

here is some sloppy code i threw together, Maybe you guys can try to understand what im trying to do from this.

 

$topx = $_GET['x'] - $_GET['distance'];
$topy = $_GET['y'] - $_GET['distance'];
$botx = $_GET['x'] + $_GET['distance'];
$boty = $_GET['y'] + $_GET['distance'];

if($topx < 0) {
    $topx = 499 + $_GET['x'] - $_GET['distance'];
    $conditionals = "x BETWEEN 0 AND " . $topx . " AND x BETWEEN 499 AND " . $botx;
} 
if($botx > 499) {
    $botx = $_GET['x'] + $_GET['distance'] - 499;
    $conditionals = "x BETWEEN 0 AND " . $botx . " AND x BETWEEN 499 AND " . $topx;
}
if($topy < 0) {
    $topy = 499 + $_GET['y'] - $_GET['distance'];
    if(isset($conditionals)) {
        $conditionals .= " AND ";
    }
    $conditionals .= "y BETWEEN 0 AND " . $topy . " AND y BETWEEN 499 AND " . $boty;
}
if($boty > 499) {
    $boty = $_GET['y'] + $_GET['distance'] - 499;
    if(isset($conditionals)) {
        $conditionals .= " AND ";
    }
    $conditionals .= "y BETWEEN 0 AND " . $boty . " AND y BETWEEN 499 AND " . $topy;
}

 

Note, the 'conditionals' var is me trying to build a PROBABLY INVALID mysql select query.

 

Any ideas? Thanks

I made this for you.  It's not an instant solution to your problem, but ought to help you with the logic.

<?php
$x = 20;
$y = 20;

$distance = 30;
$gridWidth = 500;
$gridHeight = 500;

// Calculations
$tlX = ($x - $distance);
$tlY = ($y - $distance);
$brX = ($x + $distance);
$brY = ($y + $distance);

header('Content-type: image/png');

$i = imagecreate($gridWidth,$gridHeight);
$black = imagecolorallocate($i, 0, 0, 0);
$green = imagecolorallocate($i, 0, 255, 0);
$red = imagecolorallocate($i, 255, 0, 0);

// Background color
imagefill($i, 0, 0, $black);

// Draw the initial block. It may be cut off, but we'll handle that next.
imagefilledrectangle($i, $tlX, $tlY, $brX, $brY, $green);

if ($tlX < 0 || $tlY < 0 || $brX > $gridWidth || $brY > $gridHeight) {
// If $tlX is negative, we wrap from the right.
if ($tlX < 0) {
	imagefilledrectangle($i, $gridWidth - abs($tlX), $tlY, $gridWidth, $brY, $red);
}

// If $tlY is negative, we wrap from the bottom.
if ($tlY < 0) {
	imagefilledrectangle($i, $tlX, $gridWidth - abs($tlY), $brX, $gridHeight, $red);
}

// If both $tlX and $tlY are negative, we wrap from the bottom and right.
if ($tlX < 0 && $tlY < 0) {
	imagefilledrectangle($i, $gridWidth - abs($tlX), $gridHeight - abs($tlY), $gridWidth, $gridHeight, $red);
}
}

imagepng($i);

 

 

Edit: I just realized I did not take into account a B.R. coordinate pair that exceeds the grid width/height.  I will have updated code posted shortly.

Updated code.

 

<?php
$x = 480;
$y = 480;

$distance = 30;
$gridWidth = 500;
$gridHeight = 500;

// Calculations
$tlX = ($x - $distance);
$tlY = ($y - $distance);
$brX = ($x + $distance);
$brY = ($y + $distance);

header('Content-type: image/png');

$i = imagecreate($gridWidth,$gridHeight);
$black = imagecolorallocate($i, 0, 0, 0);
$green = imagecolorallocate($i, 0, 255, 0);
$red = imagecolorallocate($i, 255, 0, 0);

// Background color
imagefill($i, 0, 0, $black);

// Draw the initial block. It may be cut off, but we'll handle that next.
imagefilledrectangle($i, $tlX, $tlY, $brX, $brY, $green);

if ($tlX < 0 || $tlY < 0 || $brX > $gridWidth || $brY > $gridHeight) {
// If $tlX is negative, we wrap from the right.
if ($tlX < 0) {
	imagefilledrectangle($i, $gridWidth - abs($tlX), $tlY, $gridWidth, $brY, $red);
}

// If $tlY is negative, we wrap from the bottom.
if ($tlY < 0) {
	imagefilledrectangle($i, $tlX, $gridWidth - abs($tlY), $brX, $gridHeight, $red);
}

// If both $tlX and $tlY are negative, we wrap from the bottom and right.
if ($tlX < 0 && $tlY < 0) {
	imagefilledrectangle($i, $gridWidth - abs($tlX), $gridHeight - abs($tlY), $gridWidth, $gridHeight, $red);
}

// If $brX is greater than the grid width, we wrap from the left.
if ($brX > $gridWidth) {
	imagefilledrectangle($i, 0, $tlY, $brX - $gridWidth, $brY, $red);
}

// If $brY is greater than the grid height, we wrap from the top.
if ($brY > $gridHeight) {
	imagefilledrectangle($i, $tlX, 0, $brX, $brY - $gridHeight, $red);
}

// If both $brX and $brY are greater than the grid width/height, we wrap from the top and left.
if ($brX > $gridWidth && $brY > $gridHeight) {
	imagefilledrectangle($i, 0, 0, $brX - $gridWidth, $brY - $gridHeight, $red);
}
}

imagepng($i);

Thanks for the quick reply :D

I was able to figure this, its untested at the moment but it seems completely correct

 

$topx = $_GET['x'] - $_GET['distance'];
$topy = $_GET['y'] - $_GET['distance'];
$botx = $_GET['x'] + $_GET['distance'];
$boty = $_GET['y'] + $_GET['distance'];

if($topx < 0) {
    $topx = 499 + $_GET['x'] - $_GET['distance'];
$topxflag = TRUE;
}
if($botx > 499) {
    $botx = $_GET['x'] + $_GET['distance'] - 499;
$botxflag = TRUE;
}
if($topy < 0) {
    $topy = 499 + $_GET['y'] - $_GET['distance'];
$topyflag = TRUE;
}
if($boty > 499) {
    $boty = $_GET['y'] + $_GET['distance'] - 499;
$botyflag = TRUE;
}

if ($topxflag == TRUE || $botxflag == TRUE) {
$xconditional = "`x` BETWEEN 0 AND " . $botx . " AND `x` BETWEEN 499 AND " . $topx;
}
if ($topxflag == FALSE && $botxflag == FALSE) {
$xconditional = "`x` BETWEEN " . $topx . " AND " . $botx;
}
if ($topyflag == TRUE || $botyflag == TRUE) {
$yconditional = "`y` BETWEEN 0 AND " . $boty . " AND `y` BETWEEN 499 AND " . $topy;
}
if ($topyflag == FALSE && $botyflag == FALSE) {
$yconditional = "`y` BETWEEN " . $topy . " AND " . $boty;
}

$query = "SELECT * FROM `map` WHERE " . $xconditional . " AND " . $yconditional;

$request = mysql_query($query);

Just if you want to make sure its foolproof, the different cases to test are

 

1. When $topx wraps to the left

2. When $topx wraps to the right

 

3. When $topy wraps to the bottom

4. When $topy wraps to the top

 

6. When $topx wraps to the left and $topy wraps to the bottom

7. When $topx wraps to the left and $topy wraps to the top

 

8. When $topx wraps to the right and $topy wraps to the bottom

9. When $topx wraps to the right and $topy wraps to the top

I was missing logic for two of the test cases in my code.

 

Updated version that passes all tests:

<?php
$x = 20;
$y = 470;
$debug = FALSE;

$distance = 30;
$gridWidth = 500;
$gridHeight = 500;

// Calculations
$tlX = ($x - $distance);
$tlY = ($y - $distance);
$brX = ($x + $distance);
$brY = ($y + $distance);

if ($debug) {
echo "TL: $tlX,$tlY<br />";
echo "BR: $brX,$brY<br />";
}

if (!$debug) {
header('Content-type: image/png');
}

$i = imagecreate($gridWidth,$gridHeight);
$black = imagecolorallocate($i, 0, 0, 0);
$green = imagecolorallocate($i, 0, 255, 0);
$red = imagecolorallocate($i, 255, 0, 0);

// Background color
imagefill($i, 0, 0, $black);

// Draw the initial block. It may be cut off, but we'll handle that next.
imagefilledrectangle($i, $tlX, $tlY, $brX, $brY, $green);

if ($tlX < 0 || $tlY < 0 || $brX > $gridWidth || $brY > $gridHeight) {
// If $tlX is negative, we wrap from the right.
if ($tlX < 0) {
	imagefilledrectangle($i, $gridWidth - abs($tlX), $tlY, $gridWidth, $brY, $red);
}

// If $tlY is negative, we wrap from the bottom.
if ($tlY < 0) {
	imagefilledrectangle($i, $tlX, $gridWidth - abs($tlY), $brX, $gridHeight, $red);
}

// If $tlX is negative and $brY is greater than the grid height, we wrap from the top and right.
if ($tlX < 0 && $brY > $gridHeight) {
	imagefilledrectangle($i, $gridWidth - abs($tlX), 0, $gridWidth, $brY - $gridHeight, $red);
}

// If both $tlX and $tlY are negative, we wrap from the bottom and right.
if ($tlX < 0 && $tlY < 0) {
	imagefilledrectangle($i, $gridWidth - abs($tlX), $gridHeight - abs($tlY), $gridWidth, $gridHeight, $red);
}

///////////////////////////////////////////////////////////////////////////

// If $brX is greater than the grid width, we wrap from the left.
if ($brX > $gridWidth) {
	imagefilledrectangle($i, 0, $tlY, $brX - $gridWidth, $brY, $red);
}

// If $brY is greater than the grid height, we wrap from the top.
if ($brY > $gridHeight) {
	imagefilledrectangle($i, $tlX, 0, $brX, $brY - $gridHeight, $red);
}

// If both $brX and $brY are greater than the grid width/height, we wrap from the top and left.
if ($brX > $gridWidth && $brY > $gridHeight) {
	imagefilledrectangle($i, 0, 0, $brX - $gridWidth, $brY - $gridHeight, $red);
}

// If $brX is greater than the grid width and $tlY is negative, we wrap from the bottom and left.
if ($brX > $gridWidth && $tlY < 0) {
	imagefilledrectangle($i, 0, $gridHeight - abs($tlY), $brX - $gridWidth, $gridHeight, $red);
}
}

if (!$debug) {
imagepng($i);
}

Just if you want to make sure its foolproof, the different cases to test are

 

1. When $topx wraps to the left

2. When $topx wraps to the right

 

3. When $topy wraps to the bottom

4. When $topy wraps to the top

 

6. When $topx wraps to the left and $topy wraps to the bottom

7. When $topx wraps to the left and $topy wraps to the top

 

8. When $topx wraps to the right and $topy wraps to the bottom

9. When $topx wraps to the right and $topy wraps to the top

 

I think i have that all covered in my php, its the same if topx wraps as if botx wraps, so they would use the same get query, then based on which ones get flagged (or wrap) it builds the query at the end.

Thanks for the help, i think ive got the logic, i jst now need to get the query right.

 

SELECT * 
FROM  `map` 
WHERE  `x` 
BETWEEN 0 
AND 11 
AND  `x` 
BETWEEN 499 
AND 490 
AND  `y` 
BETWEEN 0 
AND 11 
AND  `y` 
BETWEEN 499 
AND 490
LIMIT 0 , 30

this is an example of a query thats ran when it hits all 4 corners

 

Its not returning anything even though there are coordinates in the area.

Is it counteracting itself? Thanks

maybe

<?php
$x = $_GET['x'];
$y = $_GET['y'];
$d = $_GET['distance'];
$d1 = 499 - $d;
$condition = " WHERE (ABS(`x`-$x)<=$d OR ABS(`x`-$x)>=$d1) AND (ABS(`y`-$y)<=$d OR ABS(`y`-$y)>=$d1)"; 
?>

ups i have two extra (

The thing is i need to pull BOTH, not one or the other. Say it wraps around just the right side of the grid, id need  to pull from the left x coordinate to the right edge of the grid, AND id need to pull from 0 to the right x.

 

Maybe if i pull EVERYTHING from those coordinates, i can then restrict it using a php array where y is > this and < that.

Thing is i want it to use the least amount of system resources as possible too ^^

The thing is i need to pull BOTH, not one or the other. Say it wraps around just the right side of the grid, id need  to pull from the left x coordinate to the right edge of the grid, AND id need to pull from 0 to the right x.

Which is precisely why you would use OR instead of AND.

 

Think of it like this:

"SELECT someField FROM someTable WHERE id = 5 AND id = 10" --- would select 0 records (no single record has an id of 5 and 10)

"SELECT someField FROM someTable WHERE id = 5 OR id = 10" --- would select 2 records

 

so.. apply that logic to a query such as

"SELECT * FROM map WHERE (x BETWEEN 0 AND 10) OR (x BETWEEN 490 AND 499)" and you get records where x is between 0 and 10 or x is between 490 and 499 (in other words, you are pulling both, not just one or the other).

direct (no warping edge) distance from x1 to x2 is abs(x1 - x2) and it must be less then d

if edge distance is less then d that direct distance is greater than d complement (499 - d)

same for y

sorry i'm not good in english

 

The thing is i need to pull BOTH, not one or the other. Say it wraps around just the right side of the grid, id need  to pull from the left x coordinate to the right edge of the grid, AND id need to pull from 0 to the right x.

Which is precisely why you would use OR instead of AND.

 

Think of it like this:

"SELECT someField FROM someTable WHERE id = 5 AND id = 10" --- would select 0 records (no single record has an id of 5 and 10)

"SELECT someField FROM someTable WHERE id = 5 OR id = 10" --- would select 2 records

 

so.. apply that logic to a query such as

"SELECT * FROM map WHERE (x BETWEEN 0 AND 10) OR (x BETWEEN 490 AND 499)" and you get records where x is between 0 and 10 or x is between 490 and 499 (in other words, you are pulling both, not just one or the other).

 

Oh! Thats awesome! thanks for explaining it to me :) i was confused on what or did i guess, thought it would only return one of the two records.

ill test some things out and let you guys know how it goes

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.