1<?php 2/** 3 * 3d Library 4 * 5 * PHP versions 5 6 * 7 * LICENSE: 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 * @category Image 23 * @package Image_3D 24 * @author Arne Nordmann <3d-rotate@arne-nordmann.de> 25 */ 26 27/** 28 * Creates a SVG, to move and rotate the 3D-object at runtime 29 * 30 * @category Image 31 * @package Image_3D 32 * @author Arne Nordmann <3d-rotate@arne-nordmann.de> 33 */ 34class Image_3D_Driver_SVGControl extends Image_3D_Driver 35{ 36 37 /** 38 * Width of the image 39 */ 40 protected $_x; 41 /** 42 * Height of the image 43 */ 44 protected $_y; 45 46 /** 47 * Current, increasing element-id (integer) 48 */ 49 protected $_id; 50 51 /** 52 * Array of gradients 53 */ 54 protected $_gradients; 55 /** 56 * Rectangle with background-color 57 */ 58 protected $_background; 59 /** 60 * Array of polygones 61 */ 62 protected $_polygones; 63 64 /** 65 * Constructor 66 * 67 */ 68 public function __construct() 69 { 70 $this->_image = ''; 71 $this->_id = 1; 72 73 $this->_gradients = array(); 74 $this->_polygones = array(); 75 } 76 77 /** 78 * Creates image header 79 * 80 * @param float $x width of the image 81 * @param float $y height of the image 82 * 83 * @return void 84 */ 85 public function createImage($x, $y) 86 { 87 $this->_x = (int) $x; 88 $this->_y = (int) $y; 89 90 $this->_image = <<<EOF 91<?xml version="1.0" ?> 92<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 93 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 94 95<svg xmlns="http://www.w3.org/2000/svg" x="0" y="0" width="{$this->_x}" height="{$this->_y}" onload="init(evt)"> 96EOF; 97 98 $this->_image .= "\n\n"; 99 } 100 101 /** 102 * Adds coloured background to the image 103 * 104 * Draws a rectangle with the size of the image and the passed colour 105 * 106 * @param Image_3D_Color $color Background colour of the image 107 * 108 * @return void 109 */ 110 public function setBackground(Image_3D_Color $color) 111 { 112 $this->_background = "\t<!-- coloured background -->\n"; 113 $this->_background .= sprintf("\t<rect id=\"background\" x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" style=\"%s\" />\n", 114 $this->_x, 115 $this->_y, 116 $this->_getStyle($color)); 117 } 118 119 protected function _getStyle(Image_3D_Color $color) 120 { 121 $values = $color->getValues(); 122 123 $values[0] = (int) round($values[0] * 255); 124 $values[1] = (int) round($values[1] * 255); 125 $values[2] = (int) round($values[2] * 255); 126 $values[3] = 1 - $values[3]; 127 128 // optional: "shape-rendering: optimizeSpeed;" to increase speed 129 return sprintf('fill:#%02x%02x%02x; stroke:none;', 130 $values[0], 131 $values[1], 132 $values[2]) 133 .((empty($values[3]))?'':' opacity:'.$values[3]); // opacity 134 } 135 136 protected function _getStop(Image_3D_Color $color, $offset = 0, $alpha = null) 137 { 138 $values = $color->getValues(); 139 140 $values[0] = (int) round($values[0] * 255); 141 $values[1] = (int) round($values[1] * 255); 142 $values[2] = (int) round($values[2] * 255); 143 if ($alpha === null) { 144 $values[3] = 1 - $values[3]; 145 } else { 146 $values[3] = 1 - $alpha; 147 } 148 149 return sprintf("\t\t\t<stop id=\"stop%d\" offset=\"%.1f\" style=\"stop-color:rgb(%d, %d, %d); stop-opacity:%.4f;\" />\n", 150 $this->_id++, 151 $offset, 152 $values[0], 153 $values[1], 154 $values[2], 155 $values[3]); 156 } 157 158 protected function _addGradient($string) 159 { 160 $id = 'linearGradient' . $this->_id++; 161 162 $this->_gradients[] = str_replace('[id]', $id, $string); 163 return $id; 164 } 165 166 protected function _addPolygon($string) 167 { 168 $id = 'data_polygon' . $this->_id++; 169 170 $this->_polygones[] = str_replace('[id]', $id, $string); 171 return $id; 172 } 173 174 public function drawPolygon(Image_3D_Polygon $polygon) 175 { 176 $list = ''; 177 $points = $polygon->getPoints(); 178 179 $svg = "\t\t\t<polygon id=\"[id]\" "; //Image_3D_P 180 181 // number of points 182 $svg .= 'nop="'.count($points).'" '; 183 184 // coordinates on start 185 foreach ($points as $nr => $point) { 186 $svg .= 'x'.$nr.'="'.round($point->getX()).'" '; 187 $svg .= 'y'.$nr.'="'.round($point->getY()).'" '; 188 $svg .= 'z'.$nr.'="'.round($point->getZ()).'" '; 189 } 190 $svg .= 'style="'.$this->_getStyle($polygon->getColor())."\" />\n"; 191 192 $this->_addPolygon($svg); 193 } 194 195 public function drawGradientPolygon(Image_3D_Polygon $polygon) 196 { 197 } 198 199 /** 200 * Creates scripting area for moving and rotating the object 201 * 202 * @return string 203 */ 204 protected function _getScript() 205 { 206 $p_count = count($this->_polygones); 207 208 // Create entire scripting area for moving and rotating the polygones 209 $script = <<<EOF 210 <!-- ECMAScript for moving and rotating --> 211 <script type="text/ecmascript"> <![CDATA[ 212 213 var svgdoc; 214 var svgns; 215 216 var width, height; 217 var viewpoint, distance; 218 219 var plist, pcont, t1; 220 221 var timer; 222 223 var mov_x, mov_y, mov_z; 224 var rot_x, rot_y, rot_z; 225 226 // Some kind of constructor 227 function init(evt) { 228 // Set image dimension 229 width = {$this->_x}; 230 height = {$this->_y}; 231 232 // Set viewpoint and distance for perspective 233 viewpoint = (width + height) / 2; 234 distance = (width + height) / 2; 235 236 // Set path to 0 237 mov_x = 0; 238 mov_y = 0; 239 mov_z = 0; 240 rot_x = 0; 241 rot_y = 0; 242 rot_z = 0; 243 244 // Reference the SVG-Document 245 svgdoc = evt.target.ownerDocument; 246 svgns = 'http://www.w3.org/2000/svg'; 247 248 // Reference list of Image_3D_Polygons 249 plist = svgdoc.getElementById('plist'); 250 251 // Reference container for polygones 252 pcont = svgdoc.getElementById('pcont'); 253 254 drawAllPolygones(); 255 } 256 257 // Draw all polygones 258 function drawAllPolygones() { 259 // Update all polygones 260 for (i=1; i<={$p_count}; ++i) { 261 dp = svgdoc.getElementById("data_polygon"+i); 262 263 // Number of points for this polygon 264 nop = parseInt(dp.getAttribute("nop")); 265 266 // find coordinates of each point 267 pstr = ''; 268 for (j=0; j<nop; ++j) { 269 x = parseInt(dp.getAttribute('x'+j)); 270 y = parseInt(dp.getAttribute('y'+j)); 271 z = parseInt(dp.getAttribute('z'+j)); 272 273 // Rotation 274 if (rot_x!=0 || rot_y!=0 || rot_z!=0) { 275 /*if (rot_x!=0) { 276 // rotate around the x-axis 277 } 278 279 if (rot_y!=0) { 280 // rotate around the y-axis 281 }*/ 282 283 if (rot_z!=0) { 284 // rotate around the z-axis 285 var b = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); 286 var phi = Math.atan2(x, y); 287 x = b * Math.sin(phi + Math.PI/360*rot_z); 288 y = b * Math.cos(phi + Math.PI/360*rot_z); 289 } 290 } 291 292 // Calculate coordinates on screen (perspectively - viewpoint, distance: 500) 293 x = Math.round(viewpoint * (x + mov_x) / (z + distance) + {$this->_x}) / 2; 294 y = Math.round(viewpoint * (y + mov_y) / (z + distance) + {$this->_y}) / 2; 295 296 // Create string of points 297 pstr += x+','+y+' '; 298 } 299 300 // Manipulate the polygon if existing, otherwise create it 301 p = svgdoc.getElementById("polygon"+i); 302 if (p==null) { 303 // Polygon doesn't exist, create it 304 p = svgdoc.createElementNS(svgns, 'polygon'); 305 306 // Get style of data polygon 307 var style = dp.getAttribute("style"); 308 p.setAttributeNS(null, "style", style); 309 310 p.setAttributeNS(null, "id", "polygon"+i); 311 p.setAttributeNS(null, "points", pstr); 312 pcont.appendChild(p); 313 } else { 314 // Polygon exists, just update points-attribute 315 p.setAttributeNS(null, "points", pstr); 316 } 317 } 318 } 319 320 // Translate X 321 function move_left(steps) { 322 if (steps>0) { 323 mov_x -= 3; 324 drawAllPolygones(); 325 timer = setTimeout('move_left('+(steps-1)+')', 1); 326 } 327 } 328 function move_right(steps) { 329 if (steps>0) { 330 mov_x += 3; 331 drawAllPolygones(); 332 timer = setTimeout('move_right('+(steps-1)+')', 1); 333 } 334 } 335 336 // Translate Y 337 function move_up(steps) { 338 if (steps>0) { 339 mov_y -= 3; 340 drawAllPolygones(); 341 timer = setTimeout('move_up('+(steps-1)+')', 1); 342 } 343 } 344 function move_down(steps) { 345 if (steps>0) { 346 mov_y += 3; 347 drawAllPolygones(); 348 timer = setTimeout('move_down('+(steps-1)+')', 1); 349 } 350 } 351 352 // Translate Z (zoom) 353 function zoom_in(steps) { 354 if (steps>0) { 355 distance -= 3; 356 viewpoint += 1; 357 drawAllPolygones(); 358 timer = setTimeout('zoom_in('+(steps-1)+')', 1); 359 } 360 } 361 function zoom_out(steps) { 362 if (steps>0) { 363 distance += 3; 364 viewpoint -= 1; 365 drawAllPolygones(); 366 timer = setTimeout('zoom_out('+(steps-1)+')', 1); 367 } 368 } 369 370 // Rotate Z 371 function rotate_z_cw(steps) { 372 if (steps>0) { 373 rot_z -= 6; 374 drawAllPolygones(); 375 timer = setTimeout('rotate_z_cw('+(steps-1)+')', 1); 376 } 377 } 378 function rotate_z_ccw(steps) { 379 if (steps>0) { 380 rot_z += 6; 381 drawAllPolygones(); 382 timer = setTimeout('rotate_z_ccw('+(steps-1)+')', 1); 383 } 384 } 385 386 // Back to default position 387 function move_to_default() { 388 // Move to default Position 389 mov_x = 0; 390 mov_y = 0; 391 mov_z = 0; 392 rot_x = 0; 393 rot_y = 0; 394 rot_z = 0; 395 396 // Kill existing timer to stop remaining movements 397 clearTimeout(timer); 398 399 // Zoom to default position 400 viewpoint = (width + height) / 2; 401 distance = (width + height) / 2; 402 403 // Draw all polygones with reset parameters 404 drawAllPolygones(); 405 } 406 407 // In- or decrease one of the three coordinates 408 function moveAllPolygones(coord, step) { 409 var p, c; 410 411 // Find all polygones 412 for (i=1; i<={$p_count}; ++i) { 413 p = svgdoc.getElementById('polygon'+i); 414 415 // Number of points for this polygon 416 nop = parseInt(p.getAttribute("nop")); 417 418 switch (coord) { 419 case 0 : // X 420 for (j=0; j<nop; ++j) { 421 var c = parseInt(p.getAttribute('x'+j)); 422 p.setAttribute('x'+j, (c+step)); 423 } 424 break; 425 case 1 : // Y 426 for (j=0; j<nop; ++j) { 427 var c = parseInt(p.getAttribute('y'+j)); 428 p.setAttribute('y'+j, (c+step)); 429 } 430 break; 431 case 2 : // Z 432 for (j=0; j<nop; ++j) { 433 var c = parseInt(p.getAttribute('z'+j)); 434 p.setAttribute('z'+j, (c+step)); 435 } 436 break; 437 } 438 } 439 } 440 441 ]]> </script> 442 443EOF; 444 445 return $script; 446 } 447 448 /** 449 * Creates controls for moving and rotating the object 450 * 451 * @return string 452 */ 453 protected function _getControls() 454 { 455 456 function drawArrow($x, $y, $id, $rot, $funct) 457 { 458 $arrow_points = ($x+12).','.($y+3).' '.($x+3).','.($y+8).' '.($x+12).','.($y+13); 459 460 $arrow = "\t<g id=\"".$id.'" transform="rotate('.$rot.', '.($x+8).', '.($y+8) 461 .')" onclick="'.$funct."\" style=\"cursor:pointer\">\n"; 462 $arrow .= "\t\t<rect x=\"".$x.'" y="'.$y.'" width="16" height="16" ' 463 ." style=\"fill:#bbb; stroke:none;\" />\n"; 464 $arrow .= "\t\t<rect x=\"".($x+1).'" y="'.($y+1).'" width="14" height="14" ' 465 ." style=\"fill:#ddd; stroke:none;\" />\n"; 466 $arrow .= "\t\t<polygon points=\"".$arrow_points.'" ' 467 ." style=\"fill:#000; stroke:none;\" />\n"; 468 $arrow .= "\t</g>\n"; 469 470 return $arrow; 471 } 472 473 $x = $this->_x * 0.05; 474 $y = $this->_y * 0.05; 475 476 $controls = "\n\t<!-- Control Elements -->\n"; 477 $controls .= "\t<rect x=\"0\" y=\"0\" width=\"".$this->_x."\" height=\"20\" style=\"fill:#eee; stroke:#ddd; stroke-width:1px; shape-rendering:optimizeSpeed;\" />\n"; 478 479 // Button "1:1" 480 $controls .= "\t<g onclick=\"move_to_default()\" style=\"cursor:pointer;\">\n"; 481 $controls .= "\t\t<rect x=\"0\" y=\"0\" width=\"20\" height=\"20\" style=\"fill:url(#b_off); stroke:#ccc; stroke-width:1px; shape-rendering:optimizeSpeed;\" />\n"; 482 $controls .= "\t\t<text x=\"10\" y=\"14\" style=\"font-size:10px; text-anchor:middle;\">1:1</text>\n"; 483 $controls .= "\t\t<rect x=\"0\" y=\"0\" width=\"20\" height=\"20\" style=\"opacity:0;\" />\n"; 484 $controls .= "\t</g>\n"; 485 486 // Button "zoom in" 487 $controls .= "\t<g onclick=\"zoom_in(10)\" transform=\"translate(25, 0)\" style=\"cursor:pointer;\">\n"; 488 $controls .= "\t\t<rect x=\"0\" y=\"0\" width=\"20\" height=\"20\" style=\"fill:url(#b_off); stroke:#ccc; stroke-width:1px; shape-rendering:optimizeSpeed;\" />\n"; 489 $controls .= "\t\t<path style=\"fill:#999; stroke:#aaa; stroke-width:1px;\" d=\"M 5 13 L 3 17 A 2 2 0 0 0 8 17 L 11 14\"/>\n"; 490 $controls .= "\t\t<circle cx=\"11\" cy=\"9\" r=\"7\" style=\"fill:#fff; stroke:#ccc; stroke-width:1px;\" />\n"; 491 $controls .= "\t\t<text x=\"11\" y=\"13\" style=\"font-size:10px; text-anchor:middle;\">+</text>\n"; 492 $controls .= "\t\t<rect x=\"0\" y=\"0\" width=\"20\" height=\"20\" style=\"opacity:0;\" />\n"; 493 $controls .= "\t</g>\n"; 494 495 // Button "zoom out" 496 $controls .= "\t<g onclick=\"zoom_out(10)\" transform=\"translate(46, 0)\" style=\"cursor:pointer;\">\n"; 497 $controls .= "\t\t<rect x=\"0\" y=\"0\" width=\"20\" height=\"20\" style=\"fill:url(#b_off); stroke:#ccc; stroke-width:1px; shape-rendering:optimizeSpeed;\" />\n"; 498 $controls .= "\t\t<path style=\"fill:#999; stroke:#aaa; stroke-width:1px;\" d=\"M 5 13 L 3 17 A 2 2 0 0 0 8 17 L 11 14\"/>\n"; 499 $controls .= "\t\t<circle cx=\"11\" cy=\"9\" r=\"7\" style=\"fill:#fff; stroke:#ccc; stroke-width:1px;\" />\n"; 500 $controls .= "\t\t<text x=\"10\" y=\"8\" style=\"font-size:10px; text-anchor:middle;\">_</text>\n"; 501 $controls .= "\t\t<rect x=\"0\" y=\"0\" width=\"20\" height=\"20\" style=\"opacity:0;\" />\n"; 502 $controls .= "\t</g>\n"; 503 504 /*// Button "hand" 505 $controls .= "\t<g transform=\"translate(70, 0)\">\n"; 506 $controls .= "\t\t<rect x=\"0\" y=\"0\" width=\"20\" height=\"20\" style=\"fill:url(#b_off); stroke:#ccc; stroke-width:1px; shape-rendering:optimizeSpeed;\" />\n"; 507 $controls .= "\t\t<path d=\"M 7.95,18.08 C 8.01,15.70 5.14,15.75 4.62,12.86 C 4.09,9.934 3.76,8.16 3.76,8.16 C 3.76,8.16 5.54,7.95 5.98,9.47 C 6.42,11 7.07,12.48 7.07,12.48 C 7.07,12.48 6.12,5.12 6.16,4.68 C 6.22,4.04 6.30,3.28 6.953,3.24 C 7.64,3.19 8.06,3.66 8.26,4.51 C 8.38,5.05 8.98,8.49 8.98,8.49 C 8.98,8.49 8.66,3.41 8.84,2.98 C 9.131,2.30 9.17,1.97 9.81,1.92 C 10.45,1.88 10.94,2.60 11.05,3.07 C 11.15,3.53 11.37,8.24 11.37,8.24 C 11.37,8.24 11.55,4.08 11.81,3.49 C 12.08,2.90 12.14,2.39 12.78,2.47 C 13.42,2.56 13.80,3.19 13.74,3.87 C 13.69,4.55 13.74,9.72 13.74,9.72 C 13.74,9.72 14.30,7.12 14.45,6.63 C 14.63,6.03 15.17,5.32 15.70,5.48 C 16.13,5.61 16.27,7.01 15.95,8.52 C 15.65,9.92 15.32,11.86 15.06,12.77 C 14.79,13.68 14.36,14.38 13.77,15.17 C 13.18,15.96 12.94,17.01 12.97,18.11 C 10.73,18.16 8.71,18.07 7.95,18.07\" style=\"fill:#fff; stroke:#000; stroke-width:.5;\" />\n"; 508 $controls .= "\t\t<rect x=\"0\" y=\"0\" width=\"20\" height=\"20\" style=\"opacity:0;\" />\n"; 509 $controls .= "\t</g>\n"; 510 511 // Button "drag" 512 $controls .= "\t<g transform=\"translate(91, 0)\">\n"; 513 $controls .= "\t\t<rect x=\"0\" y=\"0\" width=\"20\" height=\"20\" style=\"fill:url(#b_off); stroke:#ccc; stroke-width:1px; shape-rendering:optimizeSpeed;\" />\n"; 514 $controls .= "\t\t<text x=\"10\" y=\"14\" style=\"font-size:10px; text-anchor:middle;\">d</text>\n"; 515 $controls .= "\t\t<rect x=\"0\" y=\"0\" width=\"20\" height=\"20\" style=\"opacity:0;\" />\n"; 516 $controls .= "\t</g>\n";*/ 517 518 // Button "rotate counter-clockwise" 519 $controls .= "\t<g transform=\"translate(115, 0)\" onclick=\"rotate_z_ccw(15)\" style=\"cursor:pointer;\">\n"; 520 $controls .= "\t\t<rect x=\"0\" y=\"0\" width=\"20\" height=\"20\" style=\"fill:url(#b_off); stroke:#ccc; stroke-width:1px; shape-rendering:optimizeSpeed;\" />\n"; 521 $controls .= "\t\t<path style=\"fill:none; stroke:#000; stroke-width:1px;\" d=\"M 9 16 A 6 6 0 1 0 5 10\" />\n"; 522 $controls .= "\t\t<polygon style=\"fill:#000;\" points=\"2,10 8,10 5,14\" />\n"; 523 $controls .= "\t\t<rect x=\"0\" y=\"0\" width=\"20\" height=\"20\" style=\"opacity:0;\" />\n"; 524 $controls .= "\t</g>\n"; 525 526 // Button "rotate clockwise" 527 $controls .= "\t<g transform=\"translate(136, 0)\" onclick=\"rotate_z_cw(15)\" style=\"cursor:pointer;\">\n"; 528 $controls .= "\t\t<rect x=\"0\" y=\"0\" width=\"20\" height=\"20\" style=\"fill:url(#b_off); stroke:#ccc; stroke-width:1px; shape-rendering:optimizeSpeed;\" />\n"; 529 $controls .= "\t\t<path style=\"fill:none; stroke:#000; stroke-width:1px;\" d=\"M 9 16 A 6 6 0 1 1 15 10\" />\n"; 530 $controls .= "\t\t<polygon style=\"fill:#000;\" points=\"12,10 18,10 15,14\" />\n"; 531 $controls .= "\t\t<rect x=\"0\" y=\"0\" width=\"20\" height=\"20\" style=\"opacity:0;\" />\n"; 532 $controls .= "\t</g>\n"; 533 534 // Move left 535 $x = 0; 536 $y = $this->_y / 2 - 8; 537 538 $controls .= drawArrow($x, $y, 'move_left', 0, 'move_left(15)'); 539 540 // Move up 541 $x = $this->_x / 2 - 8; 542 $y = 20; 543 544 $controls .= drawArrow($x, $y, 'move_up', 90, 'move_up(15)'); 545 546 // Move right 547 $x = $this->_x - 16; 548 $y = $this->_y / 2 - 8; 549 550 $controls .= drawArrow($x, $y, 'move_right', 180, 'move_right(15)'); 551 552 // Move down 553 $x = $this->_x / 2 - 8; 554 $y = $this->_y - 16; 555 556 $controls .= drawArrow($x, $y, 'move_down', -90, 'move_down(15)'); 557 558 return $controls; 559 } 560 561 public function save($file) 562 { 563 // Start of SVG definition area 564 $this->_image .= sprintf("\t<defs id=\"defs%d\">\n", $this->_id++); 565 566 // Add scripting for moving and rotating 567 $this->_image .= $this->_getScript(); 568 569 // Add gradients in case of GAUROUD-shading 570 if (count($this->_gradients)>0) { 571 $this->_image .= implode('', $this->_gradients); 572 } 573 574 // Add all polygones 575 $this->_image .= "\n\t\t<!-- polygon data elements -->\n\t\t<g id=\"plist\">\n"; 576 $this->_image .= implode('', $this->_polygones); 577 $this->_image .= "\t\t</g>\n"; 578 579 /***** button gradients to defs *****/ 580 $this->_image .= "\t<linearGradient id=\"b_off\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n"; 581 $this->_image .= "\t\t<stop offset=\"0\" stop-color=\"#eee\" />\n"; 582 $this->_image .= "\t\t<stop offset=\"1\" stop-color=\"#ccc\" />\n"; 583 $this->_image .= "\t</linearGradient>\n"; 584 $this->_image .= "\t<linearGradient id=\"b_on\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n"; 585 $this->_image .= "\t\t<stop offset=\"0\" stop-color=\"#ccc\" />\n"; 586 $this->_image .= "\t\t<stop offset=\"1\" stop-color=\"#eee\" />\n"; 587 $this->_image .= "\t</linearGradient>\n"; 588 /**********/ 589 590 // End of SVG definition area 591 $this->_image .= sprintf("\t</defs>\n\n"); 592 593 // Draw background 594 $this->_image .= $this->_background; 595 596 // Create container for drawn polygones 597 $this->_image .= "\n\t<!-- Container for drawn polygones-->"; 598 $this->_image .= "\n\t<g id=\"cont\">"; 599 $this->_image .= "\n\t\t<g id=\"pcont\">"; 600 $this->_image .= "\n\t\t</g>"; 601 $this->_image .= "\n\t</g>\n"; 602 603 // Add controls for moving and rotating 604 $this->_image .= $this->_getControls(); 605 606 $this->_image .= "</svg>\n"; 607 file_put_contents($file, $this->_image); 608 } 609 610 public function getSupportedShading() 611 { 612 return array(Image_3D_Renderer::SHADE_NO, Image_3D_Renderer::SHADE_FLAT); 613 } 614} 615 616?> 617