You are here

GIS Developing Follow Me with PHP--Visualize Geodata and create map in raster image

At least you should have some minimal experience with the real coordinate, screen coordinate, which could be called image coordinate. The real coordinate you maybe use everyday mostly is Cartesian coordinate system, the XY coordinate is describing in this image.

The Cartesian coordinate system allows negative coordinates. You use the Cartesian plane as a surface that represents the world in which your graphical objects exist. For example, a triangle can be defined by three points (2,5), (5,2), and (2,2), as shown in image:

Unfortunately, the computer doesnt care about real coordinate, they use screen coordinate, which reverses the Y coordinates of real coordinate as their own Y coordinate. As shown in this figure.


Because of the differences between a screen display and the Cartesian coordinate system, you need a way to translate points from one system to the other. You must map points in the Cartesian coordinate system to points in the screen coordinate system so that objects you draw onscreen are positioned correctly. Please map point (x1,y1) in the Cartesian coordinate system to point (x2,y2) in the screen coordinate system requires the following simple formulas, maxY means the height of the image you want to create.
x2 = x1;
y2 = maxY - y1;
I hope you havnt forgot what you have learned at the elementary school. And the triangle will be drawn as this:

Maybe you are wondering now, why the triangle has turned around here, but the image we see in the computer has the same shape direction. Don't worry, the screen coordinate is only understood by computer programming language during the visulization, the image will be displayed same as the real coordinate at last to the user before the monitor.

Ok, we can enter the subject now.
Supposed that you have a vector data now, for example, one array of  points in longitude&latitude coordinate, which are storeing the capitals' locations of countries worldwidly.

-87.3 36.28333
-90.05 30
-74 40.75
-76.2833 36.85
-81.4167 28.5
-75.1667 40
.......................
168.3 -17.75
-69.3 10.05


We could draw those point geometry in one image now. How to get the screen coordinate from the lat&lon coordinate? There are two ways to convert the coordinate.

First is stretching the gemetry to fit the output image size. For example, the square geometry will be stretched to rectange to fit the image(red rectange in the middle).


For beautification of the output map , the geometry should be displayed in the middle of the image. So the margin between the boundry and image must be considered.

//$width and $height is the width and height of the ouput image
//$minx, $miny is the leftbottom corner of geometry boundary in realworld coordinate
//$maxx, $maxy is the upright corner of geometry boundary in realworld coordinate
//$x, $y is some point coordinate on the geometry

function getPixelXYFromReal(
$x,$y,$minx,$miny,$maxx,$maxy,$width,$height){
    $w=$maxx-$minx;
    $h=$maxy-$miny;
    $s=$w/$h;
    $coord = array();

     $Scale_x = ($x-$minx)/$w;
     $Scale_y = ($y-$miny)/$h;

        if($s>=1){
            $Length_xpixel = $width*$Scale_x;
            $Length_ypixel = $width/$s*$Scale_y;
            //make the image display in the middle of picture
            $Pixel_x = $Length_xpixel;
            $Pixel_y = $height-$Length_ypixel-($height-$width/$s)/2;
            $scale = $w/$width;
        }
        if($s<1) {
            $Length_xpixel = $height*$s*$Scale_x;
            $Length_ypixel = $height*$Scale_y;
            //make the image display in the middle of picture
            $Pixel_x = $Length_xpixel+($width-$height*$s)/2;
            $Pixel_y = $height-$Length_ypixel;
            $scale = $h/$height;
        }
   
 //
$Pixel_x and $Pixel_y are the pixel coordinate in the screen
    $coord[0]=$Pixel_x;
    $coord[1]=$Pixel_y;
    $coord[2]=$scale;
    return $coord;
}

Now we have one world map image with size 620 * 310 pixels,
the  proportion is 620:310=2:1.



Fortunately the proportion of longitude and latitude is also 360:180=2:1. And minx =-180, miny=-90, maxx=180,maxy=90
So our function could be simplified as that:


function getPixelXYFromReal($x,$y,$width,$height){
    $coord = array();

    $Pixel_x =
(($x + 180) * ($width / 360));
    $Pixel_y =
((($y * -1) + 90) * ($height / 180));   
    $scale = 360/$width;

 //
$Pixel_x and $Pixel_y are the pixel coordinate in the screen
    $coord[0]=$Pixel_x;
    $coord[1]=$Pixel_y;
    $coord[2]=$scale;
    return $coord;
}


