Graphviz  2.29.20120524.0446
plugin/core/gvrender_core_pov.c
Go to the documentation of this file.
00001 /* $Id:  */
00002 /* vim:set shiftwidth=8 ts=8: */
00003 
00004 /**********************************************************
00005 *            Copyright (c) 2011 Andy Jeutter              *
00006 *            AKA HallerHarry at gmx.de                    *
00007 *            All rights reserved.                         *
00008 **********************************************************/
00009 
00010 /*************************************************************************
00011  * This program and the accompanying materials
00012  * are made available under the terms of the Eclipse Public License v1.0
00013  * which accompanies this distribution, and is available at
00014  * http://www.eclipse.org/legal/epl-v10.html
00015  *
00016  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00017  *************************************************************************/
00018 
00019 #ifdef HAVE_CONFIG_H
00020 #define _GNU_SOURCE
00021 #include "config.h"
00022 #endif
00023 
00024 #include <stdarg.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <ctype.h>
00028 #include <errno.h>
00029 
00030 #include "macros.h"
00031 #include "const.h"
00032 
00033 #include "gvplugin_render.h"
00034 #include "gvplugin_device.h"
00035 #include "gvio.h"
00036 #include "gvcint.h"
00037 
00038 #define POV_VERSION \
00039     "#version 3.6;\n"
00040 
00041 #define POV_GLOBALS \
00042     "global_settings { assumed_gamma 1.0 }\n"
00043 
00044 #define POV_DEFAULT \
00045     "#default { finish { ambient 0.1 diffuse 0.9 } }\n"
00046 
00047 #define POV_INCLUDE \
00048     "#include \"colors.inc\"\n"\
00049     "#include \"textures.inc\"\n"\
00050     "#include \"shapes.inc\"\n"
00051 
00052 #define POV_LIGHT \
00053     "light_source { <1500,3000,-2500> color White }\n"
00054 
00055 #define POV_CAMERA \
00056     "camera { location <%.3f , %.3f , %.3f>\n"\
00057     "         look_at  <%.3f , %.3f , %.3f>\n"\
00058     "         right x * image_width / image_height\n"\
00059     "         angle %.3f\n"\
00060     "}\n"
00061 
00062 #define POV_SKY_AND_GND \
00063     "//sky\n"\
00064     "plane { <0, 1, 0>, 1 hollow\n"\
00065     "    texture {\n"\
00066     "        pigment { bozo turbulence 0.95\n"\
00067     "            color_map {\n"\
00068     "                [0.00 rgb <0.05, 0.20, 0.50>]\n"\
00069     "                [0.50 rgb <0.05, 0.20, 0.50>]\n"\
00070     "                [0.75 rgb <1.00, 1.00, 1.00>]\n"\
00071     "                [0.75 rgb <0.25, 0.25, 0.25>]\n"\
00072     "                [1.00 rgb <0.50, 0.50, 0.50>]\n"\
00073     "            }\n"\
00074     "            scale <1.00, 1.00, 1.50> * 2.50\n"\
00075     "            translate <0.00, 0.00, 0.00>\n"\
00076     "        }\n"\
00077     "        finish { ambient 1 diffuse 0 }\n"\
00078     "    }\n"\
00079     "    scale 10000\n"\
00080     "}\n"\
00081     "//mist\n"\
00082     "fog { fog_type 2\n"\
00083     "    distance 50\n"\
00084     "    color rgb <1.00, 1.00, 1.00> * 0.75\n"\
00085     "    fog_offset 0.10\n"\
00086     "    fog_alt 1.50\n"\
00087     "    turbulence 1.75\n"\
00088     "}\n"\
00089     "//gnd\n"\
00090     "plane { <0.00, 1.00, 0.00>, 0\n"\
00091     "    texture {\n"\
00092     "        pigment{ color rgb <0.25, 0.45, 0.00> }\n"\
00093     "        normal { bumps 0.75 scale 0.01 }\n"\
00094     "        finish { phong 0.10 }\n"\
00095     "    }\n"\
00096     "}\n"
00097 
00098 #define POV_BOX \
00099     "box { <%.3f, %.3f, %.3f>, <%.3f, %.3f, %.3f>\n"
00100 
00101 #define POV_SCALE1 \
00102     "scale %.3f\n"
00103 
00104 #define POV_SCALE3 \
00105     "scale    "POV_VECTOR3"\n"
00106 
00107 #define POV_ROTATE \
00108     "rotate   "POV_VECTOR3"\n"
00109 
00110 #define POV_TRANSLATE \
00111     "translate"POV_VECTOR3"\n"
00112 
00113 #define END \
00114     "}\n"
00115 
00116 #define POV_TORUS \
00117     "torus { %.3f, %.3f\n"
00118 
00119 #define POV_SPHERE_SWEEP \
00120     "sphere_sweep {\n"\
00121     "    %s\n"\
00122     "    %d,\n"
00123 
00124 #define POV_SPHERE \
00125     "sphere {"POV_VECTOR3", 1.0\n"      // center, radius
00126 
00127 #define POV_TEXT \
00128     "text {\n"\
00129     "    ttf \"%s\",\n"\
00130     "    \"%s\", %.3f, %.3f\n"
00131 
00132 #define POV_DECLARE \
00133     "#declare %s = %s;\n"
00134 
00135 #define POV_OBJECT \
00136     "object { %s }\n"
00137 
00138 #define POV_VERBATIM \
00139     "%s\n"
00140 
00141 #define POV_DEBUG \
00142     "#debug %s\n"
00143 
00144 #define POV_POLYGON \
00145     "polygon { %d,\n"
00146 
00147 #define POV_VECTOR3 \
00148     "<%9.3f, %9.3f, %9.3f>"
00149 
00150 #define POV_PIGMENT_COLOR \
00151     "pigment { color %s }\n"
00152 
00153 #define POV_COLOR_NAME \
00154     "%s transmit %.3f"
00155 
00156 #define POV_COLOR_RGB \
00157     "rgb"POV_VECTOR3" transmit %.3f"
00158 
00159 //colors are taken from /usr/share/povray-3.6/include/colors.inc
00160 //list must be LANG_C sorted (all lower case)
00161 #define POV_COLORS \
00162 "aquamarine",\
00163 "bakerschoc",\
00164 "black",\
00165 "blue",\
00166 "blueviolet",\
00167 "brass",\
00168 "brightgold",\
00169 "bronze",\
00170 "bronze2",\
00171 "brown",\
00172 "cadetblue",\
00173 "clear",\
00174 "coolcopper",\
00175 "copper",\
00176 "coral",\
00177 "cornflowerblue",\
00178 "cyan",\
00179 "darkbrown",\
00180 "darkgreen",\
00181 "darkolivegreen",\
00182 "darkorchid",\
00183 "darkpurple",\
00184 "darkslateblue",\
00185 "darkslategray",\
00186 "darkslategrey",\
00187 "darktan",\
00188 "darkturquoise",\
00189 "darkwood",\
00190 "dkgreencopper",\
00191 "dustyrose",\
00192 "feldspar",\
00193 "firebrick",\
00194 "flesh",\
00195 "forestgreen",\
00196 "gold",\
00197 "goldenrod",\
00198 "gray05",\
00199 "gray10",\
00200 "gray15",\
00201 "gray20",\
00202 "gray25",\
00203 "gray30",\
00204 "gray35",\
00205 "gray40",\
00206 "gray45",\
00207 "gray50",\
00208 "gray55",\
00209 "gray60",\
00210 "gray65",\
00211 "gray70",\
00212 "gray75",\
00213 "gray80",\
00214 "gray85",\
00215 "gray90",\
00216 "gray95",\
00217 "green",\
00218 "greencopper",\
00219 "greenyellow",\
00220 "huntersgreen",\
00221 "indianred",\
00222 "khaki",\
00223 "lightblue",\
00224 "light_purple",\
00225 "lightsteelblue",\
00226 "lightwood",\
00227 "limegreen",\
00228 "magenta",\
00229 "mandarinorange",\
00230 "maroon",\
00231 "mediumaquamarine",\
00232 "mediumblue",\
00233 "mediumforestgreen",\
00234 "mediumgoldenrod",\
00235 "mediumorchid",\
00236 "mediumseagreen",\
00237 "mediumslateblue",\
00238 "mediumspringgreen",\
00239 "mediumturquoise",\
00240 "mediumvioletred",\
00241 "mediumwood",\
00242 "med_purple",\
00243 "mica",\
00244 "midnightblue",\
00245 "navy",\
00246 "navyblue",\
00247 "neonblue",\
00248 "neonpink",\
00249 "newmidnightblue",\
00250 "newtan",\
00251 "oldgold",\
00252 "orange",\
00253 "orangered",\
00254 "orchid",\
00255 "palegreen",\
00256 "pink",\
00257 "plum",\
00258 "quartz",\
00259 "red",\
00260 "richblue",\
00261 "salmon",\
00262 "scarlet",\
00263 "seagreen",\
00264 "semiSweetChoc",\
00265 "sienna",\
00266 "silver",\
00267 "skyblue",\
00268 "slateblue",\
00269 "spicypink",\
00270 "springgreen",\
00271 "steelblue",\
00272 "summersky",\
00273 "tan",\
00274 "thistle",\
00275 "turquoise",\
00276 "verydarkbrown",\
00277 "very_light_purple",\
00278 "violet",\
00279 "violetred",\
00280 "wheat",\
00281 "white",\
00282 "yellow",\
00283 "yellowgreen"
00284 
00285 #define GV_OBJ_EXT(type, obj, name) \
00286         do { \
00287                 char debug_str[256]; \
00288                 gvprintf(job, POV_DECLARE, type, obj); \
00289                 gvprintf(job, POV_OBJECT, type); \
00290                 gvprintf(job, POV_DECLARE, "Min", "min_extent("type")"); \
00291                 gvprintf(job, POV_DECLARE, "Max", "max_extent("type")"); \
00292                 snprintf(debug_str, 256,  \
00293                         "concat(\"Dim = \" , vstr(3, Max - Min, \", \", 0, 3)," \
00294                         " \" "type": %s\", \"\\n\")", name); \
00295                 gvprintf(job, POV_DEBUG, debug_str); \
00296         } while (0)
00297 
00298 /*
00299 //png, gif, NO jpg!
00300 pigment
00301 { image_map
00302   { gif "image.gif"
00303     map_type 1
00304   }
00305 }
00306 */
00307 
00308 /*
00309 #declare Sphere =
00310 sphere {
00311   <0,0,0>, 1
00312   pigment { rgb <1,0,0> }
00313 }
00314 #declare Min = min_extent ( Sphere );
00315 #declare Max = max_extent ( Sphere );
00316 object { Sphere }
00317 box {
00318     Min, Max 
00319     pigment { rgbf <1,1,1,0.5> }
00320     scale<20,20,20>
00321 }
00322 */
00323 
00324 /*
00325 STRING functions
00326 
00327 str( float , min_len , digits_after_dot )
00328 concat( STRING , STRING , [STRING ,...])
00329 chr( INT )
00330 substr( STRING , INT , INT )
00331 strupr( STRING ) 
00332 strlwr( STRING )
00333 vstr( vec_dimension , vec, sep_str, min_len, digits_after_dot )
00334 
00335 examples:
00336 #debug vstr(3, Min, ", ", 0, 3)                                                                                                                                                                                        
00337 #debug "\n*****************\n"
00338 #debug concat ( "Max =", vstr(3, Max, ", ", 0, 3), chr(13), chr(10) )
00339 */
00340 
00341 
00342 #define DPI 72.0
00343 #define RENDERER_COLOR_TYPE RGBA_BYTE
00344 typedef enum { FORMAT_POV, } format_type;
00345 
00346 //#define DEBUG
00347 
00348 //TODO: check why this dot file does not work (90 rotated)
00349 //   /usr/share/graphviz/graphs/directed/NaN.gv
00350 //TODO: add Texttures
00351 //TODO: check how we can receive attributes from dot file
00352 //   if we can't receive attributes set defaults in pov include file
00353 //   - put #include "graph-scheme-fancy.inc" in pov file
00354 //   - run povray with +L`pwd`
00355 //   - put e.g. #declare mycolor = Gold; in graph-scheme-fancy.inc
00356 //   - use textures and color: pigment { color mycolor transmit 0.000 }
00357 //TODO: idea, put the whole graph in a declare= and then
00358 //   print it with something along the line:
00359 //   object{ graph translate{page->translation, ...} rotate{page->rotation, ...} }
00360 
00361 static char *pov_knowncolors[] = { POV_COLORS };
00362 
00363 static float layerz = 0;
00364 static float z = 0;
00365 
00366 char *el(GVJ_t* job, char *template, ...)
00367 {
00368 #if defined(HAVE_VASPRINTF)
00369         char *str;
00370         va_list arglist;
00371 
00372         va_start(arglist, template);
00373         vasprintf(&str, template, arglist);
00374         va_end(arglist);
00375 
00376         return str;
00377 #elif defined(HAVE_VSNPRINTF)
00378         char buf[BUFSIZ];
00379         size_t len;
00380         char *str;
00381         va_list arglist;
00382 
00383         va_start(arglist, template);
00384         len = vsnprintf((char *)buf, BUFSIZ, template, arglist);
00385         if (len < 0) {
00386                 job->common->errorfn("pov renderer:el - %s\n", strerror(errno));
00387                 str = strdup ("");
00388         }
00389         else if (len >= BUFSIZ) {
00390                 str = malloc (len+1);
00391                 va_end(arglist);
00392                 va_start(arglist, template);
00393                 len = vsprintf(str, template, arglist);
00394         }
00395         else {
00396                 str = strdup (buf);
00397         }
00398         va_end(arglist);
00399 
00400         return str;
00401 #else
00402 /* Dummy function that will never be used */
00403         return strdup(""); 
00404 #endif
00405 }
00406 
00407 static char *pov_color_as_str(GVJ_t * job, gvcolor_t color, float transparency)
00408 {
00409         char *pov, *c;
00410         switch (color.type) {
00411         case COLOR_STRING:
00412 #ifdef DEBUG
00413                 gvprintf(job, "// type = %d, color = %s\n", color.type, color.u.string);
00414 #endif
00415                 if (!strcmp(color.u.string, "red"))
00416                         c = el(job, POV_COLOR_NAME, "Red", transparency);
00417                 else if (!strcmp(color.u.string, "green"))
00418                         c = el(job, POV_COLOR_NAME, "Green", transparency);
00419                 else if (!strcmp(color.u.string, "blue"))
00420                         c = el(job, POV_COLOR_NAME, "Blue", transparency);
00421                 else
00422                         c = el(job, POV_COLOR_NAME, color.u.string, transparency);
00423                 break;
00424         case RENDERER_COLOR_TYPE:
00425 #ifdef DEBUG
00426                 gvprintf(job, "// type = %d, color = %d, %d, %d\n",
00427                          color.type, color.u.rgba[0], color.u.rgba[1],
00428                          color.u.rgba[2]);
00429 #endif
00430                 c = el(job, POV_COLOR_RGB,
00431                        color.u.rgba[0] / 256.0, color.u.rgba[1] / 256.0,
00432                        color.u.rgba[2] / 256.0, transparency);
00433                 break;
00434         default:
00435                 fprintf(stderr,
00436                         "oops, internal error: unhandled color type=%d %s\n",
00437                         color.type, color.u.string);
00438                 assert(0);      //oops, wrong type set in gvrender_features_t?
00439         }
00440         pov = el(job, POV_PIGMENT_COLOR, c);
00441         free(c);
00442         return pov;
00443 }
00444 
00445 static void pov_comment(GVJ_t * job, char *str)
00446 {
00447         gvprintf(job, "//*** comment: %s\n", str);
00448 }
00449 
00450 static void pov_begin_job(GVJ_t * job)
00451 {
00452         gvputs(job, POV_VERSION);
00453         gvputs(job, POV_GLOBALS);
00454         gvputs(job, POV_DEFAULT);
00455         gvputs(job, POV_INCLUDE);
00456         gvprintf(job, POV_DECLARE, "black", "Black");
00457         gvprintf(job, POV_DECLARE, "white", "White");
00458 }
00459 
00460 static void pov_begin_graph(GVJ_t * job)
00461 {
00462         float x, y, d, px, py;
00463 
00464         gvprintf(job, "//*** begin_graph %s\n", agnameof(job->obj->u.g));
00465 #ifdef DEBUG
00466         gvprintf(job, "// graph_index = %d, pages = %d, layer = %d/%d\n",
00467                  job->graph_index, job->numPages, job->layerNum,
00468                  job->numLayers);
00469         gvprintf(job, "// pagesArraySize.x,y = %d,%d\n", job->pagesArraySize.x,
00470                  job->pagesArraySize.y);
00471         gvprintf(job, "// pagesArrayFirst.x,y = %d,%d\n",
00472                  job->pagesArrayFirst.x, job->pagesArrayFirst.y);
00473         gvprintf(job, "// pagesArrayElem.x,y = %d,%d\n", job->pagesArrayElem.x,
00474                  job->pagesArrayElem.y);
00475         gvprintf(job, "// bb.LL,UR = %.3f,%.3f, %.3f,%.3f\n", job->bb.LL.x,
00476                  job->bb.LL.y, job->bb.UR.x, job->bb.UR.y);
00477         gvprintf(job, "// pageBox in graph LL,UR = %.3f,%.3f, %.3f,%.3f\n",
00478                  job->pageBox.LL.x, job->pageBox.LL.y, job->pageBox.UR.x,
00479                  job->pageBox.UR.y);
00480         gvprintf(job, "// pageSize.x,y = %.3f,%.3f\n", job->pageSize.x,
00481                  job->pageSize.y);
00482         gvprintf(job, "// focus.x,y = %.3f,%.3f\n", job->focus.x, job->focus.y);
00483         gvprintf(job, "// zoom = %.3f, rotation = %d\n", job->zoom,
00484                  (float)job->rotation);
00485         gvprintf(job, "// view port.x,y = %.3f,%.3f\n", job->view.x,
00486                  job->view.y);
00487         gvprintf(job, "// canvasBox LL,UR = %.3f,%.3f, %.3f,%.3f\n",
00488                  job->canvasBox.LL.x, job->canvasBox.LL.y, job->canvasBox.UR.x,
00489                  job->canvasBox.UR.y);
00490         gvprintf(job, "// pageBoundingBox LL,UR = %d,%d, %d,%d\n",
00491                  job->pageBoundingBox.LL.x, job->pageBoundingBox.LL.y,
00492                  job->pageBoundingBox.UR.x, job->pageBoundingBox.UR.y);
00493         gvprintf(job, "// boundingBox (all pages) LL,UR = %d,%d, %d,%d\n",
00494                  job->boundingBox.LL.x, job->boundingBox.LL.y,
00495                  job->boundingBox.UR.x, job->boundingBox.UR.y);
00496         gvprintf(job, "// scale.x,y = %.3f,%.3f\n", job->scale.x, job->scale.y);
00497         gvprintf(job, "// translation.x,y = %.3f,%.3f\n", job->translation.x,
00498                  job->translation.y);
00499         gvprintf(job, "// devscale.x,y = %.3f,%.3f\n", job->devscale.x,
00500                  job->devscale.y);
00501         gvprintf(job, "// verbose = %d\n", job->common->verbose);
00502         gvprintf(job, "// cmd = %s\n", job->common->cmdname);
00503         gvprintf(job, "// info = %s, %s, %s\n", job->common->info[0],
00504                  job->common->info[1], job->common->info[2]);
00505 #endif
00506 
00507         //setup scene
00508         x = job->view.x / 2.0 * job->scale.x;
00509         y = job->view.y / 2.0 * job->scale.y;
00510         d = -500;
00511         px = atanf(x / abs(d)) * 180 / M_PI * 2;
00512         py = atanf(y / abs(d)) * 180 / M_PI * 2;
00513         gvprintf(job, POV_CAMERA, x, y, d, x, y, 0.0,
00514                  (px > py ? px : py) * 1.2);
00515         gvputs(job, POV_SKY_AND_GND);
00516         gvputs(job, POV_LIGHT);
00517 }
00518 
00519 static void pov_end_graph(GVJ_t * job)
00520 {
00521         gvputs(job, "//*** end_graph\n");
00522 }
00523 
00524 static void pov_begin_layer(GVJ_t * job, char *layername, int layerNum, int numLayers)
00525 {
00526         gvprintf(job, "//*** begin_layer: %s, %d/%d\n", layername, layerNum,
00527                  numLayers);
00528         layerz = layerNum * -10;
00529 }
00530 
00531 static void pov_end_layer(GVJ_t * job)
00532 {
00533         gvputs(job, "//*** end_layer\n");
00534 }
00535 
00536 static void pov_begin_page(GVJ_t * job)
00537 {
00538         gvputs(job, "//*** begin_page\n");
00539 }
00540 
00541 static void pov_end_page(GVJ_t * job)
00542 {
00543         gvputs(job, "//*** end_page\n");
00544 }
00545 
00546 static void pov_begin_cluster(GVJ_t * job)
00547 {
00548         gvputs(job, "//*** begin_cluster\n");
00549         layerz -= 2;
00550 }
00551 
00552 static void pov_end_cluster(GVJ_t * job)
00553 {
00554         gvputs(job, "//*** end_cluster\n");
00555 }
00556 
00557 static void pov_begin_node(GVJ_t * job)
00558 {
00559         gvprintf(job, "//*** begin_node: %s\n", agnameof(job->obj->u.n));
00560 }
00561 
00562 static void pov_end_node(GVJ_t * job)
00563 {
00564         gvputs(job, "//*** end_node\n");
00565 }
00566 
00567 static void pov_begin_edge(GVJ_t * job)
00568 {
00569         gvputs(job, "//*** begin_edge\n");
00570         layerz -= 5;
00571 #ifdef DEBUG
00572         gvprintf(job, "// layerz = %.3f\n", layerz);
00573 #endif
00574 }
00575 
00576 static void pov_end_edge(GVJ_t * job)
00577 {
00578         gvputs(job, "//*** end_edge\n");
00579         layerz += 5;
00580 #ifdef DEBUG
00581         gvprintf(job, "// layerz = %.3f\n", layerz);
00582 #endif
00583 }
00584 
00585 static void pov_textpara(GVJ_t * job, pointf c, textpara_t * para)
00586 {
00587         double x, y;
00588         char *pov, *s, *r, *t, *p;
00589 
00590         gvprintf(job, "//*** textpara: %s, fontsize = %.3f, fontname = %s\n",
00591                  para->str, para->fontsize, para->fontname);
00592         z = layerz - 9;
00593 
00594 #ifdef DEBUG
00595         if (para->postscript_alias)
00596                 gvputs(job, "// Warning: postscript_alias not handled!\n");
00597 #endif
00598 
00599         //handle text justification
00600         switch (para->just) {
00601         case 'l':               //left justified
00602                 break;
00603         case 'r':               //right justified
00604                 c.x = c.x - para->width;
00605                 break;
00606         default:
00607         case 'n':               //centered
00608                 c.x = c.x - para->width / 2.0;
00609                 break;
00610         }
00611 
00612         x = (c.x + job->translation.x) * job->scale.x;
00613         y = (c.y + job->translation.y) * job->scale.y;
00614 
00615         s = el(job, POV_SCALE1, para->fontsize * job->scale.x);
00616         r = el(job, POV_ROTATE, 0.0, 0.0, (float)job->rotation);
00617         t = el(job, POV_TRANSLATE, x, y, z);
00618         p = pov_color_as_str(job, job->obj->pencolor, 0.0);
00619 
00620         //pov bundled fonts: timrom.ttf, cyrvetic.ttf
00621         pov = el(job, POV_TEXT "    %s    %s    %s    %s    %s" END,
00622                 para->fontname, 0.25, 0.0,      //font, depth (0.5 ... 2.0), offset
00623                 para->str, "    no_shadow\n", s, r, t, p);
00624 
00625 #ifdef DEBUG
00626         GV_OBJ_EXT("Text", pov, para->str);
00627         gvprintf(job, "sphere{<0, 0, 0>, 2\ntranslate<%f, %f, %f>\n"
00628                  "pigment{color Red}\nno_shadow\n}\n", x, y, z - 1);
00629 #else
00630         gvputs(job, pov);
00631 #endif
00632 
00633         free(pov);
00634         free(r);
00635         free(p);
00636         free(t);
00637         free(s);
00638 }
00639 
00640 static void pov_ellipse(GVJ_t * job, pointf * A, int filled)
00641 {
00642         char *pov, *s, *r, *t, *p;
00643         float cx, cy, rx, ry, w;
00644 
00645         gvputs(job, "//*** ellipse\n");
00646         z = layerz - 6;
00647 
00648         // A[0] center, A[1] corner of ellipse
00649         cx = (A[0].x + job->translation.x) * job->scale.x;
00650         cy = (A[0].y + job->translation.y) * job->scale.y;
00651         rx = (A[1].x - A[0].x) * job->scale.x;
00652         ry = (A[1].y - A[0].y) * job->scale.y;
00653         w = job->obj->penwidth / (rx + ry) / 2.0 * 5;
00654 
00655         //draw rim (torus)
00656         s = el(job, POV_SCALE3, rx, (rx + ry) / 4.0, ry);
00657         r = el(job, POV_ROTATE, 90.0, 0.0, (float)job->rotation);
00658         t = el(job, POV_TRANSLATE, cx, cy, z);
00659         p = pov_color_as_str(job, job->obj->pencolor, 0.0);
00660 
00661         pov = el(job, POV_TORUS "    %s    %s    %s    %s" END, 1.0, w, //radius, size of ring
00662                  s, r, t, p);
00663 
00664 #ifdef DEBUG
00665         GV_OBJ_EXT("Torus", pov, "");
00666         gvprintf(job, "sphere{<0, 0, 0>, 2\ntranslate<%f, %f, %f>\n"
00667                  "pigment{color Green}\nno_shadow\n}\n", cx, cy, z - 1);
00668 #else
00669         gvputs(job, pov);
00670 #endif
00671 
00672         free(s);
00673         free(r);
00674         free(t);
00675         free(p);
00676         free(pov);
00677 
00678         //backgroud of ellipse if filled
00679         if (filled) {
00680                 s = el(job, POV_SCALE3, rx, ry, 1.0);
00681                 r = el(job, POV_ROTATE, 0.0, 0.0, (float)job->rotation);
00682                 t = el(job, POV_TRANSLATE, cx, cy, z);
00683                 p = pov_color_as_str(job, job->obj->fillcolor, 0.0);
00684 
00685                 pov = el(job, POV_SPHERE "    %s    %s    %s    %s" END,
00686                          0.0, 0.0, 0.0, s, r, t, p);
00687 
00688                 gvputs(job, pov);
00689 
00690                 free(s);
00691                 free(r);
00692                 free(t);
00693                 free(p);
00694                 free(pov);
00695         }
00696 }
00697 
00698 static void pov_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
00699                        int arrow_at_end, int filled)
00700 {
00701         int i;
00702         char *v, *x;
00703         char *pov, *s, *r, *t, *p;
00704 
00705         gvputs(job, "//*** bezier\n");
00706         z = layerz - 4;
00707 
00708         s = el(job, POV_SCALE3, job->scale.x, job->scale.y, 1.0);
00709         r = el(job, POV_ROTATE, 0.0, 0.0, (float)job->rotation);
00710         t = el(job, POV_TRANSLATE, 0.0, 0.0, z - 2);
00711         p = pov_color_as_str(job, job->obj->fillcolor, 0.0);
00712 
00713         pov = el(job, POV_SPHERE_SWEEP, "b_spline", n + 2);
00714 
00715         for (i = 0; i < n; i++) {
00716                 v = el(job, POV_VECTOR3 ", %.3f\n", A[i].x + job->translation.x, A[i].y + job->translation.y, 0.0, job->obj->penwidth); //z coordinate, thickness
00717                 x = el(job, "%s    %s", pov, v);        //catenate pov & vector v
00718                 free(v);
00719                 free(pov);
00720                 pov = x;
00721 
00722                 //TODO: we currently just use the start and end points of the curve as
00723                 //control points but we should use center of nodes
00724                 if (i == 0 || i == n - 1) {
00725                         v = el(job, POV_VECTOR3 ", %.3f\n", A[i].x + job->translation.x, A[i].y + job->translation.y, 0.0, job->obj->penwidth); //z coordinate, thickness
00726                         x = el(job, "%s    %s", pov, v);        //catenate pov & vector v
00727                         free(v);
00728                         free(pov);
00729                         pov = x;
00730                 }
00731 #ifdef DEBUG
00732                 gvprintf(job, "sphere{<0, 0, 0>, 2\ntranslate<%f, %f, %f>\n"
00733                          "pigment{color Yellow}\nno_shadow\n}\n",
00734                          (A[i].x + job->translation.x) * job->scale.x,
00735                          (A[i].y + job->translation.y) * job->scale.y, z - 2);
00736 #endif
00737         }
00738         x = el(job, "        tolerance 0.01\n    %s    %s    %s    %s" END, s, r, t,
00739                p);
00740         pov = el(job, "%s%s", pov, x);  //catenate pov & end str
00741         free(x);
00742 
00743         gvputs(job, pov);
00744 
00745         free(s);
00746         free(r);
00747         free(t);
00748         free(p);
00749         free(pov);
00750 }
00751 
00752 static void pov_polygon(GVJ_t * job, pointf * A, int n, int filled)
00753 {
00754         char *pov, *s, *r, *t, *p, *v, *x;
00755         int i;
00756 
00757         gvputs(job, "//*** polygon\n");
00758         z = layerz - 2;
00759 
00760         s = el(job, POV_SCALE3, job->scale.x, job->scale.y, 1.0);
00761         r = el(job, POV_ROTATE, 0.0, 0.0, (float)job->rotation);
00762         t = el(job, POV_TRANSLATE, 0.0, 0.0, z - 2);
00763         p = pov_color_as_str(job, job->obj->pencolor, 0.0);
00764 
00765         pov = el(job, POV_SPHERE_SWEEP, "linear_spline", n + 1);
00766 
00767         for (i = 0; i < n; i++) {
00768                 v = el(job, POV_VECTOR3 ", %.3f\n", A[i].x + job->translation.x, A[i].y + job->translation.y, 0.0, job->obj->penwidth); //z coordinate, thickness
00769                 x = el(job, "%s    %s", pov, v);        //catenate pov & vector v
00770                 free(v);
00771                 free(pov);
00772                 pov = x;
00773         }
00774 
00775         //close polygon, add starting point as final point^
00776         v = el(job, POV_VECTOR3 ", %.3f\n", A[0].x + job->translation.x, A[0].y + job->translation.y, 0.0, job->obj->penwidth); //z coordinate, thickness
00777 
00778         x = el(job, "%s    %s", pov, v);        //catenate pov & vector v
00779         free(v);
00780         free(pov);
00781         pov = x;
00782 
00783         x = el(job, "    tolerance 0.1\n    %s    %s    %s    %s" END, s, r, t, p);
00784         pov = el(job, "%s%s", pov, x);  //catenate pov & end str
00785         free(x);
00786 
00787         gvputs(job, pov);
00788 
00789         free(s);
00790         free(r);
00791         free(t);
00792         free(p);
00793         free(pov);
00794 
00795         //create fill background
00796         if (filled) {
00797                 s = el(job, POV_SCALE3, job->scale.x, job->scale.y, 1.0);
00798                 r = el(job, POV_ROTATE, 0.0, 0.0, (float)job->rotation);
00799                 t = el(job, POV_TRANSLATE, 0.0, 0.0, z - 2);
00800                 p = pov_color_as_str(job, job->obj->fillcolor, 0.25);
00801 
00802                 pov = el(job, POV_POLYGON, n);
00803 
00804                 for (i = 0; i < n; i++) {
00805                         //create on z = 0 plane, then translate to real z pos
00806                         v = el(job, POV_VECTOR3,
00807                                A[i].x + job->translation.x,
00808                                A[i].y + job->translation.y, 0.0);
00809                         x = el(job, "%s\n    %s", pov, v);      //catenate pov & vector v
00810                         free(v);
00811                         free(pov);
00812                         pov = x;
00813                 }
00814                 x = el(job, "\n    %s    %s    %s    %s" END, s, r, t, p);
00815                 pov = el(job, "%s%s", pov, x);  //catenate pov & end str
00816                 free(x);
00817 
00818                 gvputs(job, pov);
00819 
00820                 free(s);
00821                 free(r);
00822                 free(t);
00823                 free(p);
00824                 free(pov);
00825         }
00826 }
00827 
00828 static void pov_polyline(GVJ_t * job, pointf * A, int n)
00829 {
00830         char *pov, *s, *r, *t, *p, *v, *x;
00831         int i;
00832 
00833         gvputs(job, "//*** polyline\n");
00834         z = layerz - 6;
00835 
00836         s = el(job, POV_SCALE3, job->scale.x, job->scale.y, 1.0);
00837         r = el(job, POV_ROTATE, 0.0, 0.0, (float)job->rotation);
00838         t = el(job, POV_TRANSLATE, 0.0, 0.0, z);
00839         p = pov_color_as_str(job, job->obj->pencolor, 0.0);
00840 
00841         pov = el(job, POV_SPHERE_SWEEP, "linear_spline", n);
00842 
00843         for (i = 0; i < n; i++) {
00844                 v = el(job, POV_VECTOR3 ", %.3f\n", A[i].x + job->translation.x, A[i].y + job->translation.y, 0.0, job->obj->penwidth); //z coordinate, thickness
00845                 x = el(job, "%s    %s", pov, v);        //catenate pov & vector v
00846                 free(v);
00847                 free(pov);
00848                 pov = x;
00849         }
00850 
00851         x = el(job, "    tolerance 0.01\n    %s    %s    %s    %s" END, s, r, t, p);
00852         pov = el(job, "%s%s", pov, x);  //catenate pov & end str
00853         free(x);
00854 
00855         gvputs(job, pov);
00856 
00857         free(s);
00858         free(r);
00859         free(t);
00860         free(p);
00861         free(pov);
00862 }
00863 
00864 gvrender_engine_t pov_engine = {
00865         pov_begin_job,
00866         0,                      /* pov_end_job */
00867         pov_begin_graph,
00868         pov_end_graph,
00869         pov_begin_layer,
00870         pov_end_layer,
00871         pov_begin_page,
00872         pov_end_page,
00873         pov_begin_cluster,
00874         pov_end_cluster,
00875         0,                      /* pov_begin_nodes */
00876         0,                      /* pov_end_nodes */
00877         0,                      /* pov_begin_edges */
00878         0,                      /* pov_end_edges */
00879         pov_begin_node,
00880         pov_end_node,
00881         pov_begin_edge,
00882         pov_end_edge,
00883         0,                      /* pov_begin_anchor */
00884         0,                      /* pov_end_anchor */
00885         0,                      /* pov_begin_label */
00886         0,                      /* pov_end_label */
00887         pov_textpara,
00888         0,                      /* pov_resolve_color */
00889         pov_ellipse,
00890         pov_polygon,
00891         pov_bezier,
00892         pov_polyline,
00893         pov_comment,
00894         0,                      /* pov_library_shape */
00895 };
00896 
00897 gvrender_features_t render_features_pov = {
00898         /* flags */
00899         GVDEVICE_DOES_LAYERS
00900             | GVRENDER_DOES_MAP_RECTANGLE
00901             | GVRENDER_DOES_MAP_CIRCLE
00902             | GVRENDER_DOES_MAP_POLYGON
00903             | GVRENDER_DOES_MAP_ELLIPSE
00904             | GVRENDER_DOES_MAP_BSPLINE
00905             | GVRENDER_NO_WHITE_BG
00906             | GVRENDER_DOES_TRANSFORM
00907             | GVRENDER_DOES_Z | GVRENDER_DOES_MAP_BSPLINE,
00908         4.0,                    /* default pad - graph units */
00909         pov_knowncolors,        /* knowncolors */
00910         sizeof(pov_knowncolors) / sizeof(char *),       /* strings in knowncolors */
00911         RENDERER_COLOR_TYPE     /* set renderer color type */
00912 };
00913 
00914 gvdevice_features_t device_features_pov = {
00915         GVDEVICE_DOES_TRUECOLOR,        /* flags */
00916         {0.0, 0.0},             /* default margin - points */
00917         {0.0, 0.0},             /* default page width, height - points */
00918         {DPI, DPI},             /* default dpi */
00919 };
00920 
00921 gvplugin_installed_t gvrender_pov_types[] = {
00922 #ifdef HAVE_VSNPRINTF
00923         {FORMAT_POV, "pov", 1, &pov_engine, &render_features_pov},
00924 #endif
00925         {0, NULL, 0, NULL, NULL}
00926 };
00927 
00928 gvplugin_installed_t gvdevice_pov_types[] = {
00929 #ifdef HAVE_VSNPRINTF
00930         {FORMAT_POV, "pov:pov", 1, NULL, &device_features_pov},
00931 #endif
00932         {0, NULL, 0, NULL, NULL}
00933 };
00934