source: Revenant/geoworld/src/chemelem.cpp@ 7ef8ec4

port/mars-tycoon
Last change on this file since 7ef8ec4 was 80a6a52, checked in by Jonathan Neufeld <support@…>, 3 years ago

Get to a compile state for terrain procedural generation

  • Property mode set to 100644
File size: 6.8 KB
Line 
1#include "chemelem.h"
2
3#include <string.h>
4
5namespace geoworld
6{
7 PeriodicTable periodicity;
8
9 PeriodicTable::PeriodicTable ()
10 {
11#define ASSIGN_CHEM(x) _name2num[#x] = x
12 ASSIGN_CHEM(H);
13 ASSIGN_CHEM(He);
14 ASSIGN_CHEM(Li);
15 ASSIGN_CHEM(Be);
16 ASSIGN_CHEM(B);
17 ASSIGN_CHEM(C);
18 ASSIGN_CHEM(N);
19 ASSIGN_CHEM(O);
20 ASSIGN_CHEM(F);
21 ASSIGN_CHEM(Ne);
22 ASSIGN_CHEM(Na);
23 ASSIGN_CHEM(Mg);
24 ASSIGN_CHEM(Al);
25 ASSIGN_CHEM(Si);
26 ASSIGN_CHEM(P);
27 ASSIGN_CHEM(S);
28 ASSIGN_CHEM(Cl);
29 ASSIGN_CHEM(Ar);
30 ASSIGN_CHEM(K);
31 ASSIGN_CHEM(Ca);
32 ASSIGN_CHEM(Sc);
33 ASSIGN_CHEM(Ti);
34 ASSIGN_CHEM(V);
35 ASSIGN_CHEM(Cr);
36 ASSIGN_CHEM(Mn);
37 ASSIGN_CHEM(Fe);
38 ASSIGN_CHEM(Co);
39 ASSIGN_CHEM(Ni);
40 ASSIGN_CHEM(Cu);
41 ASSIGN_CHEM(Zn);
42 ASSIGN_CHEM(Ga);
43 ASSIGN_CHEM(Ge);
44 ASSIGN_CHEM(As);
45 ASSIGN_CHEM(Se);
46 ASSIGN_CHEM(Br);
47 ASSIGN_CHEM(Kr);
48 ASSIGN_CHEM(Rb);
49 ASSIGN_CHEM(Sr);
50 ASSIGN_CHEM(Y);
51 ASSIGN_CHEM(Zr);
52 ASSIGN_CHEM(Nb);
53 ASSIGN_CHEM(Mo);
54 ASSIGN_CHEM(Tc);
55 ASSIGN_CHEM(Ru);
56 ASSIGN_CHEM(Rh);
57 ASSIGN_CHEM(Pd);
58 ASSIGN_CHEM(Ag);
59 ASSIGN_CHEM(Cd);
60 ASSIGN_CHEM(In);
61 ASSIGN_CHEM(Sn);
62 ASSIGN_CHEM(Sb);
63 ASSIGN_CHEM(Te);
64 ASSIGN_CHEM(I);
65 ASSIGN_CHEM(Xe);
66 ASSIGN_CHEM(Cs);
67 ASSIGN_CHEM(Ba);
68 ASSIGN_CHEM(La);
69 ASSIGN_CHEM(Ce);
70 ASSIGN_CHEM(Pr);
71 ASSIGN_CHEM(Nd);
72 ASSIGN_CHEM(Pm);
73 ASSIGN_CHEM(Sm);
74 ASSIGN_CHEM(Eu);
75 ASSIGN_CHEM(Gd);
76 ASSIGN_CHEM(Tb);
77 ASSIGN_CHEM(Dy);
78 ASSIGN_CHEM(Ho);
79 ASSIGN_CHEM(Er);
80 ASSIGN_CHEM(Tm);
81 ASSIGN_CHEM(Yb);
82 ASSIGN_CHEM(Lu);
83 ASSIGN_CHEM(Hf);
84 ASSIGN_CHEM(Ta);
85 ASSIGN_CHEM(W);
86 ASSIGN_CHEM(Re);
87 ASSIGN_CHEM(Os);
88 ASSIGN_CHEM(Ir);
89 ASSIGN_CHEM(Pt);
90 ASSIGN_CHEM(Au);
91 ASSIGN_CHEM(Hg);
92 ASSIGN_CHEM(Tl);
93 ASSIGN_CHEM(Pb);
94 ASSIGN_CHEM(Bi);
95 ASSIGN_CHEM(Po);
96 ASSIGN_CHEM(At);
97 ASSIGN_CHEM(Rn);
98 ASSIGN_CHEM(Fr);
99 ASSIGN_CHEM(Ra);
100 ASSIGN_CHEM(Ac);
101 ASSIGN_CHEM(Th);
102 ASSIGN_CHEM(Pa);
103 ASSIGN_CHEM(U);
104 ASSIGN_CHEM(Np);
105 ASSIGN_CHEM(Pu);
106 ASSIGN_CHEM(Am);
107 ASSIGN_CHEM(Cm);
108 ASSIGN_CHEM(Bk);
109 ASSIGN_CHEM(Cf);
110 ASSIGN_CHEM(Es);
111 ASSIGN_CHEM(Fm);
112 ASSIGN_CHEM(Md);
113 ASSIGN_CHEM(No);
114 ASSIGN_CHEM(Lr);
115 ASSIGN_CHEM(Rf);
116 ASSIGN_CHEM(Db);
117 ASSIGN_CHEM(Sg);
118 ASSIGN_CHEM(Bh);
119 ASSIGN_CHEM(Hs);
120 ASSIGN_CHEM(Mt);
121 ASSIGN_CHEM(Ds);
122 ASSIGN_CHEM(Rg);
123 ASSIGN_CHEM(Uub);
124 ASSIGN_CHEM(Uut);
125 ASSIGN_CHEM(Uuq);
126 ASSIGN_CHEM(Uup);
127 ASSIGN_CHEM(Uuh);
128 ASSIGN_CHEM(Uus);
129 ASSIGN_CHEM(Uuo);
130#undef ASSIGN_CHEM
131 }
132
133 ChemicalFormulaParser::Token::Token( const std::string & formula, const unsigned s0 )
134 : type(typeOf(formula[s0])), _s0(s0), _formula(formula), _s(s0)
135 {
136 switch (type)
137 {
138 case TNum:
139 while (++_s < formula.length() && typeOf(formula[_s]) == TNum);
140 break;
141 case TWord:
142 while (++_s < formula.length() && (formula[_s] >= 'a' && formula[_s] <= 'z'));
143 break;
144 case TSep:
145 while (++_s < formula.length() && typeOf(formula[_s]) == TSep);
146 break;
147 default:
148 ++_s;
149 break;
150 }
151 }
152
153 ChemicalFormulaParser::Token & ChemicalFormulaParser::Token::operator = ( const ChemicalFormulaParser::Token & a )
154 {
155 _s0 = a._s0;
156 _s = a._s;
157 if (_formula != a._formula)
158 throw Ex();
159
160 return *this;
161 }
162
163 ChemicalFormulaParser::TokenType ChemicalFormulaParser::Token::typeOf( const char ch )
164 {
165 if ((ch >= '0' && ch <= '9') || ch == '.')
166 return TNum;
167 else if (ch >= 'A' && ch <= 'Z')
168 return TWord;
169 else if (ch == ' ' || ch == '.')
170 return TSep;
171 else if (ch == '(')
172 return TOpen;
173 else if (ch == ')')
174 return TClose;
175 else if (ch == ',')
176 return TAlt;
177 else
178 throw Ex();
179 }
180
181 void ChemicalFormulaParser::Token::operator >> ( unsigned & num ) const
182 {
183 num = atoi (_formula.substr(_s0, _s - _s0).c_str());
184 }
185
186 void ChemicalFormulaParser::Token::operator >> ( AtomicNumber & atom ) const
187 {
188 atom = periodicity[_formula.substr(_s0, _s - _s0)];
189 }
190
191 void ChemicalFormulaParser::Token::operator >> ( float & f ) const
192 {
193 f = static_cast <float> (atof(_formula.substr(_s0, _s - _s0).c_str()));
194 }
195
196 unsigned ChemicalFormulaParser::Token::length() const
197 {
198 return _s - _s0;
199 }
200
201
202 bool ChemicalFormulaParser::lookAhead( const std::vector <ChemicalFormulaParser::Token>::const_iterator & i, const ChemicalFormulaParser::TokenType tok ) const
203 {
204 return ((i + 1) != _tokens.end() && (i + 1)->type == tok);
205 }
206
207 bool ChemicalFormulaParser::lookBehind( const std::vector <ChemicalFormulaParser::Token>::const_iterator & i, const ChemicalFormulaParser::TokenType tok ) const
208 {
209 return (i != _tokens.begin() && (i - 1)->type == tok);
210 }
211
212 void ChemicalFormulaParser::quantities (ChemicalFormulaParser::IQuantityCallback * cb)
213 {
214 float mqty = 1, gqty = 1, gdqty = 1;
215 AtomicNumber atom;
216 std::vector <Token>::const_iterator i = _tokens.begin();
217 float quantiteas[NUM_CHEM_ELEMENTS];
218
219 memset(quantiteas, 0, sizeof(quantiteas));
220 while (i != _tokens.end())
221 {
222 // Do nothing, skip, group quantifiers were processed in-advance while processing 'TOpen'
223 if (lookBehind(i, TClose) && i->type == TNum) {}
224
225 else if (i->type == TNum)
226 {
227 *i++ >> mqty;
228
229 if (i == _tokens.end())
230 throw Ex(); // Molecular quantifiers cannot terminate a formula
231
232 if (i->type == TWord)
233 {
234 unsigned aqty = 1;
235
236 *i >> atom;
237
238 // If we're at the end of the word, we expect an atomic quantifier here
239 if (lookAhead(i, TNum))
240 {
241 *++i >> aqty;
242 }
243
244 quantiteas[atom] += mqty * aqty * (gqty / gdqty);
245 } else
246 throw Ex(); // A chemical element name must immediately follow a molecular quantifier
247 } else if (i->type == TWord)
248 {
249 unsigned aqty = 1;
250
251 *i >> atom;
252
253 // If we're at the end of the word, we expect an atomic quantifier here
254 if (lookAhead(i, TNum))
255 {
256 *++i >> aqty;
257 }
258
259 quantiteas[atom] += mqty * aqty * (gqty / gdqty);
260
261 // Process a group including the suffixes after the group terminator
262 } else if (i->type == TOpen)
263 {
264 std::vector <Token>::const_iterator i2 = i;
265
266 // Scan to the end of the group
267 while (i2->type != TClose && i2 != _tokens.end())
268 {
269 // If we encounter a comma, then we increase the group quantity dividend (Q = Qm * Qa * Qg / Qd)
270 if (i->type == TAlt)
271 gdqty++;
272 i2++;
273 }
274
275 // Check for an unbalanced group (no closing brace found)
276 if (i2 == _tokens.end())
277 throw Ex(); // No closing brace found
278
279 // We hope the next token after the group terminator is a number, it becomes our group quantity
280 if (lookAhead(i2, TNum))
281 *++i2 >> gqty;
282 } else if (i->type == TClose)
283 {
284 gqty = 1;
285 gdqty = 1;
286 }
287 i++;
288 }
289
290 for (unsigned c = 0; c < NUM_CHEM_ELEMENTS; c++)
291 {
292 if (quantiteas[c] > 0)
293 cb->setChemicalQuantity(static_cast <AtomicNumber> (c), quantiteas[c]);
294 }
295 }
296 ChemicalFormulaParser::ChemicalFormulaParser (const std::string & formula) : _formula(formula)
297 {
298 unsigned c = 0;
299
300 while (c < _formula.length())
301 {
302 _tokens.push_back(Token(_formula, c));
303 c += _tokens.back().length();
304 }
305 }
306}
Note: See TracBrowser for help on using the repository browser.