- PVSM.RU - https://www.pvsm.ru -

В прошлый раз [1] мы конструировали пространственный индекс, а сейчас просто воспользуемся этим навыком, чтобы сделать живой (не статический) картографический сервис с web интерфейсом и производительностью, скажем, миллион запросов в день на совершенно обычном «железе».
<html><body>
<?vsp
declare cnt integer;
cnt := sequence_next ('xxx.YYY.__cnt');
?>
<table width="100%" border="1">
<tr><td align="center"><?vsp= cnt ?></td></tr>
</table>
</body></html>
Встроенная функция sequence_next атомарно наращивает счетчик и возвращает его значение.
VHOST_DEFINE(lpath=>'/test/',ppath=>'/test/',vsp_user=>'DBA');
http://localhost:8890/test/test.vsp
for select blob_to_string(Shape) as data from
xxx.YYY."water-polygon" as x,
xxx.YYY."v_water-polygon_spx_enum_items_in_box" as a
where a.minx = cminx and a.miny = cminy and a.maxx = cmaxx and a.maxy = cmaxy
and x."_OBJECTID_" = a.oid
and x.maxx_ >= cminx and x.minx_ <= cmaxx
and x.maxy_ >= cminy and x.miny_ <= cmaxy
do
{ ... }
Разберемся с этим запросом поподробнее.
xxx.YYY."water-polygon" — таблица водоемов, которую мы только что создали и залили данными.xxx.YYY."v_water-polygon_spx_enum_items_in_box" — процедурное view поверх вспомогательной таблицы, выполняющей роль блочного пространственного индекса. Фактически, это грубый пространственный фильтр, работающий с точностью до размера блока пространственного индекса.a.minx = cminx and... — мы задаем параметры вызова view, cminx ... — границы фрагмента карты, который мы хотим нарисовать x."_OBJECTID_" = a.oid — join между таблицей данных и синтетическим резалтсетом, полученным из процедурного view x.maxx_ >= cminx and x.minx_ <= cmaxx ... промежуточный пространственный фильтр, позволяющий не лезть за блобами с геометриями, если они заведомо не пригодятся#ifdef _USRDLL
#include "plugin.h"
#include "import_gate_virtuoso.h"
#define wi_inst (wi_instance_get()[0])
#else
#include <libutil.h>
#include "sqlnode.h"
#include "sqlbif.h"
#include "wi.h"
#include "Dk.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "gd_utils.h"
#include "gd/gd_lib.h"
#include "shplib/shapefil.h"
typedef struct img_ctx_s {
int dx_;
int dy_;
double minx_;
double miny_;
double maxx_;
double maxy_;
double mulx_;
double muly_;
int black_;
int red_;
int green_;
int blue_;
int attr_;
gdImagePtr img_;
} img_ctx_t;
caddr_t
img_create_proc (caddr_t * qst, caddr_t * err, state_slot_t ** args)
{
img_ctx_t *ptr = (img_ctx_t *)dk_alloc_box (sizeof (img_ctx_t), DV_STRING);
ptr->dx_ = bif_long_arg (qst, args, 0, "img_create_proc");
ptr->dy_ = bif_long_arg (qst, args, 1, "img_create_proc");
ptr->minx_ = bif_double_arg (qst, args, 2, "img_create_proc");
ptr->miny_ = bif_double_arg (qst, args, 3, "img_create_proc");
ptr->maxx_ = bif_double_arg (qst, args, 4, "img_create_proc");
ptr->maxy_ = bif_double_arg (qst, args, 5, "img_create_proc");
ptr->attr_ = bif_long_arg (qst, args, 6, "img_create_proc");
ptr->img_ = gdImageCreateTrueColor (ptr->dx_, ptr->dy_);
ptr->mulx_ = ptr->dx_/fabs(ptr->maxx_ - ptr->minx_);
ptr->muly_ = ptr->dy_/fabs(ptr->maxy_ - ptr->miny_);
ptr->black_ = gdImageColorAllocate (ptr->img_, 0, 0, 0);
ptr->blue_ = gdImageColorAllocate (ptr->img_, 0, 0, 255);
ptr->red_ = gdImageColorAllocate (ptr->img_, 255, 0, 0);
ptr->green_ = gdImageColorAllocate (ptr->img_, 0, 255, 0);
return (caddr_t)ptr;
}
caddr_t
img_saveas_proc (caddr_t * qst, caddr_t * err, state_slot_t ** args)
{
img_ctx_t *ptr = (img_ctx_t *)bif_arg (qst, args, 0, "img_saveas_proc");
gdImagePtr im = ptr->img_;
caddr_t fname = bif_string_arg (qst, args, 1, "img_saveas_proc");
FILE *out = fopen (fname, "wb");
if (NULL != out)
{
gdImageGif (im, out);
fclose (out);
return (caddr_t)0;
}
return (caddr_t)-1;
}
static unsigned char clip(int value)
{
if (value < 0)
value = 0;
else if (value > 255)
value = 255;
return value;
}
caddr_t
img_fromptr_proc (caddr_t * qst, caddr_t * err, state_slot_t ** args)
{
ptrlong addr = unbox(bif_long_arg (qst, args, 0, "img_fromptr_proc"));
return addr;
}
caddr_t
img_tostr_proc (caddr_t * qst, caddr_t * err, state_slot_t ** args)
{
img_ctx_t *ptr = (img_ctx_t *)bif_arg (qst, args, 0, "img_tostr_proc");
gdImagePtr im = ptr->img_;
void *rv = NULL;
caddr_t ret = NULL;
int size = 0;
gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
gdImageGifCtx (im, out);
rv = gdDPExtractData (out, &size);
if (NULL == rv || size <= 0)
return 0;
out->gd_free (out);
ret = dk_alloc_box (size, DV_STRING);
memcpy (ret, rv, size);
gdFree(rv);
return (caddr_t)box_num (ret);
}
caddr_t
img_destroy_proc (caddr_t * qst, caddr_t * err, state_slot_t ** args)
{
img_ctx_t *ptr = (img_ctx_t *)bif_arg (qst, args, 0, "img_destroy_proc");
gdImagePtr im = ptr->img_;
gdImageDestroy(im);
/*dk_free_box (ptr);*/
return 0;
}
caddr_t
img_draw_polyline_proc (caddr_t * qst, caddr_t * err, state_slot_t ** args)
{
img_ctx_t *ptr = (img_ctx_t *)bif_arg (qst, args, 0, "img_draw_polyline_proc");
gdImagePtr im = ptr->img_;
caddr_t data = bif_string_arg (qst, args, 1, "img_draw_polyline_proc");
SHPObject *shp = SHPDeserialize (data);
int nparts = shp->nParts;
int npoints = shp->nVertices;
double *px = shp->padfX;
double *py = shp->padfY;
int i, j;
int color = bif_long_arg (qst, args, 2, "img_draw_polyline_proc");
gdImageSetAntiAliased (im, color);
for (i = 0; i < nparts; i++)
{
long ps = shp->panPartStart[i];
long psz = (i==(nparts-1))? npoints-ps : shp->panPartStart[i+1]-ps;
gdPointPtr points = (gdPointPtr)malloc(sizeof (gdPoint) * psz);
for (j = 0; j < psz; j++)
{
points[j].x = (px[ps+j] - ptr->minx_) * ptr->mulx_;
points[j].y = (ptr->attr_ & 1) ?
ptr->dy_ - (py[ps+j] - ptr->miny_) * ptr->muly_:
(py[ps+j] - ptr->miny_) * ptr->muly_;
}
for (j = 1; j < psz; j++)
{
/*if (points[j].x == points[j-1].x && points[j].y == points[j-1].y)
gdImageSetPixel (im, points[j].x, points[j].y, ptr->blue_);
else*/
gdImageLine (im, points[j].x, points[j].y, points[j-1].x, points[j-1].y, gdAntiAliased);
}
free (points);
}
SHPDestroyObject (shp);
return 0;
}
caddr_t
img_draw_polygone_proc (caddr_t * qst, caddr_t * err, state_slot_t ** args)
{
img_ctx_t *ptr = (img_ctx_t *)bif_arg (qst, args, 0, "img_draw_polygone_proc");
gdImagePtr im = ptr->img_;
caddr_t data = bif_string_arg (qst, args, 1, "img_draw_polygone_proc");
SHPObject *shp = SHPDeserialize (data);
int nparts = shp->nParts;
int npoints = shp->nVertices;
double *px = shp->padfX;
double *py = shp->padfY;
int i,j;
int color = bif_long_arg (qst, args, 2, "img_draw_polygone_proc");
int bcolor = bif_long_arg (qst, args, 3, "img_draw_polygone_proc");
for (i = 0; i < nparts; i++)
{
long ps = shp->panPartStart[i];
long psz = (i==(nparts-1))? npoints-ps : shp->panPartStart[i+1]-ps;
gdPointPtr points = (gdPointPtr)malloc (sizeof (gdPoint) * psz);
for (j = 0; j < psz; j++)
{
points[j].x = (px[ps+j] - ptr->minx_) * ptr->mulx_;
points[j].y = (ptr->attr_ & 1) ?
ptr->dy_ - (py[ps+j] - ptr->miny_) * ptr->muly_:
(py[ps+j] - ptr->miny_) * ptr->muly_;
}
gdImageSetAntiAliased (im, color);
gdImageFilledPolygon (im, points, psz, gdAntiAliased);
if (bcolor >= 0)
{
gdImageSetAntiAliased (im, bcolor);
gdImagePolygon (im, points, psz, gdAntiAliased);
}
free (points);
}
SHPDestroyObject(shp);
return 0;
}
caddr_t
img_alloc_color_proc (caddr_t * qst, caddr_t * err, state_slot_t ** args)
{
img_ctx_t *ptr = (img_ctx_t *)bif_arg (qst, args, 0, "img_alloc_color_proc");
gdImagePtr im = ptr->img_;
int r = bif_long_arg (qst, args, 1, "img_alloc_color_proc");
int g = bif_long_arg (qst, args, 2, "img_alloc_color_proc");
int b = bif_long_arg (qst, args, 3, "img_alloc_color_proc");
return box_num(gdImageColorAllocateAlpha (ptr->img_, r, g, b, 0));
}
void
init_shcall_gd_utils ()
{
bif_define ("img_create", img_create_proc);
bif_define ("img_saveas", img_saveas_proc);
bif_define ("img_tostr", img_tostr_proc);
bif_define ("img_fromptr", img_fromptr_proc);
bif_define ("img_destroy", img_destroy_proc);
bif_define ("img_alloc_color", img_alloc_color_proc);
bif_define ("img_draw_polyline", img_draw_polyline_proc);
bif_define ("img_draw_polygone", img_draw_polygone_proc);
}
declare img any;
img := img_create (512, 512, cminx, cminy, cmaxx, cmaxy, 1);
declare cl integer;
declare bg integer;
cl := img_alloc_color (img, 0, 0, 255);
bg := img_alloc_color (img, 0, 0, 200);
whenever not found goto nf;
for select blob_to_string(Shape) as data from
xxx.YYY."water-polygon" as x,
xxx.YYY."v_water-polygon_spx_enum_items_in_box" as a
where
a.minx = cminx and a.miny = cminy
and a.maxx = cmaxx and a.maxy = cmaxy
and x."_OBJECTID_" = a.oid
and x.maxx_ >= cminx and x.minx_ <= cmaxx
and x.maxy_ >= cminy and x.miny_ <= cmaxy
do
{
img_draw_polygone (img, data, cl, bg);
}
nf:;
declare ptr integer;
ptr := img_tostr (img); -- сделали gif
img_destroy (img); -- освободили контекст
declare image any;
image := img_fromptr(ptr); -- магия деструктора
http_header ('Content-type: image/giftn'); -- формирование заголовка
http(image); -- выдача результата в ответный поток
<?vsp
if ({?'getfile'} <> '')
{
http_header ('Content-type: image/giftn'); -- set the header to jpg
declare s_params any;
s_params := deserialize (decode_base64 (get_keyword ('params', params, '')));
-- dbg_obj_print(s_params);
declare "min_x" double precision;
declare "min_y" double precision;
declare "max_x" double precision;
declare "max_y" double precision;
declare "cminx" double precision;
declare "cminy" double precision;
declare "cmaxx" double precision;
declare "cmaxy" double precision;
declare "s" varchar;
s := get_keyword ('minx', s_params, '');
if (s = '')
cminx := min_x;
else
cminx := atof(s);
s := get_keyword ('miny', s_params, '');
if (s = '')
cminy := min_y;
else
cminy := atof(s);
s := get_keyword ('maxx', s_params, '');
if (s = '')
cmaxx := max_x;
else
cmaxx := atof(s);
s := get_keyword ('maxy', s_params, '');
if (s = '')
cmaxy := max_y;
else
cmaxy := atof(s);
declare img any;
img := img_create (512, 512, cminx, cminy, cmaxx, cmaxy, 1);
declare cl integer;
declare bg integer;
{
cl := img_alloc_color (img, 0, 0, 255);
bg := img_alloc_color (img, 0, 0, 200);
whenever not found goto nf;
for select blob_to_string(Shape) as data from
xxx.YYY."water-polygon" as x, xxx.YYY."v_water-polygon_spx_enum_items_in_box" as a
where a.minx = cminx and a.miny = cminy and a.maxx = cmaxx and a.maxy = cmaxy
and x."_OBJECTID_" = a.oid
and x.maxx_ >= cminx and x.minx_ <= cmaxx
and x.maxy_ >= cminy and x.miny_ <= cmaxy
do
{
img_draw_polygone (img, data, cl, bg);
}
nf:;
cl := img_alloc_color (img, 0, 255, 0);
bg := img_alloc_color (img, 0, 255, 0);
whenever not found goto nf2;
for select blob_to_string(Shape) as data from
xxx.YYY."vegetation-polygon" as x, xxx.YYY."v_vegetation-polygon_spx_enum_items_in_box" as a
where a.minx = cminx and a.miny = cminy and a.maxx = cmaxx and a.maxy = cmaxy
and x."_OBJECTID_" = a.oid
and x.maxx_ >= cminx and x.minx_ <= cmaxx
and x.maxy_ >= cminy and x.miny_ <= cmaxy
do
{
img_draw_polygone (img, data, cl, bg);
}
nf2:;
cl := img_alloc_color (img, 255, 0, 0);
bg := img_alloc_color (img, 255, 0, 0);
whenever not found goto nf3;
for select blob_to_string(Shape) as data from
xxx.YYY."building-polygon" as x, xxx.YYY."v_building-polygon_spx_enum_items_in_box" as a
where a.minx = cminx and a.miny = cminy and a.maxx = cmaxx and a.maxy = cmaxy
and x."_OBJECTID_" = a.oid
and x.maxx_ >= cminx and x.minx_ <= cmaxx
and x.maxy_ >= cminy and x.miny_ <= cmaxy
do
{
img_draw_polygone (img, data, cl, bg);
}
nf3:;
}
declare ptr integer;
ptr := img_tostr (img);
img_destroy (img);
declare image any;
image := img_fromptr(ptr);
http(image); -- table and display
--dbg_obj_print('boom',{?'id'});
return;
}
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<?vsp
declare "min_x" double precision;
declare "min_y" double precision;
declare "max_x" double precision;
declare "max_y" double precision;
min_x := 82.;
max_x := 84.;
min_y := 54.;
max_y := 56.;
params := vector_concat (params,
vector ('minx', sprintf('%g', min_x),
'maxx', sprintf('%g', max_x),
'miny', sprintf('%g', min_y),
'maxy', sprintf('%g', max_y)));
?>
<html>
<body zonload="window.location.reload();">
<script language="JavaScript" type="text/javascript">
function full_extent()
{
document.forms['form1'].minx.value=<?vsp=min_x ?>;
document.forms['form1'].miny.value=<?vsp=min_y ?>;
document.forms['form1'].maxx.value=<?vsp=max_x ?>;
document.forms['form1'].maxy.value=<?vsp=max_y ?>;
}
</script>
<script language="JavaScript" type="text/javascript">
function zoom_in()
{
var dx = Math.abs(document.forms['form1'].maxx.value - document.forms['form1'].minx.value);
dx = dx/8;
var tmp = document.forms['form1'].maxx.value;
tmp -= dx;
document.forms['form1'].maxx.value = tmp;
tmp = document.forms['form1'].minx.value;
tmp -= -dx;
document.forms['form1'].minx.value = tmp;
var dy = Math.abs(document.forms['form1'].maxy.value - document.forms['form1'].miny.value);
dy = dy/8;
tmp = document.forms['form1'].maxy.value;
tmp -= dy;
document.forms['form1'].maxy.value = tmp;
tmp = document.forms['form1'].miny.value;
tmp -= -dy;
document.forms['form1'].miny.value = tmp;
}
</script>
<script language="JavaScript" type="text/javascript">
function zoom_out()
{
var dx = -Math.abs(document.forms['form1'].maxx.value - document.forms['form1'].minx.value);
dx = dx/8;
var tmp = document.forms['form1'].maxx.value;
tmp -= dx;
document.forms['form1'].maxx.value = tmp;
tmp = document.forms['form1'].minx.value;
tmp -= -dx;
document.forms['form1'].minx.value = tmp;
var dy = -Math.abs(document.forms['form1'].maxy.value - document.forms['form1'].miny.value);
dy = dy/8;
tmp = document.forms['form1'].maxy.value;
tmp -= dy;
document.forms['form1'].maxy.value = tmp;
tmp = document.forms['form1'].miny.value;
tmp -= -dy;
document.forms['form1'].miny.value = tmp;
}
</script>
<script language="JavaScript" type="text/javascript">
function pan_left()
{
var dx = Math.abs(document.forms['form1'].maxx.value - document.forms['form1'].minx.value);
dx = dx/8;
document.forms['form1'].maxx.value -= dx;
document.forms['form1'].minx.value -= dx;
}
function pan_right()
{
var dx = -Math.abs(document.forms['form1'].maxx.value - document.forms['form1'].minx.value);
dx = dx/8;
document.forms['form1'].maxx.value -= dx;
document.forms['form1'].minx.value -= dx;
}
function pan_up()
{
var dy = -Math.abs(document.forms['form1'].maxy.value - document.forms['form1'].miny.value);
dy = dy/8;
document.forms['form1'].maxy.value -= dy;
document.forms['form1'].miny.value -= dy;
}
function pan_down()
{
var dy = Math.abs(document.forms['form1'].maxy.value - document.forms['form1'].miny.value);
dy = dy/8;
document.forms['form1'].maxy.value -= dy;
document.forms['form1'].miny.value -= dy;
}
</script>
<form method="GET" id="form1" name="form1">
<?vsp
declare "cminx" double precision;
declare "cminy" double precision;
declare "cmaxx" double precision;
declare "cmaxy" double precision;
declare "s" varchar;
s := get_keyword ('minx', params, '');
if (s = '')
cminx := min_x;
else
cminx := atof(s);
s := get_keyword ('miny', params, '');
if (s = '')
cminy := min_y;
else
cminy := atof(s);
s := get_keyword ('maxx', params, '');
if (s = '')
cmaxx := max_x;
else
cmaxx := atof(s);
s := get_keyword ('maxy', params, '');
if (s = '')
cmaxy := max_y;
else
cmaxy := atof(s);
declare mashtab double precision;
mashtab := floor((cmaxx-cminx)*96./(512.*2.54));
declare cnt integer;
cnt := sequence_next ('xxx.YYY.__cnt');
?>
<input type="hidden" name="minx" value='<?vsp=cminx ?>'/>
<input type="hidden" name="miny" value='<?vsp=cminy ?>'/>
<input type="hidden" name="maxx" value='<?vsp=cmaxx ?>'/>
<input type="hidden" name="maxy" value='<?vsp=cmaxy ?>'/>
<table width="100%" border="1" cellpadding="0" cellspacing="0" summary="">
<tr>
<td width="20%" align="center" > </td>
<td width="20%" align="center" >Min X</td>
<td width="20%" align="center" >Min Y</td>
<td width="20%" align="center" >Max X</td>
<td width="20%" align="center" >Max Y</td>
</tr>
<tr>
<td width="20%" align="center" >Default extent</td>
<td width="20%" align="center" > <?vsp=min_x ?> </td>
<td width="20%" align="center" > <?vsp=min_y ?> </td>
<td width="20%" align="center" > <?vsp=max_x ?> </td>
<td width="20%" align="center" > <?vsp=max_y ?> </td>
</tr>
<tr>
<td width="20%" align="center" >Current extent</td>
<td width="20%" align="center" > <?vsp=sprintf('%10.3f', cminx) ?> </td>
<td width="20%" align="center" > <?vsp=sprintf('%10.3f', cminy) ?> </td>
<td width="20%" align="center" > <?vsp=sprintf('%10.3f', cmaxx) ?> </td>
<td width="20%" align="center" > <?vsp=sprintf('%10.3f', cmaxy) ?> </td>
</tr>
<tr>
<td width="20%" align="center" > </td>
<td width="20%" align="center" >
<input type="button" onclick="javascript: full_extent(); document.forms['form1'].submit ();" value="[*]"/>
</td>
<td width="20%" align="center" >
<input type="button" onclick="javascript: zoom_in(); document.forms['form1'].submit ();" value="+" />
<br><input type="button" onclick="javascript: zoom_out(); document.forms['form1'].submit ();" value="-" />
</td>
<td width="20%" align="center" >
<input type="button" onclick="javascript: pan_up(); document.forms['form1'].submit ();" value="^" />
<br>
<input type="button" onclick="javascript: pan_down(); document.forms['form1'].submit ();" value="V" />
</td>
<td width="20%" align="center" >
<input type="button" onclick="javascript: pan_left(); document.forms['form1'].submit ();" value="<" />
<input type="button" onclick="javascript: pan_right(); document.forms['form1'].submit ();" value=">" />
</td>
</tr>
<tr><td colspan=5 align="center">
<p><img src=""></p>
</td></tr>
</table>
</form></body></html>

Кто первым правильно назовёт перевал под номером 40 на фрагменте карты в шапке статьи, получит благодарность автора.
Автор: zzeng
Источник [11]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/news/47624
Ссылки в тексте:
[1] раз: http://habrahabr.ru/post/196682/
[2] OSM: http://www.openstreetmap.org/
[3] shpfile: http://ru.wikipedia.org/wiki/Shapefile
[4] датасет: http://gis-lab.info/qa/osmshp.html
[5] Virtuoso V7.0.0: http://virtuoso.openlinksw.com/dataspace/doc/dav/wiki/Main/VOSDownload
[6] Shapefile C Library: http://shapelib.maptools.org/
[7] wget: http://ru.wikipedia.org/wiki/Wget
[8] С — plugin: http://docs.openlinksw.com/virtuoso/cinterface.html
[9] GD: http://en.wikipedia.org/wiki/GD_Graphics_Library
[10] точечные индексы: http://habrahabr.ru/post/186564/
[11] Источник: http://habrahabr.ru/post/200642/
Нажмите здесь для печати.