src/parser.cpp

changeset 200
ca23936b455b
parent 183
97b591813c8b
child 201
5d201ee4a9c3
equal deleted inserted replaced
199:6988973515d2 200:ca23936b455b
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */ 17 */
18 18
19 #include "model.h" 19 #include "model.h"
20 #include "parser.h" 20 #include "parser.h"
21 #include "linetypes/conditionaledge.h" 21 #include "ldrawalgorithm.h"
22 #include "linetypes/edge.h"
23 #include "linetypes/errorline.h"
24 #include "linetypes/metacommand.h"
25 #include "linetypes/object.h"
26 #include "linetypes/quadrilateral.h"
27 #include "linetypes/subfilereference.h"
28 #include "linetypes/triangle.h"
29 22
30 struct BodyParseError 23 struct BodyParseError
31 { 24 {
32 QString message; 25 QString message;
33 }; 26 };
62 if (line == "0 BFC INVERTNEXT" or line == "0 BFC CERTIFY INVERTNEXT") 55 if (line == "0 BFC INVERTNEXT" or line == "0 BFC CERTIFY INVERTNEXT")
63 { 56 {
64 invertNext = true; 57 invertNext = true;
65 continue; 58 continue;
66 } 59 }
67 model.append(parseFromString(line)); 60 ModelElement element = parseLDrawLine(line);
68 if (invertNext) 61 if (invertNext)
69 { 62 {
70 model[model.size() - 1]->invert(nullptr); 63 element = inverted(element);
71 } 64 }
65 model.append(element);
72 invertNext = false; 66 invertNext = false;
73 } 67 }
74 } 68 }
75 69
76 static ldraw::Color colorFromString(const QString& colorString) 70 static ldraw::Color colorFromString(const QString& colorString)
138 } 132 }
139 } 133 }
140 return result; 134 return result;
141 } 135 }
142 136
143 static std::unique_ptr<ldraw::Object> parseType0Line( 137 static Comment parseType0Line(const QString& line)
144 const QString& line, 138 {
145 const QStringList& tokens) 139 return {line.mid(1).trimmed()};
146 { 140 }
147 Q_UNUSED(tokens) 141
148 return std::make_unique<ldraw::MetaCommand>(line.mid(1).trimmed()); 142 static Colored<SubfileReference> parseType1Line(const QStringList& tokens)
149 } 143 {
150
151 static std::unique_ptr<ldraw::SubfileReference> parseType1Line(
152 const QString& line,
153 const QStringList& tokens)
154 {
155 Q_UNUSED(line)
156 constexpr int colorPosition = 1; 144 constexpr int colorPosition = 1;
157 constexpr int positionPosition = 2; // 2..4 145 constexpr int positionPosition = 2; // 2..4
158 constexpr int transformPosition = 5; // 5..13 146 constexpr int transformPosition = 5; // 5..13
159 constexpr int namePosition = 14; 147 constexpr int namePosition = 14;
160 if (tokens.size() != 15) 148 if (tokens.size() != 15)
162 throw BodyParseError{"wrong amount of tokens in a type-1 line"}; 150 throw BodyParseError{"wrong amount of tokens in a type-1 line"};
163 } 151 }
164 const ldraw::Color color = colorFromString(tokens[colorPosition]); 152 const ldraw::Color color = colorFromString(tokens[colorPosition]);
165 const glm::mat4 transform = matrixFromStrings(tokens, transformPosition, positionPosition); 153 const glm::mat4 transform = matrixFromStrings(tokens, transformPosition, positionPosition);
166 const QString& name = tokens[namePosition]; 154 const QString& name = tokens[namePosition];
167 return std::make_unique<ldraw::SubfileReference>(transform, name, color); 155 return Colored<SubfileReference>{
168 } 156 {
169 157 .name = name,
170 template<typename T, int NumVertices> 158 .transformation = transform,
171 static std::unique_ptr<T> parsePolygon( 159 },
172 const QString& line, 160 color,
173 const QStringList& tokens) 161 };
174 { 162 }
175 Q_UNUSED(line) 163
164 template<int NumVertices>
165 static auto parsePolygon(const QStringList& tokens)
166 {
176 constexpr int colorPosition = 1; 167 constexpr int colorPosition = 1;
177 auto vertexPosition = [](int n) { return 2 + 3*n; }; 168 auto vertexPosition = [](int n) { return 2 + 3*n; };
178 if (tokens.size() != 2 + 3 * NumVertices) 169 if (tokens.size() != 2 + 3 * NumVertices)
179 { 170 {
180 throw BodyParseError{"wrong amount of tokens"}; 171 throw BodyParseError{"wrong amount of tokens"};
183 std::array<glm::vec3, NumVertices> vertices; 174 std::array<glm::vec3, NumVertices> vertices;
184 for (int i = 0; i < NumVertices; i += 1) 175 for (int i = 0; i < NumVertices; i += 1)
185 { 176 {
186 vertices[unsigned_cast(i)] = vertexFromStrings(tokens, vertexPosition(i)); 177 vertices[unsigned_cast(i)] = vertexFromStrings(tokens, vertexPosition(i));
187 } 178 }
188 return std::make_unique<T>(vertices, color); 179 return std::make_pair(vertices, color);
189 } 180 }
190 181
191 std::unique_ptr<ldraw::Object> Parser::parseFromString(QString line) 182 ModelElement parseLDrawLine(QString line)
192 { 183 {
193 line = line.trimmed(); 184 line = line.trimmed();
194 try 185 try
195 { 186 {
196 const QStringList tokens = line.split(QRegExp{R"(\s+)"}); 187 const QStringList tokens = line.split(QRegExp{R"(\s+)"});
197 if (tokens.empty() or tokens == QStringList{{""}}) 188 if (tokens.empty() or tokens == QStringList{{""}})
198 { 189 {
199 return std::make_unique<ldraw::Empty>(); 190 return Empty{};
200 } 191 }
201 bool ok_code; 192 bool ok_code;
202 const int code = tokens[0].toInt(&ok_code); 193 const int code = tokens[0].toInt(&ok_code);
203 if (not ok_code) 194 if (not ok_code)
204 { 195 {
205 throw BodyParseError{"line type was not an integer"}; 196 throw BodyParseError{"line type was not an integer"};
206 } 197 }
207 switch (code) 198 switch (code)
208 { 199 {
209 case 0: 200 case 0:
210 return parseType0Line(line, tokens); 201 return parseType0Line(line);
211 case 1: 202 case 1:
212 return parseType1Line(line, tokens); 203 return parseType1Line(tokens);
213 case 2: 204 case 2:
214 return parsePolygon<ldraw::Edge, 2>(line, tokens); 205 {
206 const auto pair = parsePolygon<2>(tokens);
207 return Colored<LineSegment>{{pair.first[0], pair.first[1]}, pair.second};
208 }
215 case 3: 209 case 3:
216 return parsePolygon<ldraw::Triangle, 3>(line, tokens); 210 {
211 const auto pair = parsePolygon<3>(tokens);
212 return Colored<Triangle>{{pair.first[0], pair.first[1], pair.first[2]}, pair.second
213 };
214 }
217 case 4: 215 case 4:
218 return parsePolygon<ldraw::Quadrilateral, 4>(line, tokens); 216 {
217 const auto pair = parsePolygon<4>(tokens);
218 const Quadrilateral quad{pair.first[0], pair.first[1], pair.first[2], pair.first[3]};
219 return Colored<Quadrilateral>{quad, pair.second};
220 }
219 case 5: 221 case 5:
220 return parsePolygon<ldraw::ConditionalEdge, 4>(line, tokens); 222 {
223 const auto pair = parsePolygon<4>(tokens);
224 const ConditionalEdge cedge{pair.first[0], pair.first[1], pair.first[2], pair.first[3]};
225 return Colored<ConditionalEdge>{cedge, pair.second};
226 }
221 default: 227 default:
222 throw BodyParseError{utility::format("bad line type '%1'", code)}; 228 throw BodyParseError{utility::format("bad line type '%1'", code)};
223 } 229 }
224 } 230 }
225 catch(const BodyParseError& error) 231 catch(const BodyParseError& error)
226 { 232 {
227 return std::make_unique<ldraw::ErrorLine>(line, error.message); 233 return ParseError{line};
228 } 234 }
229 } 235 }

mercurial