diff --git a/api.php b/api.php --- a/api.php +++ b/api.php @@ -1,320 +1,319 @@ <?php /** * API entry point * * Zed. The immensity of stars. The HyperShip. The people. * * (c) 2010, Dereckson, some rights reserved. * Released under BSD license. * * @package Zed * @subpackage EntryPoints * @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org> * @copyright 2010 Sébastien Santoro aka Dereckson * @license http://www.opensource.org/licenses/bsd-license.php BSD * @version 0.1 * @link http://scherzo.dereckson.be/doc/zed * @link http://zed.dereckson.be/ * @filesource * @todo Consider to output documentation on / and /ship queries * @todo /app/getdata */ //API Preferences define('URL', 'http://' . $_SERVER['HTTP_HOST'] . '/index.php'); //Pluton library require_once('includes/core.php'); require_once('includes/config.php'); //API libs require_once('includes/api/api_helpers.php'); require_once('includes/api/cerbere.php'); //Use our URL controller method if you want to mod_rewrite the API $url = explode('/', substr($_SERVER['PATH_INFO'], 1)); switch ($module = $url[0]) { /* ------------------------------------------------------------- Site API /time /location - /perso (disabled) + /coordinates - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case '': //Nothing to do //TODO: offer documentation instead die(); case 'time': //Hypership time api_output(get_hypership_time(), "time"); break; case 'location': //Checks creditentials cerbere(); //Gets location info require_once("includes/geo/location.php"); $location = new GeoLocation($url[1], $url[2]); api_output($location, "location"); break; + + case 'coordinates': + //Checks creditentials + cerbere(); + //Get coordiantes + api_output(GeoGalaxy::get_coordinates(), 'galaxy', 'object'); + break; - //case 'perso': - // //Checks creditentials - // cerbere(); - // //Gets perso info - // require_once("includes/objects/perso.php"); - // $perso = new Perso($url[1]); - // api_output($perso, "perso"); - // break; /* ------------------------------------------------------------- Ship API /authenticate /appauthenticate /appauthenticated /move /land /flyout - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case 'ship': //Ship API //Gets ship from Ship API key (distinct of regular API keys) require_once('includes/objects/ship.php'); $ship = Ship::from_api_key($_REQUEST['key']) or cerbere_die("Invalid ship API key"); switch ($command = $url[1]) { case '': //Nothing to do //TODO: offer documentation instead die(); case 'authenticate': //TODO: web authenticate break; case 'appauthenticate': //Allows desktop application to authenticate an user $tmp_session_id = $url[2] or cerbere_die("/appauthenticate/ must be followed by any session identifier"); if ($_REQUEST['name']) { //Perso will be offered auth invite at next login. //Handy for devices like PDA, where it's not easy to auth. $perso = new Perso($_REQUEST['name']); if ($perso->lastError) { cerbere_die($perso->lastError); } if (!$ship->is_perso_authenticated($perso->id)) { $ship->request_perso_authenticate($perso->id); } $ship->request_perso_confirm_session($tmp_session_id, $perso->id); } else { //Delivers an URL. App have to redirects user to this URL //launching a browser or printing the link. $ship_code = $ship->get_code(); registry_set("api.ship.session.$ship_code.$tmp_session_id", -1); $url = get_server_url() . get_url() . "?action=api.ship.appauthenticate&session_id=" . $tmp_session_id; api_output($url, "URL"); } break; case 'appauthenticated': //Checks the user authentication $tmp_session_id = $url[2] or cerbere_die("/appauthenticated/ must be followed by any session identifier you used in /appauthenticate"); $perso_id = $ship->get_perso_from_session($tmp_session_id); if (!$isPersoAuth = $ship->is_perso_authenticated($perso_id)) { //Global auth not ok/revoked. $auth->status = -1; } else { $perso = Perso::get($perso_id); $auth->status = 1; $auth->perso->id = $perso->id; $auth->perso->nickname = $perso->nickname; $auth->perso->name = $perso->name; //$auth->perso->location = $perso->location; //Is the perso on board? Yes if its global location is S... $auth->perso->onBoard = ( $perso->location_global[0] == 'S' && substr($perso->location_global, 1, 5) == $ship->id ); if ($auth->perso->onBoard) { //If so, give local location $auth->perso->location_local = $perso->location_local; } } api_output($auth, "auth"); break; case 'move': //Moves the ship to a new location, given absolute coordinates //TODO: handle relative moves if (count($url) < 2) cerbere_die("/move/ must be followed by a location expression"); //Gets location class //It's allow: (1) to normalize locations between formats // (2) to ensure the syntax //==> if the ship want to communicate free forms coordinates, must be added on GeoLocation a free format try { $location = new GeoLocation($url[2]); } catch (Exception $ex) { $reply->success = 0; $reply->error = $ex->getMessage(); api_output($reply, "move"); break; } $ship->location_global = $location->global; $ship->save_to_database(); $reply->success = 1; $reply->location = $ship->location; api_output($reply, "move"); break; case 'land': case 'flyin': //Flies in try { $location = new GeoLocation($location); } catch (Exception $ex) { $reply->success = 0; $reply->error = $ex->getMessage(); api_output($reply, "land"); break; } break; case 'flyout': //Flies out break; } break; /* ------------------------------------------------------------- Application API /checkuserkey - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case 'app': //Application API require_once("includes/objects/application.php"); $app = Application::from_api_key($_REQUEST['key']) or cerbere_die("Invalid application API key"); switch ($command = $url[1]) { case '': //Nothing to do //TODO: offer documentation instead die(); case 'checkuserkey': if (count($url) < 2) cerbere_die("/checkuserkey/ must be followed by an user key"); $reply = (boolean)$app->get_perso_id($url[2]); api_output($reply, "check"); break; case 'pushuserdata': if (count($url) < 3) cerbere_die("/pushuserdata/ must be followed by an user key"); $perso_id = $app->get_perso_id($url[2]) or cerbere_die("Invalid application user key"); //then, falls to 'pushdata' case 'pushdata': $data_id = $_REQUEST['data'] ? $_REQUEST['data'] : new_guid(); //Gets data switch ($mode = $_REQUEST['mode']) { case '': cerbere_die("Add in your data posted or in the URL mode=file to read data from the file posted (one file per api call) or mode=request to read data from \$_REQUEST['data']."); case 'request': $data = $_REQUEST['data']; $format = "raw"; break; case 'file': $file = $_FILES['datafile']['tmp_name'] or cerbere_die("File is missing"); if (!is_uploaded_file($file)) cerbere_die("Invalid form request"); $data = ""; if (preg_match('/\.tar$/', $file)) { $format = "tar"; $data = file_get_contents($file); } elseif (preg_match('/\.tar\.bz2$/', $file)) { $format = "tar"; } elseif (preg_match('/\.bz2$/', $file)) { $format = "raw"; } else { $format = "raw"; $data = file_get_contents($file); } if ($data === "") { //.bz2 $bz = bzopen($file, "r") or cerbere_die("Couldn't open $file"); while (!feof($bz)) { $data .= bzread($bz, BUFFER_SIZE); } bzclose($bz); } unlink($file); break; default: cerbere_die("Invalid mode. Expected: file, request"); } //Saves data global $db; $data_id = $db->sql_escape($data_id); $data = $db->sql_escape($data); $perso_id = $perso_id ? $perso_id : 'NULL'; $sql = "REPLACE INTO applications_data (application_id, data_id, data_content, data_format, perso_id) VALUES ('$app->id', '$data_id', '$data', '$format', $perso_id)"; if (!$db->sql_query($sql)) message_die(SQL_ERROR, "Can't save data", '', __LINE__, __FILE__, $sql); //cerbere_die("Can't save data"); //Returns api_output($data_id); break; case 'getuserdata': // /api.php/getuserdata/data_id/perso_key // /api.php/getdata/data_id if (count($url) < 3) cerbere_die("/getuserdata/ must be followed by an user key"); $perso_id = $app->get_perso_id($url[2]) or cerbere_die("Invalid application user key"); //then, falls to 'getdata' case 'getdata': if (count($url) < 2) cerbere_die('/' + $url[0] + '/ must be followed by the data ID'); if (!$perso_id) $perso_id = 'NULL'; $data_id = $db->sql_escape($url[1]); $sql = "SELECT data_content FROM applications_data WHERE application_id = '$app->id' AND data_id = '$data_id' AND perso_id = $perso_id"; if (!$result = $db->sql_query($sql)) { message_die(SQL_ERROR, "Unable to query the table", '', __LINE__, __FILE__, $sql); } while ($row = $db->sql_fetchrow($result)) { } break; default: echo "Unknown module:"; dprint_r($url); break; } break; default: echo "Unknown module:"; dprint_r($url); break; } ?> diff --git a/dev/objects_viewer.html b/dev/objects_viewer.html new file mode 100644 --- /dev/null +++ b/dev/objects_viewer.html @@ -0,0 +1,219 @@ +<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" > +<head> + <title>Zed galaxy :: objects representation</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <link rel="Stylesheet" href="../css/zed/theme.css" type="text/css" /> + <style type="text/css"> + @import "/js/dojo/dojo/resources/dojo.css"; + @import "/js/dojo/dijit/tests/css/dijitTests.css"; + @import "/js/dojo/dijit/themes/tundra/tundra.css"; + + body { + margin-left: auto; + margin-right: auto; + } + + .viewscreen { + width: 500px; height: 500px; + background-color: black; + background-image: url('http://www.formandfunction.com/wraptures/datum-TILE/Astronomy/Cluster_Virgo.jpg'); + } + </style> + <script type="text/javascript" src="/js/misc.js" djConfig="isDebug: false"></script> + <script type="text/javascript" src="/js/dojo/dojo/dojo.js" djConfig="isDebug: false"></script> + <script type="text/javascript" src="/js/dojo/dojox/gfx3d/object.js"></script> + <script type="text/javascript" src="/js/dojo/dojox/gfx3d/scheduler.js"></script> + + <script type="text/javascript"> + dojo.require("dojox.gfx3d"); + + viewer = { + angles: {x: 30, y: 30, z: 0}, + view: null, + objects: null, + + getObjects: function() { + var url = 'http://zed51.dereckson.be/api.php/coordinates?key=303392c7-97c6-11df-a1e9-000c2923380c&format=json'; + + dojo.xhrGet({ + handleAs: "json", + url: url, + preventCache: true, + handle: function (response, ioArgs) { + viewer.objects = response; + viewer.drawObjects(); + } + }); + }, + + initialize: function() { + viewer.getObjects(); + }, + + drawObjects: function () { + viewer.makeObjects(); + + //Some cones to help understand the axis rotation + //(thanks Alphos for the tip) + var coneZ = [ + {x: 0, y: 0, z: 15}, + {x: 5, y: 0, z: 0}, + {x: 0, y: 5, z: 0}, + {x: -5, y: 0, z: 0}, + {x: 0, y: -5, z: 0} + ]; + + var coneX = [ + {x: 15, y: 0, z: 0}, + {x: 0, y: 5, z: 0}, + {x: 0, y: 0, z: 5}, + {x: 0, y: -5, z: 0}, + {x: 0, y: 0, z: -5} + ]; + + var coneY = [ + {x: 0, y: 15, z: 0}, + {x: 0, y: 0, z: 5}, + {x: 5, y: 0, z: 0}, + {x: 0, y: 0, z: -5}, + {x: -5, y: 0, z: 0} + ]; + + view.createTriangles(coneZ, "fan") + .setStroke({color: "blue", width: 1}) + .setFill("blue") + .applyTransform(dojox.gfx3d.matrix.translate({x: 0, y: 0, z: 200})); + + view.createTriangles(coneX, "fan") + .setStroke({color: "red", width: 1}) + .setFill("red") + .applyTransform(dojox.gfx3d.matrix.translate({x: 200, y: 0, z: 0})); + + view.createTriangles(coneY, "fan") + .setStroke({color: "green", width: 1}) + .setFill("green") + .applyTransform(dojox.gfx3d.matrix.translate({x: 0, y: 200, z: 0})); + + //Zed objects + for (i = 0 ; i < this.objects.length ; i++) { + var object = this.objects[i]; + switch (object[1]) { + case 'ship': + //Spaceship -> blue cube + var c = {bottom: object[2], top: {x: object[2].x + 10, y: object[2].y + 10, z: object[2].z + 10}}; + view.createCube(c).setFill({ type: "plastic", finish: "dull", color: "blue" }); + break; + + case 'hypership': + //Hypership -> Yellow cylinder + var c = {center: object[2], height: 15, radius: 8} + view.createCylinder(c) + .setStroke("black") + .setFill({type: "plastic", finish: "dull", color: "yellow"}); + break; + + case 'asteroid': + //Asteroid -> Red orbit + var o = {center: object[2], radius: 8} + view.createOrbit(o) + .setStroke({color: "red", width: 1}); + break; + + default: + alert('Not handled object type: ' + object[1]); + + } + } + }, + + rotate: function() { + var m = dojox.gfx3d.matrix; + + if(dojo.byId('rx').checked){ + viewer.angles.x += 1; + } + if(dojo.byId('ry').checked){ + viewer.angles.y += 1; + } + if(dojo.byId('rz').checked){ + viewer.angles.z += 1; + } + var t = m.normalize([ + m.cameraTranslate(-300, -200, 0), + m.cameraRotateXg(viewer.angles.x), + m.cameraRotateYg(viewer.angles.y), + m.cameraRotateZg(viewer.angles.z) + ]); + // console.debug(t); + view.setCameraTransform(t); + view.render(); + }, + + makeObjects: function(){ + var surface = dojox.gfx.createSurface("test", 500, 500); + view = surface.createViewport(); + + view.setLights([ + { direction: { x: -10, y: -5, z: 5 }, color: "white"} + ], + { color:"white", intensity: 2 }, + "white" + ); + + var xaxis = [{x: 0, y: 0, z: 0}, {x: 200, y: 0, z: 0}]; + var yaxis = [{x: 0, y: 0, z: 0}, {x: 0, y: 200, z: 0}]; + var zaxis = [{x: 0, y: 0, z: 0}, {x: 0, y: 0, z: 200}]; + + var m = dojox.gfx3d.matrix; + + view.createEdges(xaxis).setStroke({color: "red", width: 1}); + view.createEdges(yaxis).setStroke({color: "green", width: 1}); + view.createEdges(zaxis).setStroke({color: "blue", width: 1}); + + var camera = dojox.gfx3d.matrix.normalize([ + m.cameraTranslate(-300, -200, 0), + m.cameraRotateXg(this.angles.x), + m.cameraRotateYg(this.angles.y), + m.cameraRotateZg(this.angles.z) + ]); + + view.applyCameraTransform(camera); + view.render(); + setInterval(viewer.rotate, 50); + } + }; + + dojo.addOnLoad(viewer.initialize); + </script> +</head> +<body class="tundra"> +<div style="width: 960px; margin: auto; margin-top: 1em;" class="container_16"> + <div style="float: right; width: 400px;"> + <h1>Zed objects viewer</h1> + <h2>Objects viewer</h2> + <p>This page shows the different objects in the Zed galaxy.</p> + <p>This is based on the camera rotate <a href="http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/gfx3d/tests/test_camerarotate_shaded.html">dojox.gfx3d demo</a>. + <br />The background is a <a href="http://www.formandfunction.com/wraptures/LINX/w_astronomy.html">Cluster Virgo</a> from Jonathan Gibson, under CC-BY-SA license.</p> + <h2>Controls</h2> + <form> + <input id="rx" type="checkbox" name="rotateX" checked="true" value="on"/> + <label for="rx"> Rotate around X-axis (red)</label> <br/> + <input id="ry" type="checkbox" name="rotateY" checked="false" value="off"/> + <label for="ry"> Rotate around Y-axis (green)</label> <br/> + <input id="rz" type="checkbox" name="rotateZ" checked="false" value="off"/> + <label for="rz"> Rotate around Z-axis (blue)</label> <br/> + </form> + <h2>Legend</h2> + <ul> + <li>Blue cube: ship</li> + <li>Yellow cylinder: hypership</li> + <li>Red orbit: asteroid</li> + </ul> + </div> + + + <div id="test" class="viewscreen"></div> + +</div> +</body> +</html> \ No newline at end of file diff --git a/dev/quux.php b/dev/quux.php --- a/dev/quux.php +++ b/dev/quux.php @@ -1,87 +1,105 @@ <?php require_once('includes/objects/ship.php'); require_once('includes/objects/port.php'); require_once('includes/objects/application.php'); require_once('includes/objects/content.php'); require_once('includes/objects/message.php'); require_once('includes/objects/invite.php'); require_once('includes/cache/cache.php'); include('controllers/header.php'); - $case = 'travel'; + $case = 'spherical'; switch ($case) { + case 'spherical': + require_once('includes/geo/galaxy.php'); + echo '<H2>Spherical coordinates test</H2>'; + echo '<table cellpadding=8>'; + echo "<tr><th>Name</th><th>Type</th><th>Cartesian coords</th><th>Spherical I</th><th>Spherical II</th><th>Pencil coordinates</th></tr>"; + $objects = GeoGalaxy::get_coordinates(); + foreach ($objects as $row) { + echo "<tr><th style='text-align: left'>$row[0]</th><td>$row[1]</td><td>$row[2]</td>"; + $pt = $row[2]; + echo '<td>(', implode(', ', $pt->to_spherical()), ')</td>'; + echo '<td>(', implode(', ', $pt->to_spherical2()), ')</td>'; + $pt->translate(500, 300, 200, 2); + echo '<td>', $pt, '</td>'; + echo '</tr>'; + } + echo '</table>'; + break; + case 'travel': require_once('includes/travel/travel.php'); require_once('includes/travel/place.php'); $cache = Cache::load(); $travel = $cache->get('zed_travel'); if ($travel == '') { $travel_nocached = new Travel(); $travel_nocached->load_xml("content/travel.xml"); $cache->set('zed_travel', serialize($travel_nocached)); } else { $travel = unserialize($travel); } dieprint_r($travel); break; case 'perso.create.notify': $testperso = Perso::get(4733); $message = new Message(); $message->from = 0; $message->to = invite::who_invited(4733); $url = get_server_url() . get_url('who', $testperso->nickname); $message->text = sprintf(lang_get('InvitePersoCreated'), $testperso->name, $url); $message->send(); dieprint_r($message); break; case 'pushdata'; echo ' <h2>/api.php/app/pushdata</h2> <form method="post" action="/api.php/app/pushdata?mode=file&key=37d839ba-f9fc-42ca-a3e8-28053e979b90" enctype="multipart/form-data"> <input type="file" name="datafile" /><br /> <input type="submit" value="Send file" /> </form> '; break; case 'thumbnail': $content = new Content(1); dprint_r($content); $content->generate_thumbnail(); break; case 'port': echo '<h2>Port::from_location test</h2>'; $locations = array("B00002", "B00002123", "B00001001", "xyz: [800, 42, 220]"); foreach ($locations as $location) { dprint_r(Port::from_location($location)); } break; case 'ext': $file = 'dev/foo.tar'; echo "<h2>$file</h2>"; echo "<h3>.tar.bz2</h3>"; echo ereg('\.tar\.bz2$', $file); echo "<h3>.tar</h3>"; echo ereg('\.tar$', $file); break; case 'app': echo Application::from_api_key("37d839ba-f9fc-42ca-a3e8-28053e979b90")->generate_userkey(); break; case '': dieprint_r("No case currently selected."); break; } include('controllers/footer.php'); ?> \ No newline at end of file diff --git a/dev/schema-mysql.sql b/dev/schema-mysql.sql --- a/dev/schema-mysql.sql +++ b/dev/schema-mysql.sql @@ -1,633 +1,641 @@ -- phpMyAdmin SQL Dump -- version 3.3.3 -- http://www.phpmyadmin.net -- -- Serveur: localhost -- G�n�r� le : Sam 17 Juillet 2010 � 19:37 -- Version du serveur: 5.5.4 -- Version de PHP: 5.3.2 SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; -- -- Base de donn�es: `zed` -- -- -------------------------------------------------------- -- -- Structure de la table `api_keys` -- CREATE TABLE IF NOT EXISTS `api_keys` ( `key_guid` varchar(36) NOT NULL, `key_active` tinyint(1) unsigned NOT NULL DEFAULT '1', `key_description` tinytext, `key_hits` bigint(20) NOT NULL DEFAULT '0', `key_lastcall` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`key_guid`), KEY `key_active` (`key_active`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- -- Contenu de la table `api_keys` -- -- -------------------------------------------------------- -- -- Doublure de structure pour la vue `content` -- CREATE TABLE IF NOT EXISTS `content` ( `content_id` mediumint(8) unsigned ,`location_global` varchar(9) ,`location_local` varchar(255) ,`location_k` smallint(5) unsigned ,`content_path` varchar(255) ,`user_id` smallint(5) ,`perso_id` smallint(5) ,`content_title` varchar(255) ); -- -------------------------------------------------------- -- -- Structure de la table `content_files` -- CREATE TABLE IF NOT EXISTS `content_files` ( `content_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, `content_path` varchar(255) NOT NULL, `user_id` smallint(5) NOT NULL, `perso_id` smallint(5) NOT NULL, `content_title` varchar(255) NOT NULL, PRIMARY KEY (`content_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ; -- -- Contenu de la table `content_files` -- -- -------------------------------------------------------- -- -- Structure de la table `content_locations` -- CREATE TABLE IF NOT EXISTS `content_locations` ( `location_global` varchar(9) NOT NULL, `location_local` varchar(255) NOT NULL, `location_k` smallint(5) unsigned NOT NULL, `content_id` mediumint(8) unsigned NOT NULL, PRIMARY KEY (`location_global`,`location_local`,`location_k`), KEY `content_id` (`content_id`), KEY `location_global` (`location_global`,`location_local`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; -- -- Contenu de la table `content_locations` -- -- -------------------------------------------------------- -- -- Structure de la table `geo_bodies` -- CREATE TABLE IF NOT EXISTS `geo_bodies` ( `body_code` mediumint(5) unsigned zerofill NOT NULL AUTO_INCREMENT, `body_name` varchar(31) NOT NULL, `body_status` set('hypership','asteroid','moon','planet','star','orbital','hidden') DEFAULT NULL, `body_location` varchar(15) DEFAULT NULL, `body_description` text, PRIMARY KEY (`body_code`), KEY `body_status` (`body_status`), FULLTEXT KEY `text` (`body_name`,`body_description`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ; -- -- Contenu de la table `geo_bodies` -- INSERT INTO `geo_bodies` (`body_code`, `body_name`, `body_status`, `body_location`, `body_description`) VALUES (00001, 'Hypership', 'hypership', NULL, NULL), (00002, 'Xen', 'asteroid', NULL, NULL), (00003, 'Kaos', 'asteroid', NULL, NULL); -- -------------------------------------------------------- -- -- Doublure de structure pour la vue `geo_locations` -- CREATE TABLE IF NOT EXISTS `geo_locations` ( `location_code` varchar(9) ,`location_name` varchar(255) ); -- -------------------------------------------------------- -- -- Structure de la table `geo_places` -- CREATE TABLE IF NOT EXISTS `geo_places` ( `place_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, `body_code` mediumint(5) unsigned zerofill NOT NULL, `place_code` smallint(3) unsigned zerofill NOT NULL, `place_name` varchar(255) NOT NULL, `place_description` longtext NOT NULL, `place_status` set('start','hidden') DEFAULT NULL, PRIMARY KEY (`place_id`), UNIQUE KEY `body_id` (`body_code`,`place_code`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=6 ; -- -- Contenu de la table `geo_places` -- INSERT INTO `geo_places` (`place_id`, `body_code`, `place_code`, `place_name`, `place_description`, `place_status`) VALUES (1, 00001, 001, 'Tour', 'Tour circulaire, surplombant l''hypership, offrant une vue circulaire sur l''espace (ou l''ultraespace, ou l''hyperespace) et une rotonde aux derniers �tages.\r\n\r\n== Toponymie num�rique ==\r\nChaque niveau (correspondant � un secteur, identifi� par la lettre T suivi du niveau, en partant du haut) est divis� en 6 couloirs d''approximativement 60�.', NULL), (2, 00001, 002, 'Core', 'Le c.ur de l''hypership, son centre de gravit� et les 8 cubes l''entourant.\r\n\r\n== Toponymie num�rique ==\r\nLe core est divis� en 9 secteurs : C0 pour le centre de gravit�, C1 � C4 pour les cubes de la couche inf�rieure, C5 � C8 pour les cubes de la couche sup�rieure.', NULL), (3, 00002, 001, 'Algir', '', NULL), (4, 00003, 001, 'Zeta', '', 'start'), (5, 00001, 003, 'Bays', 'Baies permettant d''accueillir divers vaisseaux au sein de l''hypership.', NULL); -- -------------------------------------------------------- -- -- Structure de la table `log_smartline` -- CREATE TABLE IF NOT EXISTS `log_smartline` ( `command_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `perso_id` smallint(5) unsigned DEFAULT NULL, `command_time` int(10) DEFAULT NULL, `command_text` varchar(255) DEFAULT NULL, `isError` tinyint(1) DEFAULT '0', PRIMARY KEY (`command_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; -- -- Contenu de la table `log_smartline` -- -- -------------------------------------------------------- -- -- Structure de la table `messages` -- CREATE TABLE IF NOT EXISTS `messages` ( `message_id` mediumint(9) NOT NULL AUTO_INCREMENT, `message_date` int(11) NOT NULL DEFAULT '0', `message_from` varchar(4) NOT NULL DEFAULT '0', `message_to` varchar(4) NOT NULL DEFAULT '0', `message_text` longtext NOT NULL, `message_flag` tinyint(4) NOT NULL DEFAULT '0', PRIMARY KEY (`message_id`), KEY `message_to` (`message_to`), KEY `message_flag` (`message_flag`), KEY `message_date` (`message_date`), KEY `inbox` (`message_to`,`message_flag`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; -- -- Contenu de la table `messages` -- -- -------------------------------------------------------- -- -- Structure de la table `motd` -- CREATE TABLE IF NOT EXISTS `motd` ( `motd_id` int(11) NOT NULL AUTO_INCREMENT, `perso_id` int(11) NOT NULL, `motd_text` varchar(255) NOT NULL, `motd_date` int(10) NOT NULL, PRIMARY KEY (`motd_id`), KEY `perso_id` (`perso_id`), KEY `motd_date` (`motd_date`), FULLTEXT KEY `motd_text` (`motd_text`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=25 ; -- -- Contenu de la table `motd` -- INSERT INTO `motd` (`motd_id`, `perso_id`, `motd_text`, `motd_date`) VALUES (24, 4960, 'You''re on the *DEVELOPMENT AND TESTING server (database zed, using the repo hg)*', 1279161701); -- -------------------------------------------------------- -- -- Structure de la table `pages` -- CREATE TABLE IF NOT EXISTS `pages` ( `page_id` int(11) NOT NULL AUTO_INCREMENT, `page_code` varchar(31) NOT NULL, `page_title` varchar(255) NOT NULL, `page_content` longtext NOT NULL, PRIMARY KEY (`page_id`), UNIQUE KEY `page_code` (`page_code`), FULLTEXT KEY `page_text` (`page_code`,`page_title`,`page_content`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ; -- -- Contenu de la table `pages` -- INSERT INTO `pages` (`page_id`, `page_code`, `page_title`, `page_content`) VALUES (3, 'ArtworkCredits', 'Artwork credits', '<h2>Login screen</h2>\r\n<p>Wires and blocks use following tutorials:</p>\r\n<ul>\r\n <li><a href="http://www.tutorio.com/tutorial/futuristic-decay-interface">Futuristic Decay Interface</a></li>\r\n <li><a href="http://www.tutorio.com/tutorial/photoshop-wire-tutorial">Photoshop Wire Tutorial</a></li>\r\n</ul>\r\n<h2>Hypership</h2>\r\n<h3>Gallery tower</h3>\r\n<p>Technical schemas Dereckson. In the future, some could contain technical shapes Photoshop brushes, by <a href="http://scully7491.deviantart.com/">scully7491</a>.</p>\r\n<p>Portholes structure (c) Richard Carpenter, Six Revisions.<br />\r\nA <a href="http://sixrevisions.com/tutorials/photoshop-tutorials/how-to-design-a-space-futuristic-gallery-layout-in-photoshop/">tutorial is available here</a>.</p>\r\n<p>When the hypership is in hyperspace mode, portholes prints a colored background by <a href="http://www.sxc.hu/profile/ilco">ilco</a>.<br />\r\nWhen reaching a system, it prints a scene excerpt.</p>\r\n<h3>Core cancelled sector</h3>\r\n<p>Photographies: Jérôme<br />\r\nEditing: Dereckson</p>\r\n<h2>Scenes</h2>\r\n<h3>Xen and Kaos</h3>\r\n<p>Scene composed from 2 wallpapers from Interfacelift, n° 587 and 781.</p>\r\n<h2>Future sources</h2>\r\n<h3>Fasticon</h3>\r\n<p>It''s possible in the future some http://www.fasticon.com/ icons are added.</p>\r\n<h4>Comic Tiger</h4>\r\n<p>(c) <a href="mailto:dirceu@fasticon.com">Dirceu Veiga</a> - FastIcon Studio.<br />\r\n<strong>License:</strong> All Icons on the Fast Icon "Download" page are are FREEWARE, but to use our Icons in your software, web site, in a theme or other project, <a href="mailto:contact@fasticon.com">you need our permission first</a>. You don''t need permission for personal use our Icons on your computer.</p>'); -- -------------------------------------------------------- -- -- Structure de la table `pages_edits` -- CREATE TABLE IF NOT EXISTS `pages_edits` ( `page_edit_id` int(11) NOT NULL AUTO_INCREMENT, `page_code` varchar(255) DEFAULT NULL, `page_version` smallint(6) NOT NULL DEFAULT '0', `page_title` varchar(255) NOT NULL DEFAULT '', `page_content` longtext, `page_edit_reason` varchar(255) DEFAULT NULL, `page_edit_user_id` smallint(4) unsigned DEFAULT NULL, `page_edit_time` int(10) DEFAULT NULL, PRIMARY KEY (`page_edit_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ; -- -- Contenu de la table `pages_edits` -- -- -------------------------------------------------------- -- -- Structure de la table `persos` -- CREATE TABLE IF NOT EXISTS `persos` ( `user_id` smallint(4) DEFAULT NULL, `perso_id` smallint(4) NOT NULL DEFAULT '0', `perso_name` varchar(255) NOT NULL DEFAULT '', `perso_nickname` varchar(31) NOT NULL DEFAULT '', `perso_race` varchar(31) NOT NULL DEFAULT '', `perso_sex` enum('M','F','N','2') NOT NULL DEFAULT 'M', `perso_avatar` varchar(255) DEFAULT NULL, `location_global` varchar(9) DEFAULT 'B00001001', `location_local` varchar(255) DEFAULT NULL, PRIMARY KEY (`perso_id`), UNIQUE KEY `nickname` (`perso_nickname`), KEY `race` (`perso_race`), KEY `user_id` (`user_id`), KEY `location_global` (`location_global`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- -- Contenu de la table `persos` -- INSERT INTO `persos` (`user_id`, `perso_id`, `perso_name`, `perso_nickname`, `perso_race`, `perso_sex`, `perso_avatar`, `location_global`, `location_local`) VALUES (2600, 4960, 'Lorem Ipsum', 'demo', 'humanoid', 'M', '', 'B00003001', '1'); -- -------------------------------------------------------- -- -- Structure de la table `persos_flags` -- CREATE TABLE IF NOT EXISTS `persos_flags` ( `flag_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `perso_id` smallint(6) NOT NULL DEFAULT '0', `flag_key` varchar(255) NOT NULL, `flag_value` varchar(512) NOT NULL, PRIMARY KEY (`flag_id`), UNIQUE KEY `persoflag` (`perso_id`,`flag_key`), KEY `perso_id` (`perso_id`), KEY `flag_key` (`flag_key`), KEY `flag` (`flag_key`(127),`flag_value`(199)) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=459 ; -- -------------------------------------------------------- -- -- Structure de la table `persos_notes` -- CREATE TABLE IF NOT EXISTS `persos_notes` ( `perso_id` smallint(4) NOT NULL, `note_code` varchar(63) NOT NULL, `note_text` longtext NOT NULL, PRIMARY KEY (`perso_id`,`note_code`), KEY `perso_id` (`perso_id`), KEY `note_code` (`note_code`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; -- -- Contenu de la table `persos_notes` -- -- -------------------------------------------------------- -- -- Structure de la table `ports` -- CREATE TABLE IF NOT EXISTS `ports` ( `port_id` smallint(6) NOT NULL AUTO_INCREMENT, `location_global` char(9) NOT NULL, `location_local` varchar(255) NOT NULL, `port_name` varchar(63) NOT NULL, `port_status` set('hidden','requiresPTA') NOT NULL, PRIMARY KEY (`port_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ; -- -- Contenu de la table `ports` -- INSERT INTO `ports` (`port_id`, `location_global`, `location_local`, `port_name`, `port_status`) VALUES (1, 'B00003001', '3', 'Le D�me de Th�tys', ''), (2, 'B00001003', '', 'Hypership''s general bays', ''); -- -------------------------------------------------------- -- -- Structure de la table `profiles` -- CREATE TABLE IF NOT EXISTS `profiles` ( `perso_id` int(11) NOT NULL, `profile_text` longtext NOT NULL, `profile_updated` int(10) NOT NULL, `profile_fixedwidth` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`perso_id`), KEY `profile_fixedwidth` (`profile_fixedwidth`), KEY `profile_updated` (`profile_updated`), FULLTEXT KEY `profile` (`profile_text`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- -- Contenu de la table `profiles` -- -- -------------------------------------------------------- -- -- Structure de la table `profiles_comments` -- CREATE TABLE IF NOT EXISTS `profiles_comments` ( `comment_id` mediumint(9) NOT NULL AUTO_INCREMENT, `perso_id` smallint(5) unsigned NOT NULL, `comment_author` smallint(5) unsigned NOT NULL, `comment_date` int(10) NOT NULL, `comment_text` text NOT NULL, PRIMARY KEY (`comment_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ; -- -- Contenu de la table `profiles_comments` -- -- -------------------------------------------------------- -- -- Structure de la table `profiles_photos` -- CREATE TABLE IF NOT EXISTS `profiles_photos` ( `photo_id` int(11) NOT NULL AUTO_INCREMENT, `perso_id` smallint(6) NOT NULL, `photo_name` varchar(63) NOT NULL, `photo_description` varchar(63) NOT NULL, `photo_avatar` tinyint(4) NOT NULL DEFAULT '0', PRIMARY KEY (`photo_id`), UNIQUE KEY `photo_name` (`photo_name`), KEY `user_id` (`perso_id`), KEY `photo_avatar` (`photo_avatar`), KEY `user_avatar` (`perso_id`,`photo_avatar`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; -- -- Contenu de la table `profiles_photos` -- -- -------------------------------------------------------- -- -- Structure de la table `profiles_tags` -- CREATE TABLE IF NOT EXISTS `profiles_tags` ( `perso_id` int(11) NOT NULL, `tag_code` varchar(31) NOT NULL, `tag_class` varchar(15) NOT NULL DEFAULT 'music', PRIMARY KEY (`perso_id`,`tag_code`), KEY `tag_code` (`tag_code`), KEY `tag_class` (`tag_class`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- -- Contenu de la table `profiles_tags` -- -- -------------------------------------------------------- -- -- Structure de la table `registry` -- CREATE TABLE IF NOT EXISTS `registry` ( `registry_key` varchar(63) NOT NULL, `registry_value` longtext NOT NULL, `registry_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`registry_key`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- -- Contenu de la table `registry` -- INSERT INTO `registry` (`registry_key`, `registry_value`, `registry_updated`) VALUES ('api.ship.session.S00001.Demios0001', '1148', '2010-07-04 15:18:04'); -- -------------------------------------------------------- -- -- Structure de la table `sessions` -- CREATE TABLE IF NOT EXISTS `sessions` ( `session_id` varchar(32) NOT NULL DEFAULT '', `Where` tinyint(4) NOT NULL DEFAULT '1', `IP` varchar(8) NOT NULL DEFAULT '', `user_id` smallint(5) NOT NULL DEFAULT '-1', `perso_id` smallint(6) DEFAULT NULL, `Skin` varchar(31) NOT NULL DEFAULT 'zed', `Skin_accent` varchar(31) NOT NULL DEFAULT '', `online` tinyint(4) NOT NULL DEFAULT '1', `HeureLimite` varchar(15) NOT NULL DEFAULT '', `SessionLimite` varchar(15) NOT NULL DEFAULT '', PRIMARY KEY (`session_id`), KEY `Where` (`Where`), KEY `HeureLimite` (`HeureLimite`) ) ENGINE=MEMORY DEFAULT CHARSET=latin1 COMMENT='Sessions @ Pluton'; -- -- Contenu de la table `sessions` -- INSERT INTO `sessions` (`session_id`, `Where`, `IP`, `user_id`, `perso_id`, `Skin`, `Skin_accent`, `online`, `HeureLimite`, `SessionLimite`) VALUES ('11o5p5fpacnoutbc2pgvh03ih1', 21, '0a000004', -1, NULL, 'zed', '', 1, '1279392190', '1279399090'), ('74ue7g6k02e6k7bfirqudmhgi7', 21, '0a000004', -1, NULL, 'zed', '', 1, '1279392191', '1279399091'), ('tu8otohbqlhknmt0atiuk850r6', 21, '0a000004', 2600, 4960, 'zed', '', 1, '1279392446', '1279399346'), ('395f7o7pme0dkt32df8h8reo66', 21, '0a000004', -1, NULL, 'zed', '', 1, '1279392191', '1279399091'), ('klss5iti1bf6vja6a6ibd48j02', 21, '0a000004', -1, NULL, 'zed', '', 1, '1279392193', '1279399093'), ('ai71qqkde5hbbjc14sh4dj87o1', 21, '0a000004', -1, NULL, 'zed', '', 1, '1279392194', '1279399094'); -- -------------------------------------------------------- -- -- Structure de la table `ships` -- CREATE TABLE IF NOT EXISTS `ships` ( `ship_id` mediumint(5) unsigned zerofill NOT NULL AUTO_INCREMENT, `ship_name` varchar(63) NOT NULL, `location_global` char(9) DEFAULT NULL, `location_local` varchar(255) NOT NULL, `api_key` varchar(36) NOT NULL, `ship_description` text NOT NULL, PRIMARY KEY (`ship_id`), UNIQUE KEY `ship_name` (`ship_name`), KEY `location` (`location_global`), KEY `api_key` (`api_key`), FULLTEXT KEY `ship_name_2` (`ship_name`,`ship_description`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ; -- -- Contenu de la table `ships` -- -- -------------------------------------------------------- -- -- Doublure de structure pour la vue `ships_sessions` -- CREATE TABLE IF NOT EXISTS `ships_sessions` ( `ship_id` varchar(5) ,`session_id` varchar(165) ,`perso_id` longtext ,`session_updated` bigint(10) ); -- -------------------------------------------------------- -- -- Structure de la table `users` -- CREATE TABLE IF NOT EXISTS `users` ( `user_id` smallint(4) NOT NULL DEFAULT '0', `username` varchar(11) NOT NULL DEFAULT '', `user_password` varchar(32) NOT NULL DEFAULT '', `user_active` tinyint(1) NOT NULL DEFAULT '0', `user_actkey` varchar(11) DEFAULT NULL, `user_email` varchar(63) NOT NULL DEFAULT '', `user_regdate` int(10) NOT NULL DEFAULT '0', PRIMARY KEY (`user_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- -- Contenu de la table `users` -- -- Adds a default account with demo/demo as login/password -- INSERT INTO `users` (`user_id`, `username`, `user_password`, `user_active`, `user_actkey`, `user_email`, `user_regdate`) VALUES (2600, 'demo', 'fe01ce2a7fbac8fafaed7c982a04e229', 1, NULL, 'lorem@ipsum.dol', 1279161321); -- -------------------------------------------------------- -- -- Structure de la table `users_invites` -- CREATE TABLE IF NOT EXISTS `users_invites` ( `invite_code` char(6) NOT NULL, `invite_date` int(10) NOT NULL, `invite_from_user_id` smallint(5) NOT NULL, `invite_from_perso_id` smallint(5) NOT NULL, `invite_to_user_id` smallint(5) DEFAULT NULL, PRIMARY KEY (`invite_code`), KEY `invite_to_user_id` (`invite_to_user_id`), KEY `invite_from_user_id` (`invite_from_user_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- -- Contenu de la table `users_invites` -- -- -------------------------------------------------------- -- -- Structure de la table `users_openid` -- CREATE TABLE IF NOT EXISTS `users_openid` ( `openid_id` mediumint(9) NOT NULL AUTO_INCREMENT, `openid_url` varchar(255) NOT NULL, `user_id` mediumint(9) NOT NULL, PRIMARY KEY (`openid_id`), UNIQUE KEY `openid_url` (`openid_url`), KEY `user_id` (`user_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ; -- -- Contenu de la table `users_openid` -- -- -------------------------------------------------------- -- -- Structure de la vue `content` -- DROP TABLE IF EXISTS `content`; CREATE VIEW `content` AS select `cl`.`content_id` AS `content_id`,`cl`.`location_global` AS `location_global`,`cl`.`location_local` AS `location_local`,`cl`.`location_k` AS `location_k`,`cf`.`content_path` AS `content_path`,`cf`.`user_id` AS `user_id`,`cf`.`perso_id` AS `perso_id`,`cf`.`content_title` AS `content_title` from (`content_locations` `cl` join `content_files` `cf`) where (`cf`.`content_id` = `cl`.`content_id`); -- -------------------------------------------------------- -- -- Structure de la vue `geo_locations` -- DROP TABLE IF EXISTS `geo_locations`; CREATE VIEW `geo_locations` AS select concat(_utf8'B',convert(`geo_bodies`.`body_code` using utf8)) AS `location_code`,`geo_bodies`.`body_name` AS `location_name` from `geo_bodies` union select concat(_utf8'B',convert(`geo_places`.`body_code` using utf8),convert(`geo_places`.`place_code` using utf8)) AS `code`,`geo_places`.`place_name` AS `NAME` from `geo_places` union select concat(_utf8'S',convert(`ships`.`ship_id` using utf8)) AS `location_code`,`ships`.`ship_name` AS `location_name` from `ships`; -- -------------------------------------------------------- -- -- Structure de la vue `ships_sessions` -- DROP TABLE IF EXISTS `ships_sessions`; CREATE VIEW `ships_sessions` AS select substr(`registry`.`registry_key`,19,5) AS `ship_id`,substr(`registry`.`registry_key`,25) AS `session_id`,`registry`.`registry_value` AS `perso_id`,unix_timestamp(`registry`.`registry_updated`) AS `session_updated` from `registry` where (left(`registry`.`registry_key`,17) = _utf8'api.ship.session.'); +-- -------------------------------------------------------- + +-- +-- Structure de la vue `geo_coordinates` +-- +CREATE VIEW geo_coordinates AS (SELECT body_name as object_name, body_status as object_type, body_location as object_location FROM geo_bodies) +UNION +(SELECT ship_name as object_name, 'ship' as object_type, location_global as object_location FROM ships WHERE LEFT(location_global, 3) = 'xyz') ORDER BY object_name \ No newline at end of file diff --git a/dev/tests/GeoGalaxyTest.php b/dev/tests/GeoGalaxyTest.php new file mode 100644 --- /dev/null +++ b/dev/tests/GeoGalaxyTest.php @@ -0,0 +1,3 @@ +<?php + +?> \ No newline at end of file diff --git a/includes/geo/galaxy.php b/includes/geo/galaxy.php --- a/includes/geo/galaxy.php +++ b/includes/geo/galaxy.php @@ -1,85 +1,119 @@ <?php /** * Geo galaxy class. * * Zed. The immensity of stars. The HyperShip. The people. * * (c) 2010, Dereckson, some rights reserved. * Released under BSD license. * * A 3D grid of objects * - * 0.1 2010-02-08 14:02 DcK - * + * 0.1 2010-02-08 14:02 Initial version [DcK] + * 0.2 2010-07-25 9:20 Spherical conversion, get objects + * * @package Zed * @subpackage Geo * @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org> * @copyright 2010 Sébastien Santoro aka Dereckson * @license http://www.opensource.org/licenses/bsd-license.php BSD * @version 0.1 * @link http://scherzo.dereckson.be/doc/zed * @link http://zed.dereckson.be/ * @filesource */ /** * Geo galaxy class * * This class provides methods to convert coordinate polars. * - * @todo add a cartesian_to_polar method - * @todo add a static method to get a grid of all the galaxy objects, with their x y z representation ; that will be useful to add in API, for a javascript galaxy viewer. - * * @todo create a unit testing file dev/tests/GeoGalaxyTest.php * @todo add unit testing for the normalize_angle method in dev/tests/GeoGalaxyTest.php - * @todo add unit testing for the polar_to_cartesian method */ class GeoGalaxy { + /* + * ----------------------------------------------------------------------- * + * Objects fetchers + * ----------------------------------------------------------------------- * + */ + + /** + * Gets all the coordinates of the objects in the galaxy. + * + * @return array An array of array. Each item is [string object_name, string object_type, GeoPoint3D coordinates] + */ + static function get_coordinates () { + global $db; + $sql = "SELECT * FROM geo_coordinates"; + if (!$result = $db->sql_query($sql)) message_die(SQL_ERROR, "Can't query geo_coordinates view.", '', __LINE__, __FILE__, $sql); + + $objects = array(); + while ($row = $db->sql_fetchrow($result)) { + //Demios ship xyz: [-50, 30, 40] + //Kaos asteroid xyz: [150, -129, 10] + $objects[] = array($row[0], $row[1], GeoPoint3D::fromString($row[2])); + } + return $objects; + } /* * ----------------------------------------------------------------------- * * Helper methods - math * ----------------------------------------------------------------------- * */ /** * Normalizes an angle, so 0 =< angle < 2 PI * * @param float $angle angle in radians (use deg2rad() if you've degrees) * @return an angle in the 0 =< angle < 2 PI interval */ static function normalize_angle ($angle) { while ($angle < 0) { $angle += 2 * M_PI; } while ($angle >= 2 * M_PI) { $angle -= 2 * M_PI; } return $angle; } - - /* - * Converts polar coordinates in cartesian x y coordinates - * @param float $angle angle in radians (use deg2rad() if you've degrees) - * @param float $height height - * @return array an array of 2 float items: x, y + + /** + * Converts (x, y, z) cartesian to (ρ, φ, θ) spherical coordinates + * + * The algo used is from http://fr.wikipedia.org/wiki/Coordonn%C3%A9es_sph%C3%A9riques#Relation_avec_les_autres_syst.C3.A8mes_de_coordonn.C3.A9es_usuels + * + * @param int $x the x coordinate + * @param int $y the y coordinate + * @param int $z the z coordinate + * @return array an array of 3 floats number, representing the (ρ, φ, θ) spherical coordinates */ - static function polar_to_cartesian ($angle, $height) { - //A story of numbers - if ($height < 0) { - //Adds 180° and gets absolute value - $height *= -1; - $angle + M_PI; - } - $x = abs(sin($angle)) . $height; - $y = abs(cos($angle)) . $height; + static function cartesian_to_spherical ($x, $y, $z) { + $rho = sqrt($x * $x + $y * $y + $z * $z); //ρ = sqrt(x² + y² + z²) + $theta= acos($z / $rho); //φ = acos z/φ + $phi = acos($x / sqrt($x * $x + $y * $y)); //θ = acos x / sqrt(x² + y²) + if (y < 0) $phi = 2 * M_PI - $phi; //∀ y < 0 θ = 2π - θ - //And now, the sign - - - //Returns our coordinates - return array($x, $y); + return array(round($rho, 2), round(rad2deg($theta), 2), round(rad2deg($phi), 2)); } + /** + * Converts (x, y, z) cartesian to (ρ, φ, θ) spherical coordinates + * + * The algo used is from http://www.phy225.dept.shef.ac.uk/mediawiki/index.php/Cartesian_to_polar_conversion + * + * @param int $x the x coordinate + * @param int $y the y coordinate + * @param int $z the z coordinate + * @return array an array of 3 floats number, representing the (ρ, φ, θ) spherical coordinates + */ + static function cartesian_to_spherical2 ($x, $y, $z) { + $rho = sqrt($x * $x + $y * $y + $z * $z); //ρ = sqrt(x² + y² + z²) + $theta= atan2($y, $x); //φ = atan2 $y $x + $phi = acos($z / $rho); //θ = acos z/φ + + return array(round($rho, 2), round(rad2deg($theta), 2), round(rad2deg($phi), 2)); + } } \ No newline at end of file diff --git a/includes/geo/point3D.php b/includes/geo/point3D.php --- a/includes/geo/point3D.php +++ b/includes/geo/point3D.php @@ -1,118 +1,208 @@ <?php /** * Geo point 3D class. * * Zed. The immensity of stars. The HyperShip. The people. * * (c) 2010, Dereckson, some rights reserved. * Released under BSD license. * * 0.1 2010-02-23 14:14 DcK * * @package Zed * @subpackage Geo * @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org> * @copyright 2010 Sébastien Santoro aka Dereckson * @license http://www.opensource.org/licenses/bsd-license.php BSD * @version 0.1 * @link http://scherzo.dereckson.be/doc/zed * @link http://zed.dereckson.be/ * @filesource */ /** * Geo point 3D class. * * This class represents a x, y, z point. * * It implements IteratorAggregate to allow the foreach instruction * on a GeoPoint3D object: * * <code> * $point = new GeoPoint3D(17, 24, -6); * foreach ($point as $axis => $coordinate) { * echo "\n\t$axis = $coordinate"; * } * //This will output: * // x = 17 * // y = 24 * // z = -6 * </code> * * The point 3D representation is xyz: [x, y, z] ; you can print it as a string * and get this format: * * <code> * $point = new GeoPoint3D(17, 24, -6); * echo (string)$point; //will output xyz: [17, 24, -6] * </code> * */ class GeoPoint3D implements IteratorAggregate { // // x, y, z public properties // /** * the x coordinate * * @var integer */ public $x; /** * the y coordinate * * @var integer */ public $y; /** * the z coordinate * * @var integer */ public $z; // // constructor / toString // /** * Initializes a new instance of GeoPoint3D class * * @param int $x the x coordinate * @param int $y the y coordinate * @param int $z the z coordinate */ function __construct ($x, $y, $z) { - $this->x = $x; - $this->y = $y; - $this->z = $z; + $this->x = (int)$x; + $this->y = (int)$y; + $this->z = (int)$z; } /** - * Returns a xyz: [x, y, z] string representation of the point coordinates + * Parses a xyz: [x, y, z] string expression ang gets a GeoPoint3D object + * + * @param string $expression the expression to parse + * @return GeoPoint3D If the specified expression could be parsed, a GeoPoint3D instance ; otherwise, null. + */ + static function fromString ($expression) { + if (string_starts_with($expression, 'xyz:', false)) { + $pos1 = strpos($expression, '[', 4) + 1; + $pos2 = strpos($expression, ']', $pos1); + if ($pos1 > -1 && $pos2 > -1) { + $expression = substr($expression, $pos1, $pos2 - $pos1); + $xyz = explode(',', $expression, 3); + return new GeoPoint3D($xyz[0], $xyz[1], $xyz[2]); + } + } + return null; + } + + /** + * Returns a xyz: [x, y, z] string representation of the point coordinates. * * @return string a xyz: [x, y, z] string representation of the coordinates */ function __toString () { return sprintf("xyz: [%d, %d, %d]", $this->x, $this->y, $this->z); } + /** + * Determines if this point is equal to the specified point. + * + * @param GeoPoint3D $point The point to compare + * @return bool true if the two points are equal ; otherwise, false. + */ + function equals ($point) { + return ($this->x == $point->x) && ($this->y == $point->y) && ($this->z == $point->z); + } + + // + // Math + // + + /** + * Gets the (ρ, φ, θ) spherical coordinates from the current x, y, z cartesian point + * + * The algo used is from http://fr.wikipedia.org/wiki/Coordonn%C3%A9es_sph%C3%A9riques#Relation_avec_les_autres_syst.C3.A8mes_de_coordonn.C3.A9es_usuels + * + * @return array an array of 3 floats number, representing the (ρ, φ, θ) spherical coordinates + */ + function to_spherical () { + return GeoGalaxy::cartesian_to_spherical($this->x, $this->y, $this->z); + } + + /** + * Gets the (ρ, φ, θ) spherical coordinates from the current x, y, z cartesian point + * + * The algo used is from http://www.phy225.dept.shef.ac.uk/mediawiki/index.php/Cartesian_to_polar_conversion + * + * @return array an array of 3 floats number, representing the (ρ, φ, θ) spherical coordinates + */ + function to_spherical2 () { + return GeoGalaxy::cartesian_to_spherical2($this->x, $this->y, $this->z); + } + + /** + * Translates the center and rescales. + * + * This method allow to help to represent coordinate in a new system + * + * This method is used to represent Zed objects in dojo with the following + * parameters: + * <code> + * $pointKaos = GeoPoint3D(800, 42, 220); + * $pointKaos->translate(500, 300, 200, 2); + * </code> + * + * @param int $dx the difference between the old x and new x (ie the value of x = 0 in the new system) + * @param int $dy the difference between the old y and new y (ie the value of y = 0 in the new system) + * @param int $dz the difference between the old y and new z (ie the value of z = 0 in the new system) + * @scale float $scale if specified, divides each coordinate by this value (optional) + */ + function translate ($dx, $dy, $dz, $scale = 1) { + if ($scale == 1) { + $this->x += $dx; + $this->y += $dy; + $this->z += $dz; + } elseif ($scale == 0) { + $this->x = 0; + $this->y = 0; + $this->z = 0; + } else { + $this->x = $this->x * $scale + $dx; + $this->y = $this->y * $scale + $dy; + $this->z = $this->z * $scale + $dz; + } + } + // // Implementing IteratorAggregate // /** * Retrieves class iterator. It traverses x, y and z. * * @return Traversable the iterator */ function getIterator () { return new ArrayIterator($this); } + + } ?> \ No newline at end of file diff --git a/includes/story/hook_spatioport.php b/includes/story/hook_spatioport.php --- a/includes/story/hook_spatioport.php +++ b/includes/story/hook_spatioport.php @@ -1,130 +1,132 @@ <?php /** * Story hook class :: spatioport * * Zed. The immensity of stars. The HyperShip. The people. * * (c) 2010, Dereckson, some rights reserved. * Released under BSD license. * * This class allows to hook spatioport content to a story. * * It lists the ship inside the spatioport and in the surrounding space. * * @package Zed * @subpackage Story * @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org> * @copyright 2010 Sébastien Santoro aka Dereckson * @license http://www.opensource.org/licenses/bsd-license.php BSD * @version 0.1 * @link http://scherzo.dereckson.be/doc/zed * @link http://zed.dereckson.be/ * @filesource * * @todo Adds spatioport services, like ship repair & co * @todo Adds a map of the sky, with ship around * @todo Consider to use the Port class instead and to move get_ships methods there. */ require_once('includes/objects/ship.php'); require_once('includes/geo/location.php'); +$class = 'SpatioportStoryHook'; + /** * Spatioport story hook class */ class SpatioportStoryHook extends StoryHook { /** * The spatioport location * * @var GeoLocation */ public $location; /** * The spatioport global location * * @var string */ public $location_global; /** * The spatioport local location * * @var string */ public $location_local; /** * Updates and gets the current section choices * * @param Array $links The story links */ function get_choices_links (&$links) { //$links[] = array('Examiner les vaisseaux', get_url('port','ships')); } /** * Initializes instance location properties */ function initialize () { $this->location_global = $this->perso->location_global; $this->location_local = $this->section->location_local; $this->location = new GeoLocation($this->location_global, $this->location_local); } /** * Appends ship list to the story description */ function add_content () { $ships = $this->get_ships(); if (count($ships)) { echo "\n<h2>Ships</h2>"; echo "<p>Amongst the ships are at the spatioport:</p>"; echo "\n<ul>"; foreach ($ships as $ship) { $url = get_url('ship', $ship); echo "\n\t<li><a href=\"$url\">$ship->name</a></li>"; } echo "\n</ul>"; } $ships = $this->get_ships_in_space(); if (count($ships)) { echo "\n<h2>In orbit</h2>"; $place = (string)$this->location->body; echo "<p>Those ships are in space around $place:</p>"; echo "\n<ul>"; foreach ($ships as $ship) { $url = get_url('ship', $ship); echo "\n\t<li><a href=\"$url\">$ship->name</a></li>"; } echo "\n</ul>"; } } /** * Get ships in the spatioports * * @param string $location_global global location * @param string $location_local local location * @return array The ships in the spatioport */ private function get_ships () { return Ship::get_ships_at($this->location_global, $this->location_local); } /** * Get ships in the space surrounding the spatioport * * @param string $location_global global location * @param string $location_local local location * @return array The ships in the space around the spatioport */ private function get_ships_in_space () { return Ship::get_ships_at($this->location_global, null); } } -?> \ No newline at end of file +?> diff --git a/includes/story/story.php b/includes/story/story.php --- a/includes/story/story.php +++ b/includes/story/story.php @@ -1,133 +1,135 @@ <?php /** * Story class * * Zed. The immensity of stars. The HyperShip. The people. * * (c) 2010, Dereckson, some rights reserved. * Released under BSD license. * * @package Zed * @subpackage Story * @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org> * @copyright 2010 Sébastien Santoro aka Dereckson * @license http://www.opensource.org/licenses/bsd-license.php BSD * @version 0.1 * @link http://scherzo.dereckson.be/doc/zed * @link http://zed.dereckson.be/ * @filesource */ +require_once('section.php'); + /** * Story class * * This class is a PHP mapping from the Story XML format. * * This class also provides a collection of helper methods to explore the story. */ class Story { /** * The file path * * @var string */ public $file; /** * The story title * * @var string */ public $title; /** * An array of StorySection elements * * @var Array */ public $sections = array(); /** * The SimpleXML parser * * @var SimpleXMLElement */ private $xml; /** * The index of start section in sections array * * @var string */ private $startSection = null; /** * An array of StorySection elements, indexed by location * * @var Array */ private $sectionsByLocation = array(); function __construct ($file) { //Opens .xml if (!file_exists($file)) { message_die(GENERAL_ERROR, "$file not found.", "Story loading error"); } $this->file = $file; $this->parse(); } /** * Gets start section * * @return StorySection the section where the story starts, or null if not defined */ function get_start_section () { return ($this->startSection != null) ? $this->sections[$this->startSection] : null; } /** * Gets section from local location * * @return StorySection the default section at this location, or null if not defined */ function get_section_from_location ($location) { return array_key_exists($location, $this->sectionsByLocation) ? $this->sectionsByLocation[$location] : null; } /** * Parses XML file */ function parse () { //Parses it $this->xml = simplexml_load_file($this->file); $this->title = (string)$this->xml->title; foreach ($this->xml->section as $section) { //Gets section $section = StorySection::from_xml($section, $this); //Have we a start section? if ($section->start) { //Ensures we've only one start section if ($this->startSection != null) { message_die(GENERAL_ERROR, "Two sections have start=\"true\": $section->id and $this->startSection.", "Story error"); } $this->startSection = $section->id; } //By location if ($section->location_local) { $this->sectionsByLocation[$section->location_local] = $section; } //Adds to sections array $this->sections[$section->id] = $section; } } } -?> \ No newline at end of file +?>