Merged changes from branches/supertux-milestone2-grumbel/ to trunk/supertux/
[supertux.git] / src / object / path.cpp
1 //  SuperTux Path
2 //  Copyright (C) 2005 Philipp <balinor@pnxs.de>
3 //  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
4 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
5 //
6 //  This program is free software: you can redistribute it and/or modify
7 //  it under the terms of the GNU General Public License as published by
8 //  the Free Software Foundation, either version 3 of the License, or
9 //  (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19 #include "object/path.hpp"
20
21 #include <sstream>
22 #include <stdexcept>
23
24 #include "lisp/list_iterator.hpp"
25 #include "util/log.hpp"
26
27 Path::Path() :
28   nodes(),
29   mode()
30 {
31 }
32
33 Path::~Path()
34 {
35 }
36
37 void
38 Path::read(const Reader& reader)
39 {
40   lisp::ListIterator iter(&reader);
41
42   mode = CIRCULAR;
43   while(iter.next()) {
44     if(iter.item() == "mode") {
45       std::string mode_string;
46       if(!iter.value()->get(mode_string))
47         throw std::runtime_error("Pathmode not a string");
48
49       if(mode_string == "oneshot")
50         mode = ONE_SHOT;
51       else if(mode_string == "pingpong")
52         mode = PING_PONG;
53       else if(mode_string == "circular")
54         mode = CIRCULAR;
55       else {
56         std::ostringstream msg;
57         msg << "Unknown pathmode '" << mode_string << "' found";
58         throw std::runtime_error(msg.str());
59       }
60       continue;
61     }
62
63     if(iter.item() != "node") {
64       log_warning << "unknown token '" << iter.item() << "' in Path nodes list. Ignored." << std::endl;
65       continue;
66     }
67     const lisp::Lisp* node_lisp = iter.lisp();
68
69     // each new node will inherit all values from the last one
70     Node node;
71     node.time = 1;
72     if( (!node_lisp->get("x", node.position.x) ||
73          !node_lisp->get("y", node.position.y)))
74       throw std::runtime_error("Path node without x and y coordinate specified");
75     node_lisp->get("time", node.time);
76
77     if(node.time <= 0)
78       throw std::runtime_error("Path node with non-positive time");
79
80     nodes.push_back(node);
81   }
82
83   if (nodes.empty())
84     throw std::runtime_error("Path with zero nodes");
85 }
86
87 Vector
88 Path::get_base() const
89 {
90   if(nodes.empty())
91     return Vector(0, 0);
92
93   return nodes[0].position;
94 }
95
96 int
97 Path::get_nearest_node_no(Vector reference_point) const
98 {
99   int nearest_node_id = -1;
100   float nearest_node_dist = 0;
101   int id = 0;
102   for (std::vector<Node>::const_iterator i = nodes.begin(); i != nodes.end(); i++, id++) {
103     float dist = (i->position - reference_point).norm();
104     if ((nearest_node_id == -1) || (dist < nearest_node_dist)) {
105       nearest_node_id = id;
106       nearest_node_dist = dist;
107     }
108   }
109   return nearest_node_id;
110 }
111
112 int
113 Path::get_farthest_node_no(Vector reference_point) const
114 {
115   int farthest_node_id = -1;
116   float farthest_node_dist = 0;
117   int id = 0;
118   for (std::vector<Node>::const_iterator i = nodes.begin(); i != nodes.end(); i++, id++) {
119     float dist = (i->position - reference_point).norm();
120     if ((farthest_node_id == -1) || (dist > farthest_node_dist)) {
121       farthest_node_id = id;
122       farthest_node_dist = dist;
123     }
124   }
125   return farthest_node_id;
126 }
127
128 /* EOF */