You are here

GIS Developing Follow Me with PHP--Load GeoInfo from Mapinfo MIF format

GIS Mapping in PHP is a very nice tutorial to tell you how to create a webmap using PHP. In its Part II the author introduces a easy way to load the geographic coordinates from Mapinfo MIF format and realize it in raster image format with PHP's image function. The author has done a nice job and his code can parse one MIF example data with Line, Polyline and Region geometries objects. Thx! But not finished yet!!!!

Try to read the MIF format standard in, or you could find that MIF contains the other graphical objects, they are as listed:
rounded rectangle
Now we can continue the work what the code lacks. The code is basic of code from
GIS Mapping in PHP, and it is not complete here, if you can't catch up with me please refer to this article. And in order to let you understand the code easily, I use the normal XY coordinate name instead of  longitude/latitude coordinate.
1. Point
            POINT x y
            [ SYMBOL (shape, color, size)]
Notice: the purple text here is the standard MIF format for graphic objects
A point object takes two parameters; an X coordinate and a Y coordinate. As an option, specify the symbol that represents the point. Symbols could be omitted, but if you like to restore the style of geometries, you can try to load it.

Read the data line by line, when 'DATA' string was found, the coordinates data is ready for the parsing.

    while (!feof($handle))
         $line = strtoupper(fgets($handle, 1024));

        else if($in_data)

                $array = explode(" ",$line);
                $arrGeomInfo = array();
                $arrGeomInfo["xmin"] = $x   = trim($array[1]);
                $arrGeomInfo["ymin"]  = $y     = trim($array[2]);
                $arrGeomInfo["xmax"] = $x = trim($array[1]);
                $arrGeomInfo["ymax"]  = $y  = trim($array[2]);
                $arrGeomInfo["objectsType"] = "POINT";
                $arrGeomInfo["pointCount"]  = 1;
                $arrGeomInfo["pointString"] = "$x $y";

We set the maximum and minimum XY as the same value, because it is just one point. Because in GD you can not draw only one pixel point in the image, but you can replace it with one circle----ellipse with same width and height, now we use one circle with 1 pixel redius to display the point. You can use your own style such as ellipse, sqaure and even one symbol from image as you will.
    $converted_points = array();
    $points        = explode(" ",$poly["pointString"]);
    $number_points = count($points);
    $i = 0;
        $lon  = $points[$i];
        $lat  = $points[$i+1];
        $pt = getlocationcoords($lat, $lon, $sx, $sy);
        $converted_points[] = $pt["x"] - $min_x;
        $converted_points[] = $pt["y"] - $min_y;

    case 'POINT':
        imageellipse($im, $converted_points[0], $converted_points[1], 2, 2, $land);

2. ARC
            ARC x1 y1 x2 y2
            a b

An arc requires the diagonally opposite corners of its bounding rectangle and the beginning (a) and ending (b) angles of the arc in degrees, moving counter-clockwise with zero at three o'clock.
Do you understand? I dont like mathmatics but I can draw a ugly image to describe this:

(x1, y1) and
(x2, y2) are the left-bottom and upright corner of the  bounding rectangle. a and b angels are the arc from begin to end in degree with counter-clockwise direction.

            else if(substr($line,0,3)=="ARC")
                $array = explode(" ",$line);
                $arrGeomInfo = array();
                $arrGeomInfo["xmin"] = $x1   = trim($array[1]);
                $arrGeomInfo["ymin"]  = $y1     = trim($array[2]);
                $arrGeomInfo["xmax"] = $x2 = trim($array[3]);
                $arrGeomInfo["ymax"]  = $y2  = trim($array[4]);
                $arrGeomInfo["objectsType"] = "ARC";
                $line = fgets($handle, 1024);
                $array_ab = explode(" ",$line);
                $a = $array_ab[0];
                $b = $array_ab[1];
                $arrGeomInfo["pointCount"]  = xxx;
                $arrGeomInfo["pointString"] = "$x1 $y1 $x2 $y2 $a $b";
The minxminy maxx,maxy here are not right here, you need calculate it more. It will not be written here, just ask your middle school mathematics teacher :)
In GD function in PHP, the way to draw an ellipse uses the other parameters:
bool imagearc ( resource image, int cx, int cy, int w, int h, int s, int e, int color )
imagearc() draws a partial ellipse centered at cx, cy (top left is 0, 0) in the image represented by image. W and h specifies the ellipse's width and height(the blue lines in the image) respectively while the start and end points are specified in degrees indicated by the s and e arguments. 0° is located at the three-o'clock position, and the arc is drawn clockwise.
We need to tranfer the parameters, but easy:
cx = (x2+x1)/2
cx = (y2+y1)/2
w = x2-x1
h= y2-y1
s =a
e =b

    case 'ARC':
        imagearc($im, ($converted_points[0]+$converted_points[2])/2,($converted_points[1]+$converted_points[3])/2, ($converted_points[2]-$converted_points[0])/2, ($converted_points[3]-$converted_points[1])/2, $converted_points[4], $converted_points[5],$land);

            TEXT "textstring"
            x1 y1 x2 y2
           [ FONT...]
           [ Spacing {1.0 | 1.5 | 2.0}]

