a2ce717c1e199905b299f53fab4e371ce8e8455f
[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 "log.hpp"
30
31 #include <assert.h>
32 #include <iostream>
33 #include <stdexcept>
34 #include <sstream>
35
36 Path::Path()
37 {
38 }
39
40 Path::~Path()
41 {
42 }
43
44 void
45 Path::read(const lisp::Lisp& reader)
46 {
47   lisp::ListIterator iter(&reader);
48
49   mode = CIRCULAR;
50   while(iter.next()) {
51     if(iter.item() == "mode") {
52       std::string mode_string;
53       if(!iter.value()->get(mode_string))
54         throw std::runtime_error("Pathmode not a string");
55
56       if(mode_string == "oneshot")
57         mode = ONE_SHOT;
58       else if(mode_string == "pingpong")
59         mode = PING_PONG;
60       else if(mode_string == "circular")
61         mode = CIRCULAR;
62       else {
63         std::ostringstream msg;
64         msg << "Unknown pathmode '" << mode_string << "' found";
65         throw std::runtime_error(msg.str());
66       }
67       continue;
68     }
69
70     if(iter.item() != "node") {
71       log_warning << "unknown token '" << iter.item() << "' in Path nodes list. Ignored." << std::endl;
72       continue;
73     }
74     const lisp::Lisp* node_lisp = iter.lisp();
75
76     // each new node will inherit all values from the last one
77     Node node;
78     node.time = 1;
79     if( (!node_lisp->get("x", node.position.x) ||
80           !node_lisp->get("y", node.position.y)))
81       throw std::runtime_error("Path node without x and y coordinate specified");
82     node_lisp->get("time", node.time);
83
84     if(node.time <= 0)
85       throw std::runtime_error("Path node with non-positive time");
86
87     nodes.push_back(node);
88   }
89
90   if (nodes.empty())
91     throw std::runtime_error("Path with zero nodes");
92 }
93
94 void
95 Path::write(lisp::Writer& writer)
96 {
97   writer.start_list("path");
98
99   switch(mode) {
100     case ONE_SHOT:
101       writer.write("mode", "oneshot");
102       break;
103     case PING_PONG:
104       writer.write("mode", "pingpong");
105       break;
106     case CIRCULAR:
107       writer.write("mode", "circular");
108       break;
109     default:
110       log_warning << "Don't know how to write mode " << (int) mode << " ?!?" << std::endl;
111       break;
112   }
113
114   for (size_t i=0; i < nodes.size(); i++) {
115     const Node& node = nodes[i];
116
117     writer.start_list("node");
118     writer.write("x", node.position.x);
119     writer.write("y", node.position.y);
120     writer.write("time", node.time);
121
122     writer.end_list("node");
123   }
124
125   writer.end_list("path");
126 }
127
128 Vector
129 Path::get_base() const
130 {
131   if(nodes.empty())
132     return Vector(0, 0);
133
134   return nodes[0].position;
135 }
136
137 int
138 Path::get_nearest_node_no(Vector reference_point) const
139 {
140   int nearest_node_id = -1;
141   float nearest_node_dist = 0;
142   int id = 0;
143   for (std::vector<Node>::const_iterator i = nodes.begin(); i != nodes.end(); i++, id++) {
144     float dist = (i->position - reference_point).norm();
145     if ((nearest_node_id == -1) || (dist < nearest_node_dist)) {
146       nearest_node_id = id;
147       nearest_node_dist = dist;
148     }
149   }
150   return nearest_node_id;
151 }
152
153 int
154 Path::get_farthest_node_no(Vector reference_point) const
155 {
156   int farthest_node_id = -1;
157   float farthest_node_dist = 0;
158   int id = 0;
159   for (std::vector<Node>::const_iterator i = nodes.begin(); i != nodes.end(); i++, id++) {
160     float dist = (i->position - reference_point).norm();
161     if ((farthest_node_id == -1) || (dist > farthest_node_dist)) {
162       farthest_node_id = id;
163       farthest_node_dist = dist;
164     }
165   }
166   return farthest_node_id;
167 }
168