Now read the coordinate and drop points in the image:

$coord_array = file("capitals.txt");

$im = imagecreatefromjpeg("earth_620.jpg");

$red = imagecolorallocate ($im, 255,0,0);

//get the output image width and height
$image_x = imagesx($im);
$image_y = imagesy($im);

// Loop though each element of the array loaded from the
// text file

foreach($coord_array as $value)
{
// Explode out the latitude and longitude coordinates

    $coord = explode(" ",$value);

// And we have done all this before ......

    $pt = getPixelXYFromReal($coord[0], $coord[1], $image_x, $image_y);
    imageellipse($im, $pt[0], $pt[1], 4, 4, $red);
}

// Return the image as a JPEG - it would be @ 230k as PNG!

header("Content-Type: image/jpeg");
imagejpeg($im,"",80);
imagedestroy($im);


The result output image will be like this:



Second is stretching the output image size to fit the geometry boundary. The output image will change it's size to keep the shape of geometry. This method was used mostly in WebGIS field because the real geocoordinate will not be transformed.



/*
*@Description: get the new width&height
*@params:minx,miny,maxx,maxy: boundinbox of the map
*@params:width,height: width and height of map in pixel
*@params enablestretchmap: flag to enable stretch map.
* false: The map will display in the middle of the map according the scale
* true:  The map will stretch according the scale
*@return get thenew width&height array
*
*/
function getStretchWidthHeight($minx,$miny,$maxx,$maxy,$width,$height){
    $size = array();

        $w=$maxx-$minx;
        $h=$maxy-$miny;
        $s=$w/$h;
        $scale = $width/$height;
        //if w>h, the width will be kept, but height will be stretched
        if ($s>=1) {
            $size[0]=$width;
            $size[1]=$width/$s;
        }
        //if w<h, the height will be kept, but width will be stretched
        else if ($s<1) {
            $size[0]=$height*$s;
            $size[1]=$height;
        }
    return $size;
}


Now we want to show only the capitals in the area longitude between 0-75 and latitude between 0-70 and the output image would be 400*300.

$coord_array = file("capitals.txt");

//get the new output image size
$newsize = getStretchWidthHeight(0,0,75,70,400,300);
$newwidth =$newsize[0];
$newheight =$newsize[1];

$im = imagecreate($newwidth,$newheight);

$red = imagecolorallocate ($im, 255,0,0);
$sea       = imagecolorallocate ($im, 0xB5,0xC7,0xD6);

imagefilledrectangle($im,0,0,$newwidth,$newheight,$sea);

// Loop though each element of the array loaded from the
// text file

foreach($coord_array as $value)
{
// Explode out the latitude and longitude coordinates

    $coord = explode(" ",$value);

// And we have done all this before ......
    $pt = getPixelXYFromReal($coord[0], $coord[1], 0,0,75,70, $newwidth, $newheight);
    imageellipse($im, $pt[0], $pt[1], 4, 4, $red);
}

// Return the image as a JPEG - it would be @ 230k as PNG!

header("Content-Type: image/jpeg");
imagejpeg($im,"",80);
imagedestroy($im);


The output image's size has changed, it is not 400*300 but 400*373 to fit the proportion of the boundary of geometry.


The source code, image and capital data could be downloaded from here. visulizeGeodata.rar

Ref:
Programming 2D Computer Graphics
http://www.informit.com/articles/article.asp?p=98117&rl=1
Blog: 

Comments

Great Example, Thanks so much for the tutorial. How could I implement this code to produce a set of polygons or points that fall between Long -81 and -82 and Lat 28 to 29. I need the map to zoom to this area so I can see the points. Thanks in advance

The example given here is PHP function, you can use it in your PHP project directly and easily.

Very nice. And how to display text on mouse hover?

This is what javascript can do, you can use div+js+css to do that

so hey there, i totally realized that some new information won't be enough to improve such topics, soyou need the hell more of it as well

This article is nice and we have implemented the same login in C#.net.
i need to use the same map in 1024 X 720 resolution. how can i implement it.

Can I copy your code to write an article to my blog? I think it's very infomative for my users!

To think, I was cnfoseud a minute ago.