* Use overloading in Lisp and Writer
[supertux.git] / src / object / path.cpp
1 //  $Id$
2 //
3 //  SuperTux Path
4 //  Copyright (C) 2005 Philipp <balinor@pnxs.de>
5 //  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
6 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
7 //
8 //  This program is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU General Public License
10 //  as published by the Free Software Foundation; either version 2
11 //  of the License, or (at your option) any later version.
12 //
13 //  This program 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
16 //  GNU General Public License for more details.
17 //
18 //  You should have received a copy of the GNU General Public License
19 //  along with this program; if not, write to the Free Software
20 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 //  02111-1307, USA.
22 #include <config.h>
23
24 #include "path.hpp"
25
26 #include "lisp/writer.hpp"
27 #include "lisp/lisp.hpp"
28 #include "lisp/list_iterator.hpp"
29 #include "object_factory.hpp"
30 #include "log.hpp"
31
32 #include <assert.h>
33 #include <iostream>
34 #include <stdexcept>
35 #include <sstream>
36
37 Path::Path()
38 {
39 }
40
41 Path::~Path()
42 {
43 }
44
45 void
46 Path::read(const lisp::Lisp& reader)
47 {
48   lisp::ListIterator iter(&reader);
49
50   mode = CIRCULAR;
51   while(iter.next()) {
52     if(iter.item() == "mode") {
53       std::string mode_string;
54       if(!iter.value()->get(mode_string))
55         throw std::runtime_error("Pathmode not a string");
56
57       if(mode_string == "oneshot")
58         mode = ONE_SHOT;
59       else if(mode_string == "pingpong")
60         mode = PING_PONG;
61       else if(mode_string == "circular")
62         mode = CIRCULAR;
63       else {
64         std::ostringstream msg;
65         msg << "Unknown pathmode '" << mode_string << "' found";
66         throw std::runtime_error(msg.str());
67       }
68       continue;
69     }
70
71     if(iter.item() != "node") {
72       log_warning << "unknown token '" << iter.item() << "' in Path nodes list. Ignored." << std::endl;
73       continue;
74     }
75     const lisp::Lisp* node_lisp = iter.lisp();
76
77     // each new node will inherit all values from the last one
78     Node node;
79     node.time = 1;
80     if( (!node_lisp->get("x", node.position.x) ||
81           !node_lisp->get("y", node.position.y)))
82       throw std::runtime_error("Path node without x and y coordinate specified");
83     node_lisp->get("time", node.time);
84
85     if(node.time <= 0)
86       throw std::runtime_error("Path node with non-positive time");
87
88     nodes.push_back(node);
89   }
90
91   if (nodes.empty())
92     throw std::runtime_error("Path with zero nodes");
93 }
94
95 void
96 Path::write(lisp::Writer& writer)
97 {
98   writer.start_list("path");
99
100   switch(mode) {
101     case ONE_SHOT:
102       writer.write("mode", "oneshot");
103       break;
104     case PING_PONG:
105       writer.write("mode", "pingpong");
106       break;
107     case CIRCULAR:
108       writer.write("mode", "circular");
109       break;
110     default:
111       log_warning << "Don't know how to write mode " << (int) mode << " ?!?" << std::endl;
112       break;
113   }
114
115   for (size_t i=0; i < nodes.size(); i++) {
116     const Node& node = nodes[i];
117
118     writer.start_list("node");
119     writer.write("x", node.position.x);
120     writer.write("y", node.position.y);
121     writer.write("time", node.time);
122
123     writer.end_list("node");
124   }
125
126   writer.end_list("path");
127 }
128
129 Vector
130 Path::get_base() const
131 {
132   if(nodes.empty())
133     return Vector(0, 0);
134
135   return nodes[0].position;
136 }
137
138 int
139 Path::get_nearest_node_no(Vector reference_point) const
140 {
141   int nearest_node_id = -1;
142   float nearest_node_dist = 0;
143   int id = 0;
144   for (std::vector<Node>::const_iterator i = nodes.begin(); i != nodes.end(); i++, id++) {
145     float dist = (i->position - reference_point).norm();
146     if ((nearest_node_id == -1) || (dist < nearest_node_dist)) {
147       nearest_node_id = id;
148       nearest_node_dist = dist;
149     }
150   }
151   return nearest_node_id;
152 }
153
154 int
155 Path::get_farthest_node_no(Vector reference_point) const
156 {
157   int farthest_node_id = -1;
158   float farthest_node_dist = 0;
159   int id = 0;
160   for (std::vector<Node>::const_iterator i = nodes.begin(); i != nodes.end(); i++, id++) {
161     float dist = (i->position - reference_point).norm();
162     if ((farthest_node_id == -1) || (dist > farthest_node_dist)) {
163       farthest_node_id = id;
164       farthest_node_dist = dist;
165     }
166   }
167   return farthest_node_id;
168 }
169