The x1, y1, x2, and y2 arguments specify the location of the text on the map. But use the space to display the text between 2 points in image is boring. Here I just use the first point as the text location. If you like, you can use the center point of the 2 points as the text location. Remember, set one attribute ["textString"] to the array to store the string content.

            else if(substr($line,0,4)=="TEXT"){
                $textString = trim(strtr(substr($line,5),'"',' '));//delete "
                $arrGeomInfo = GetPointString($handle,$count);
                $arrGeomInfo["objectsType"] = "TEXT";
                $arrGeomInfo["textString"] = $textString;
                //use only the first point
                $line  = fgets($handle, 1024);
                $array = explode(" ",$line);
                $x1 = $array[0];
                $y2  = $array[1];

                $arrGeomInfo = array();
                $arrGeomInfo["xmin"] = $x1   = trim($array[1]);
                $arrGeomInfo["ymin"]  = $y1     = trim($array[2]);
                $arrGeomInfo["xmax"] = $x1 = trim($array[1]);
                $arrGeomInfo["ymax"]  = $y1  = trim($array[2]);
                $arrGeomInfo["pointCount"]  = 1;
                $arrGeomInfo["pointString"] = "$x1 $y1";

Draw it in picture:
    case 'TEXT':
        imagestring($im, 5, $converted_points[0], $converted_points[1], $poly["textString"], $red);

            RECT x1 y1 x2 y2 
            ROUNDRECT x1 y1 x2 y2

Round rectange??? Forget it, there is no such geometries in the nature, replace it with rectange. x and y are the coordinates of the diagonally opposite corners.

            else if(substr($line,0,4)=="RECT" OR substr($line,0,9)=="ROUNDRECT")
                $array = explode(" ",$line);
                $arrGeomInfo = array();
                $arrGeomInfo["xmin"] = $x1   = trim($array[1]);
                $arrGeomInfo["ymin"]  = $y1     = trim($array[2]);
                $arrGeomInfo["xmax"] = $x2 = trim($array[3]);
                $arrGeomInfo["ymax"]  = $y2  = trim($array[4]);
                $arrGeomInfo["objectsType"] = "RECT";
                $arrGeomInfo["pointCount"]  = 2;
                $arrGeomInfo["pointString"] = "$x1 $y1 $x2 $y2";

Draw it:
    case 'RECT':
        imagerectangle($im, $converted_points[0], $converted_points[1], $converted_points[2], $converted_points[3],$land );
    case 'ROUNDRECT':
        imagerectangle($im, $converted_points[0], $converted_points[1], $converted_points[2], $converted_points[3],$land );

            ELLIPSE x1 y1 x2 y2
x y are the coordinates of the diagonally opposite corners of its bounding rectangle.
            else if(substr($line,0,7)=="ELLIPSE")
                $array = explode(" ",$line);
                $arrGeomInfo = array();
                $arrGeomInfo["xmin"] = $x1   = trim($array[1]);
                $arrGeomInfo["ymin"]  = $y1     = trim($array[2]);
                $arrGeomInfo["xmax"] = $x2 = trim($array[3]);
                $arrGeomInfo["ymax"]  = $y2 = trim($array[4]);
                $arrGeomInfo["objectsType"] = "Point";
                $arrGeomInfo["pointCount"]  = 1;
                $arrGeomInfo["pointString"] = "$x1 $y1 $x2 $y2";

Draw it:
    case 'ELLIPSE':
        imageellipse($im, ($converted_points[0]+$converted_points[2])/2, ($converted_points[1]+$converted_points[3])/2, ($converted_points[2]-$converted_points[0]), ($converted_points[3]-$converted_points[1]), $land);

The other objects LINE, PLINE and REGION have been clearly describe in that article. The MIF data could be download in from google, but select one data  which has no more than 2 Mb size, or you will meet exceptions such as: "
Maximum execution time of 30 seconds " or "cant load file size more than 2 mb".

You can download my source code here loadMif2Raster.rar  , including one MIF example data. Download and enjoy it.
Test result will be like this:

 Now you get to know how to load the geoinformation from MIF data, and you can extend the class also, for example, to input the data into database, output it in flash or SVG format. I will implement the class in PHPMyWMS later.


thankyou for usefull code, i make modification for my own purposes...
this tips simpler than use of other web-gis enggine such map-server, arcims, demis, etc.