~vbursian/research-assistant/intervers

« back to all changes in this revision

Viewing changes to RANet/Units.cpp

  • Committer: Viktor Bursian
  • Date: 2013-06-06 15:10:08 UTC
  • Revision ID: vbursian@gmail.com-20130606151008-6641eh62f0lgx8jt
Tags: version_0.3.0
version 0.3.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
////////////////////////////////////////////////////////////////////////////////
2
2
/*! @file Units.cpp   Единицы измерения физвеличин.
3
3
- Part of RANet - Research Assistant Net Library (based on ANSI C++).
4
 
- Copyright(C) 2007-2010, Viktor E. Bursian, St.Petersburg, Russia.
 
4
- Copyright(C) 2007-2011, Viktor E. Bursian, St.Petersburg, Russia.
5
5
                     Viktor.Bursian@mail.ioffe.ru
6
6
*///////////////////////////////////////////////////////////////////////////////
7
7
#include "Units.h"
 
8
#include "Symbols.h"
8
9
#include "PhysValue.h"
9
 
//#include "Trace.h"
 
10
#include "Trace.h"
 
11
#include "Log.h"
10
12
namespace RA {
11
13
//------------------------------------------------------------------------------
12
14
 
13
15
DEFINE_CLASS_TAG(sUnit)
14
16
DEFINE_CLASS_TAG(sUnits)
15
17
 
 
18
csUnits                       _Unitsless_;
 
19
 
 
20
csString          sMetricPrefix::StandardAllowance
 
21
                          ("Y..Z..E..P..T..G..M..k..0..m..u..n..p..f..a..z..y");
 
22
                         //"Y..Z..E..P..T..G..M..khd0dcm..u..n..p..f..a..z..y"
 
23
 
 
24
csString          sMetricPrefix::NoPrefixAllowed
 
25
                          ("-..-..-..-..-..-..-..-..0..-..-..-..-..-..-..-..-");
 
26
                         //"Y..Z..E..P..T..G..M..khd0dcm..u..n..p..f..a..z..y"
 
27
 
 
28
sUnit::sSystem                sUnit::System;
 
29
sUnit::pfRegisterDialog       sUnit::RegisterDialog = NULL;
16
30
psUnit                        sUnit::_1_ = new sUnit();
17
 
map<sString,psUnit >          sUnit::UnitList;
18
 
real const                    ln10 = log(real(10.0));
19
31
 
20
32
//------------------------------------------------------------ sMetricPrefix ---
21
33
 
36
48
    case  -1:  return sString("d");
37
49
    case  -2:  return sString("c");
38
50
    case  -3:  return sString("m");
39
 
    case  -6:  return sString("µ");
 
51
    case  -6:  return sString(Symbol::Micro);
40
52
    case  -9:  return sString("n");
41
53
    case -12:  return sString("p");
42
54
    case -15:  return sString("f");
54
66
  }else if( Prefix == "k"){    return   3;
55
67
  }else if( Prefix == "m"){    return  -3;
56
68
  }else if( Prefix == "M"){    return   6;
57
 
  }else if( Prefix == "µ"){    return  -6;
 
69
  }else if( Prefix ==
 
70
            Symbol::Micro){    return  -6;
58
71
  }else if( Prefix == "G"){    return   9;
59
72
  }else if( Prefix == "n"){    return  -9;
60
73
  }else if( Prefix == "T"){    return  12;
77
90
};
78
91
 
79
92
 
80
 
real  sMetricPrefix::Multiplier (sString  Prefix)
 
93
real  sMetricPrefix::Multiplier (int  Log)
81
94
{
82
 
  if( Prefix == ""){           return (real)1.0e0;
83
 
  }else if( Prefix == "k"){    return (real)1.0e3;
84
 
  }else if( Prefix == "m"){    return (real)1.0e-3;
85
 
  }else if( Prefix == "M"){    return (real)1.0e6;
86
 
  }else if( Prefix == "µ"){    return (real)1.0e-6;
87
 
  }else if( Prefix == "G"){    return (real)1.0e9;
88
 
  }else if( Prefix == "n"){    return (real)1.0e-9;
89
 
  }else if( Prefix == "T"){    return (real)1.0e12;
90
 
  }else if( Prefix == "p"){    return (real)1.0e-12;
91
 
  }else if( Prefix == "P"){    return (real)1.0e15;
92
 
  }else if( Prefix == "f"){    return (real)1.0e-15;
93
 
  }else if( Prefix == "E"){    return (real)1.0e18;
94
 
  }else if( Prefix == "a"){    return (real)1.0e-18;
95
 
  }else if( Prefix == "Z"){    return (real)1.0e21;
96
 
  }else if( Prefix == "z"){    return (real)1.0e-21;
97
 
  }else if( Prefix == "Y"){    return (real)1.0e24;
98
 
  }else if( Prefix == "y"){    return (real)1.0e-24;
99
 
  }else if( Prefix == "h"){    return (real)1.0e2;
100
 
  }else if( Prefix == "c"){    return (real)1.0e-2;
101
 
  }else if( Prefix == "da"){   return (real)1.0e1;
102
 
  }else if( Prefix == "d"){    return (real)1.0e-1;
103
 
  }else{
104
 
    return (real)1.0e0;
 
95
  switch( Log ){
 
96
    case   0:  return (real)1.0e0;
 
97
    case   3:  return (real)1.0e3;
 
98
    case  -3:  return (real)1.0e-3;
 
99
    case   6:  return (real)1.0e6;
 
100
    case  -6:  return (real)1.0e-6;
 
101
    case   9:  return (real)1.0e9;
 
102
    case  -9:  return (real)1.0e-9;
 
103
    case  12:  return (real)1.0e12;
 
104
    case -12:  return (real)1.0e-12;
 
105
    case  15:  return (real)1.0e15;
 
106
    case -15:  return (real)1.0e-15;
 
107
    case  18:  return (real)1.0e18;
 
108
    case -18:  return (real)1.0e-18;
 
109
    case  21:  return (real)1.0e21;
 
110
    case -21:  return (real)1.0e-21;
 
111
    case  24:  return (real)1.0e24;
 
112
    case -24:  return (real)1.0e-24;
 
113
    case   2:  return (real)1.0e2;
 
114
    case  -2:  return (real)1.0e-2;
 
115
    case   1:  return (real)1.0e1;
 
116
    case  -1:  return (real)1.0e-1;
 
117
    default: return power10(Log);
105
118
  };
106
119
};
107
120
 
134
147
  };
135
148
};
136
149
 
 
150
 
 
151
sString  sMetricPrefix::CombinedSymbol (int  Log)
 
152
{
 
153
  sString                     PP(Symbol(Log));
 
154
  if( PP != "?" ){
 
155
    return PP;
 
156
  }else{
 
157
    PP = "";
 
158
    while( (Log < -2) || (Log > 2) ){
 
159
      int                         L;
 
160
      L = (Log / 3) * 3;
 
161
      if( L > 24 ){
 
162
        L = 24;
 
163
      }else if( L < -24 ){
 
164
        L = -24;
 
165
      };
 
166
      PP = Symbol(L) + PP;
 
167
      Log -= L;
 
168
    };
 
169
    PP = Symbol(Log) + PP;
 
170
  };
 
171
  return PP;
 
172
};
 
173
 
 
174
//----------------------------------------------------------- sUnit::sSystem ---
 
175
 
 
176
sUnit::sSystem::~sSystem ()
 
177
{
 
178
//  StoragePlace.SetToNULL();
 
179
//  while( ! UnitList.empty() ){
 
180
//    pop
 
181
//    delete ;
 
182
//  };
 
183
};
 
184
 
 
185
 
 
186
sUnit::sSystem::sSystem ()
 
187
{
 
188
 
 
189
};
 
190
 
137
191
//-------------------------------------------------------------------- sUnit ---
138
192
 
 
193
psUnit  sUnit::Register (sString     symbol
 
194
                        ,sString     prefix_allowance
 
195
                        ,sPhysValue  definition)
 
196
{
 
197
  if( symbol.Empty() ){
 
198
    return _1_;
 
199
  }else{
 
200
    psUnit                    ExistingU = Find(symbol);
 
201
    if( ExistingU ){
 
202
      if( ExistingU->ThePrefixAllowance != prefix_allowance ){
 
203
        ExistingU->ThePrefixAllowance = prefix_allowance;
 
204
//        RANet::Log.Put(sLog::Debug,"Units"
 
205
//                      ,sString("Prefix allowance changed for '")+symbol+"'");
 
206
      };
 
207
      sString                     Old("basic");
 
208
      if( ExistingU->TheDefinition ){
 
209
        Old = ExistingU->TheDefinition->Text();
 
210
        delete ExistingU->TheDefinition;
 
211
      };
 
212
      ExistingU->TheDefinition = new sPhysValue(definition);
 
213
//      RANet::Log.Put(sLog::Debug,"Units"
 
214
//                    ,sString("Definition changed for '")+symbol
 
215
//                    +"': was "+Old+"; now "+definition.Text());
 
216
      return ExistingU;
 
217
    }else{
 
218
      psUnit              NewU( new sUnit(symbol
 
219
                                         ,prefix_allowance
 
220
                                         ,new sPhysValue(definition) ) );
 
221
      System.UnitList[NewU->Symbol()]=NewU;
 
222
//      RANet::Log.Put(sLog::Debug,"Units"
 
223
//                    ,sString("New unit registered: ")
 
224
//                    +symbol+" = "+definition.Text());
 
225
      return NewU;
 
226
    };
 
227
  };
 
228
};
 
229
 
 
230
 
 
231
psUnit  sUnit::Register (sString  symbol
 
232
                        ,sString  prefix_allowance)
 
233
{
 
234
  if( symbol.Empty() ){
 
235
    return _1_;
 
236
  }else{
 
237
    psUnit                    ExistingU = Find(symbol);
 
238
    if( ExistingU ){
 
239
      if( ExistingU->ThePrefixAllowance != prefix_allowance ){
 
240
        ExistingU->ThePrefixAllowance = prefix_allowance;
 
241
//        RANet::Log.Put(sLog::Debug,"Units"
 
242
//                      ,sString("Prefix allowance changed for '")+symbol+"'");
 
243
      };
 
244
      return ExistingU;
 
245
    }else{
 
246
      psUnit              NewU( new sUnit(symbol,prefix_allowance,NULL) );
 
247
      System.UnitList[NewU->Symbol()]=NewU;
 
248
//      RANet::Log.Put(sLog::Debug,"Units"
 
249
//                    ,sString("New unit registered: ")+symbol);
 
250
      return NewU;
 
251
    };
 
252
  };
 
253
};
 
254
 
 
255
 
 
256
psUnit  sUnit::Register (sString     symbol
 
257
                        ,sPhysValue  definition)
 
258
{
 
259
  if( symbol.Empty() ){
 
260
    return _1_;
 
261
  }else{
 
262
    psUnit                      ExistingU = Find(symbol);
 
263
    if( ExistingU ){
 
264
      sString                     Old("basic");
 
265
      if( ExistingU->TheDefinition ){
 
266
        Old = ExistingU->TheDefinition->Text();
 
267
        delete ExistingU->TheDefinition;
 
268
      };
 
269
      ExistingU->TheDefinition = new sPhysValue(definition);
 
270
//      RANet::Log.Put(sLog::Debug,"Units"
 
271
//                    ,sString("Definition changed for '")+symbol
 
272
//                    +"': was "+Old+"; now "+definition.Text());
 
273
      return ExistingU;
 
274
    }else{
 
275
      psUnit              NewU( new sUnit(symbol
 
276
                                         ,sMetricPrefix::StandardAllowance
 
277
                                         ,new sPhysValue(definition) ) );
 
278
      System.UnitList[NewU->Symbol()]=NewU;
 
279
//      RANet::Log.Put(sLog::Debug,"Units"
 
280
//                    ,sString("New unit registered: ")
 
281
//                    +symbol+" = "+definition.Text());
 
282
      return NewU;
 
283
    };
 
284
  };
 
285
};
 
286
 
 
287
 
 
288
psUnit  sUnit::Register (sString  symbol)
 
289
{
 
290
  if( symbol.Empty() ){
 
291
    return _1_;
 
292
  }else{
 
293
    psUnit                    ExistingU = Find(symbol);
 
294
    if( ExistingU ){
 
295
      return ExistingU;
 
296
    }else{
 
297
      psUnit              NewU( new sUnit(symbol
 
298
                                         ,sMetricPrefix::StandardAllowance
 
299
                                         ,NULL) );
 
300
      System.UnitList[NewU->Symbol()]=NewU;
 
301
//      RANet::Log.Put(sLog::Debug,"Units"
 
302
//                    ,sString("New unit registered: ")+symbol+" (basic)");
 
303
      return NewU;
 
304
    };
 
305
  };
 
306
};
 
307
 
 
308
 
 
309
psUnit  sUnit::Find (sString  symbol)
 
310
{
 
311
  map<sString,psUnit>::iterator    U = System.UnitList.find(symbol);
 
312
  if( U == System.UnitList.end() ){
 
313
    return NULL;
 
314
  }else{
 
315
    return U->second;
 
316
  };
 
317
};
 
318
 
 
319
 
 
320
bool  sUnit::ParseUnitWithPrefix (sString   lexem
 
321
                                 ,psUnit &  unit
 
322
                                 ,int &     prefixlg)
 
323
{
 
324
  prefixlg=0;
 
325
  unit=sUnit::Find(lexem);
 
326
  if( ! unit ){
 
327
    for( int L = 24 ; (L >= -24) && (unit == NULL) ; --L ){
 
328
      sString                     Prefix = sMetricPrefix::Symbol(L);
 
329
      int                         K=0;
 
330
      if( ! Prefix.Empty() && (Prefix != "?") ){
 
331
        if( (lexem.Substr(0,Prefix.Length()) == Prefix)
 
332
            && (lexem.Length() > Prefix.Length())        ){
 
333
//          TRACE(Prefix+"|"+lexem.Tail(Prefix.Length()));
 
334
          if( ParseUnitWithPrefix(lexem.Tail(Prefix.Length()),unit,K) ){
 
335
//            TRACE(unit->Symbol());
 
336
            prefixlg=L+K;
 
337
            break;
 
338
          };
 
339
        };
 
340
      };
 
341
    };
 
342
  };
 
343
  return ! (unit == NULL);
 
344
};
 
345
 
 
346
 
 
347
/*! Резервирует наиболее важные единицы.
 
348
 
 
349
Помогает избежать следующей проблемы:
 
350
 
 
351
Новые единицы автоматически регистрируются в плагинах и диалоге.  И, например,
 
352
"ms" будет зарегистрирована как базовая, если до этого не регистрировалась "s".
 
353
Если "s" зарегистрирована до первого появления "ms", то "ms" распознаётся как
 
354
milli-"s".
 
355
 
 
356
Последнее, впрочем, не мешает всяким извращенцам явно зарегистрировать "ms" со
 
357
смыслом, отличным от milli-"s". Тогда "ms" будет означать, например, единицу
 
358
маразма, "Mms" - мегамаразм, но "ks" и "ns" останутся производными от "s".
 
359
 
 
360
*/
 
361
void  sUnit::MakeVeryBasicDefinitions ()
 
362
{
 
363
  Register("m");
 
364
  Register("g");
 
365
  Register("s");
 
366
  Register("A");
 
367
  Register("K");
 
368
  //cannot use sPhysValue yet!
 
369
};
 
370
 
 
371
//------------------------------------
 
372
 
139
373
/*! copying is not allowed */
140
374
sUnit::sUnit (rcsUnit  U)
141
375
    :sAdam()
142
376
    ,sStorable()
143
377
    ,Is_1_Flag(U.Is_1_Flag)
 
378
    ,IsObsoleteFlag(U.IsObsoleteFlag)
144
379
    ,TheSymbol(U.TheSymbol)
145
 
    ,TheSense(U.TheSense)
 
380
    ,ThePrefixAllowance(U.ThePrefixAllowance)
 
381
    ,TheDefinition(U.TheDefinition)
146
382
{
147
383
};
148
384
 
149
385
 
150
386
/*! assignment op is not allowed */
151
 
rsUnit  sUnit::operator = (sUnit  U)
 
387
rsUnit  sUnit::operator = (rcsUnit  U)
152
388
{
153
389
  Is_1_Flag = U.Is_1_Flag;
 
390
  IsObsoleteFlag = U.IsObsoleteFlag;
154
391
  TheSymbol = U.TheSymbol;
155
 
  TheSense = U.TheSense;
 
392
  ThePrefixAllowance = U.ThePrefixAllowance;
 
393
  TheDefinition = U.TheDefinition;
156
394
  return *this;
157
395
};
158
396
 
159
397
 
160
 
psUnit  sUnit::Unit (sString  id)
161
 
{
162
 
  map<sString,psUnit>::iterator    U = UnitList.find(id);
163
 
  if( U == UnitList.end() ){
164
 
    return NULL;
165
 
  }else{
166
 
    return U->second;
167
 
  };
168
 
};
169
 
 
170
 
 
171
398
sUnit::sUnit ()
172
399
    :Is_1_Flag(true)
173
 
    ,TheSymbol("1")//𝟙
174
 
{
175
 
};
176
 
 
177
 
 
178
 
psUnit  sUnit::Register (sString  symbol  ,sString  sense)
179
 
{
180
 
  if( symbol.Empty() ){
181
 
    return _1_;
182
 
  }else{
183
 
    psUnit                    U ( new sUnit(symbol,sense) );
184
 
    psUnit                    UU = Unit( U->Id() );
185
 
    if( UU ){
186
 
      delete U;
187
 
      return UU;
188
 
    }else{
189
 
      UnitList[U->Id()]=U;
190
 
      return U;
191
 
    };
192
 
  };
193
 
};
194
 
 
195
 
 
196
 
sUnit::sUnit (sString  symbol  ,sString  sense)
 
400
    ,IsObsoleteFlag(false)
 
401
    ,TheSymbol(Symbol::Unit_1)
 
402
    ,ThePrefixAllowance(sMetricPrefix::NoPrefixAllowed)
 
403
    ,TheDefinition(NULL)
 
404
{
 
405
};
 
406
 
 
407
 
 
408
sUnit::sUnit (sString      symbol
 
409
             ,sString      prefix_allowance
 
410
             ,psPhysValue  definition)
197
411
    :Is_1_Flag(false)
 
412
    ,IsObsoleteFlag(false)
198
413
    ,TheSymbol(symbol)
199
 
    ,TheSense(sense)
 
414
    ,ThePrefixAllowance(prefix_allowance)
 
415
    ,TheDefinition(definition)
200
416
{
201
417
};
202
418
 
203
419
 
204
420
sUnit::sUnit (rsObjectStream a_stream)
205
421
    :sStorable(a_stream)
 
422
    ,TheDefinition(NULL)
206
423
{
 
424
  bool                        HasDefinition;
207
425
  a_stream.READ_INTO(Is_1_Flag);
 
426
  a_stream.READ_INTO(IsObsoleteFlag);
208
427
  a_stream.ReadString(TheSymbol);
209
 
  a_stream.ReadString(TheSense);
210
 
  Register(TheSymbol,TheSense);
 
428
  a_stream.ReadString(ThePrefixAllowance);
 
429
  a_stream.READ_INTO(HasDefinition);
 
430
  if( HasDefinition ){
 
431
    TheDefinition = new sPhysValue(a_stream);
 
432
  };
 
433
  Register(TheSymbol);
211
434
};
212
435
 
213
436
 
214
437
void  sUnit::Store (rsObjectStream a_stream)
215
438
{
 
439
  bool                        HasDefinition = (TheDefinition != NULL);
216
440
  sStorable::Store(a_stream);
217
441
  a_stream.WRITE_FROM(Is_1_Flag);
 
442
  a_stream.WRITE_FROM(IsObsoleteFlag);
218
443
  a_stream.WriteString(TheSymbol);
219
 
  a_stream.WriteString(TheSense);
220
 
};
 
444
  a_stream.WriteString(ThePrefixAllowance);
 
445
  a_stream.WRITE_FROM(HasDefinition);
 
446
  if( HasDefinition ){
 
447
    TheDefinition->Store(a_stream);
 
448
  };
 
449
};
 
450
 
 
451
 
 
452
bool  sUnit::PrefixAllowed (int  prefix_index) const
 
453
{
 
454
  char                        A = ThePrefixAllowance[24-prefix_index];
 
455
  return (A != '.') && (A != '-');
 
456
};
 
457
 
 
458
 
 
459
//void  sUnit::SetPrefixAllowance (sString)
 
460
//{
 
461
//};
 
462
//
 
463
//
 
464
//void  sUnit::SetDefinition (sPhysValue)
 
465
//{
 
466
//};
221
467
 
222
468
//------------------------------------------------------------------- sUnits ---
223
469
 
 
470
sUnits  sUnits::Parse (sString  S)
 
471
{
 
472
//  RANet::Log.OpenBlock(sLog::Debug,"sUnits::Parse",S);
 
473
  sUnits                      UU;
 
474
  bool                        Division = false;
 
475
  size_t                      P = std::min( S.Pos("*") , S.Pos("/") );
 
476
  sString                     Term;
 
477
  int                         PrefixLg;
 
478
  int                         Power;
 
479
  psUnit                      Unit;
 
480
  while( ! S.Empty() ){
 
481
    Term = S.Substr(0,P);
 
482
    Power=1;
 
483
    size_t                      PP = std::min( Term.Pos("+") , Term.Pos("-") );
 
484
    for( char D = '0' ; D <= '9' ; ++D )
 
485
      PP = std::min( PP , Term.Pos(sString(D)) );
 
486
    if( PP < Term.Length() ){
 
487
      sString                     PowerText=Term.Tail(PP);
 
488
      Term=Term.Substr(0,PP);
 
489
      PowerText >> Power;
 
490
    };
 
491
    if( Division )  Power = - Power;
 
492
    Term.EatLeadingSpaces();
 
493
    if( ! Term.Empty() ){
 
494
      if( sUnit::ParseUnitWithPrefix(Term,Unit,PrefixLg) ){
 
495
        UU.Product.push_back(sTerm(Unit,Power,PrefixLg));
 
496
      }else if( sUnit::RegisterDialog ){
 
497
        if( (*sUnit::RegisterDialog)(Term) ){
 
498
          if( sUnit::ParseUnitWithPrefix(Term,Unit,PrefixLg) ){
 
499
            UU.Product.push_back(sTerm(Unit,Power,PrefixLg));
 
500
          };
 
501
        };
 
502
      }else{
 
503
        UU.Product.push_back(sTerm(sUnit::Register(Term),Power,0));
 
504
      };
 
505
    };
 
506
    if( P < S.Length() )
 
507
      Division = (S[P] == '/');
 
508
    S = S.Tail(P+1);
 
509
    P = std::min( S.Pos("*") , S.Pos("/") );
 
510
  };
 
511
//  RANet::Log.Put(sLog::Debug,"sUnits::Parse",UU.Text());
 
512
//  RANet::Log.CloseBlock(sLog::Debug,"sUnits::Parse");
 
513
  return UU;
 
514
};
 
515
 
 
516
//----------------------------------------
 
517
 
224
518
sUnits::~sUnits ()
225
519
{
226
520
  Product.clear();
230
524
sUnits::sUnits (rsObjectStream a_stream)
231
525
    :sStorable(a_stream)
232
526
{
 
527
  a_stream.READ_INTO(InBasicTerms);
 
528
  a_stream.READ_INTO(Refined);
233
529
  bool                        Terminator = false;
234
530
  a_stream.READ_INTO(Terminator);
235
531
  while( ! Terminator ){
236
 
    sUnit                       U(a_stream);
 
532
    sString                     Symbol;
237
533
    int                         Power;
238
534
    int                         PrefixLg;
 
535
    a_stream.ReadString(Symbol);
239
536
    a_stream.READ_INTO(Power);
240
537
    a_stream.READ_INTO(PrefixLg);
241
 
    Product.push_back( sTerm(sUnit::Unit(U.Id()),Power,PrefixLg) );
 
538
    Product.push_back( sTerm(sUnit::Register(Symbol),Power,PrefixLg) );
242
539
    a_stream.READ_INTO(Terminator);
243
540
  };
244
541
};
246
543
 
247
544
void  sUnits::Store (rsObjectStream a_stream)
248
545
{
 
546
  a_stream.WRITE_FROM(InBasicTerms);
 
547
  a_stream.WRITE_FROM(Refined);
249
548
  bool                        Terminator = false;
250
549
  sStorable::Store(a_stream);
251
 
  for( std::list<sTerm>::const_iterator i = Product.begin()
252
 
                                      ; i != Product.end() ; i++ ){
 
550
  for( tProduct::const_iterator i = Product.begin()
 
551
                              ; i != Product.end() ; i++ ){
253
552
    a_stream.WRITE_FROM(Terminator);
254
 
    i->Unit->Store(a_stream);
 
553
    a_stream.WriteString(i->Unit->Symbol());
255
554
    a_stream.WRITE_FROM(i->Power);
256
555
    a_stream.WRITE_FROM(i->PrefixLg);
257
556
  };
259
558
  a_stream.WRITE_FROM(Terminator);
260
559
};
261
560
 
 
561
 
262
562
sUnits::sUnits (rcsUnits  U)
263
563
    :sAdam()
264
564
    ,sStorable()
265
565
    ,Product(U.Product)
 
566
    ,InBasicTerms(U.InBasicTerms)
 
567
    ,Refined(U.Refined)
266
568
{
267
569
};
268
570
 
269
571
 
270
 
rsUnits  sUnits::operator = (sUnits  U)
 
572
sUnits::sUnits ()
 
573
    :InBasicTerms(true)
 
574
    ,Refined(true)
271
575
{
272
 
  Product = U.Product;
273
 
  return *this;
274
576
};
275
577
 
276
578
 
277
579
sUnits::sUnits (psUnit unit
278
580
               ,int    power
279
581
               ,int    prefix_lg)
280
 
{
281
 
  if( unit != sUnit::_1_ ){
282
 
    Product.push_back(sTerm(unit,power,prefix_lg));
283
 
  };
284
 
//  Normalize();
285
 
};
286
 
 
287
 
 
288
 
sUnits::sUnits (sString  S)
289
 
{
290
 
  bool                        Division = false;
291
 
  size_t                      P = std::min( S.Pos("*") , S.Pos("/") );
292
 
  sString                     Term;
293
 
  int                         PrefixLg;
294
 
  int                         Power;
295
 
  while( ! S.Empty() ){
296
 
    Term = S.Substr(0,P);
297
 
    Power=1;
298
 
    size_t                      PP = std::min( Term.Pos("+") , Term.Pos("-") );
299
 
    for( char D = '0' ; D <= '9' ; ++D )
300
 
      PP = std::min( PP , Term.Pos(sString(D)) );
301
 
    if( PP < Term.Length() ){
302
 
      sString                     PowerText=Term.Tail(PP);
303
 
      Term=Term.Substr(0,PP);
304
 
      PowerText >> Power;
305
 
    };
306
 
    PrefixLg=0;
307
 
    if( ! Term.Empty() ){
308
 
      for( int L = 24 ; (L >= -24) && (PrefixLg == 0) ; --L ){
309
 
        sString                     Prefix = sMetricPrefix::Symbol(L);
310
 
        if( ! Prefix.Empty() && (Prefix != "?") ){
311
 
          if( (Term.Substr(0,Prefix.Length()) == Prefix)
312
 
              && (Term.Length() > Prefix.Length()) )   {
313
 
                PrefixLg=L;
314
 
                Term=Term.Tail(Prefix.Length());
315
 
              };
316
 
        };
317
 
      };
318
 
    };
319
 
    if( Division )  Power = - Power;
320
 
    if( ! Term.Empty() ){
321
 
      Product.push_back(sTerm(sUnit::Register(Term),Power,PrefixLg));
322
 
    };
323
 
    if( P < S.Length() )
324
 
      Division = S[P] == '/';
325
 
    S = S.Tail(P+1);
326
 
    P = std::min( S.Pos("*") , S.Pos("/") );
327
 
  };
328
 
//  Normalize();
329
 
};
330
 
 
331
 
 
332
 
sPhysValue  sUnits::operator * (sUnits  U) const
333
 
{
334
 
  sUnits                      ResultingUnits(*this);
335
 
  for( std::list<sTerm>::const_iterator i = U.Product.begin()
336
 
                                      ; i != U.Product.end() ; i++ ){
337
 
    ResultingUnits.Product.push_back(*i);
338
 
  };
339
 
  int                         Order;
340
 
  ResultingUnits.SimplifyProduct(Order);
341
 
  sPhysValue                       Result(ResultingUnits);
342
 
  Result.ShiftOrder(Order);
343
 
  return Result;
344
 
};
345
 
 
346
 
 
347
 
sPhysValue  sUnits::operator / (sUnits  U) const
348
 
{
349
 
  sUnits                      ResultingUnits(*this);
350
 
  for( std::list<sTerm>::const_iterator i = U.Product.begin()
351
 
                                      ; i != U.Product.end() ; i++ ){
352
 
    sTerm                       T( i->Unit , - i->Power , i->PrefixLg );
353
 
    ResultingUnits.Product.push_back(T);
354
 
  };
355
 
  int                         Order;
356
 
  ResultingUnits.SimplifyProduct(Order);
357
 
  sPhysValue                       Result(ResultingUnits);
358
 
  Result.ShiftOrder(Order);
359
 
  return Result;
360
 
};
361
 
 
362
 
 
363
 
bool  sUnits::Comparable (rcsUnits U, real &  coeff) const
364
 
{
365
 
  /*! @todo{VB_!_RAlgebra} ToBasic/U.ToBasic() */
366
 
  int                               coeff_log = 0;
367
 
  std::list<sTerm>::const_iterator  i = Product.begin();
368
 
  std::list<sTerm>::const_iterator  iU = U.Product.begin();
369
 
  while( (i != Product.end()) && (iU != U.Product.end()) ){
370
 
    if( (i->Unit->Id() == iU->Unit->Id()) && (i->Power == iU->Power) ){
371
 
      coeff_log += (i->PrefixLg - iU->PrefixLg) * i->Power;
372
 
      i++;
373
 
      iU++;
 
582
    :InBasicTerms(unit->IsBasic())
 
583
    ,Refined(true)
 
584
{
 
585
  Product.push_back(sTerm(unit,power,prefix_lg));
 
586
};
 
587
 
 
588
 
 
589
sUnits::sUnits (sString  text)
 
590
{
 
591
  try{
 
592
    sUnits                      U( sUnits::Parse(text) );
 
593
    Product = U.Product;
 
594
    InBasicTerms = U.InBasicTerms;
 
595
    Refined = U.Refined;
 
596
  }catch(...){
 
597
    Product.clear();
 
598
    InBasicTerms = true;
 
599
    Refined = true;
 
600
  };
 
601
};
 
602
 
 
603
 
 
604
bool  sUnits::Is_1_ () const
 
605
{
 
606
  return Product.empty();
 
607
};
 
608
 
 
609
 
 
610
rsUnits  sUnits::operator = (rcsUnits  U)
 
611
{
 
612
  Product = U.Product;
 
613
  InBasicTerms = U.InBasicTerms;
 
614
  Refined = U.Refined;
 
615
  return *this;
 
616
};
 
617
 
 
618
 
 
619
sPhysValue  sUnits::operator * (rcsUnits  U) const
 
620
{
 
621
  sPhysValue                  Result(*this);
 
622
  Result.TheOrder += Result.TheUnits.MultBy(U);
 
623
  return Result;
 
624
};
 
625
 
 
626
 
 
627
sPhysValue  sUnits::operator / (rcsUnits  U) const
 
628
{
 
629
  sPhysValue                  Result(*this);
 
630
  Result.TheOrder += Result.TheUnits.DivideBy(U);
 
631
  return Result;
 
632
};
 
633
 
 
634
 
 
635
int  sUnits::MultBy (rcsUnits  U)
 
636
{
 
637
  for( tProduct::const_iterator i = U.Product.begin()
 
638
                              ; i != U.Product.end() ; i++ ){
 
639
    Product.push_back(*i);
 
640
  };
 
641
  InBasicTerms = false;
 
642
  Refined = false;
 
643
  return SimplifyProduct();
 
644
};
 
645
 
 
646
 
 
647
int  sUnits::DivideBy (rcsUnits  U)
 
648
{
 
649
  for( tProduct::const_iterator i = U.Product.begin()
 
650
                              ; i != U.Product.end() ; i++ ){
 
651
    Product.push_back( sTerm( i->Unit , - i->Power , i->PrefixLg ) );
 
652
  };
 
653
  InBasicTerms = false;
 
654
  Refined = false;
 
655
  return SimplifyProduct();
 
656
};
 
657
 
 
658
 
 
659
sPhysValue  sUnits::ToBasic () const
 
660
{
 
661
  real                        Coeff = 1.0;
 
662
  sUnits                      U(*this);
 
663
  int                         Order;
 
664
  SubstituteDefinitions(Coeff,U);
 
665
  U.InBasicTerms = true;
 
666
  U.Refined = false;
 
667
  Order = U.SimplifyProduct();
 
668
  sPhysValue                  Result(Coeff,U);
 
669
  Result << Order;
 
670
  return Result;
 
671
};
 
672
 
 
673
 
 
674
//static
 
675
void  sUnits::SubstituteDefinitions (real &   coeff
 
676
                                    ,rsUnits  units)
 
677
{
 
678
  sUnits                      Result;
 
679
  bool                        Changed = false;
 
680
  for( tProduct::const_iterator i = units.Product.begin()
 
681
                              ; i != units.Product.end() ; i++ ){
 
682
    psPhysValue                 D = i->Unit->Definition();
 
683
    if( D ){
 
684
      Changed = true;
 
685
      real                        C = sMetricPrefix::Multiplier(i->PrefixLg)
 
686
                                      * D->ArbValue();
 
687
      sUnits                      DU(D->Units());
 
688
      if( i->Power > 0 ){
 
689
        for( int p = i->Power ; p != 0 ; p-- )  coeff *= C;
 
690
      }else if( i->Power < 0 ){
 
691
        for( int p = i->Power ; p != 0 ; p++ )  coeff /= C;
 
692
      };
 
693
      for( tProduct::const_iterator j = DU.Product.begin()
 
694
                                  ; j != DU.Product.end() ; j++ ){
 
695
        Result.Product.push_back( sTerm(j->Unit
 
696
                                       ,j->Power * i->Power
 
697
                                       ,j->PrefixLg          ) );
 
698
      };
374
699
    }else{
375
 
      return false;
 
700
      Result.Product.push_back(*i);
376
701
    };
377
702
  };
378
 
  if( (i != Product.end()) || (iU != U.Product.end()) )
379
 
    return false;
380
 
  coeff = power10( coeff_log );
381
 
  return true;
382
 
};
383
 
 
384
 
 
385
 
void  sUnits::SimplifyProduct (int &  log_shift)
386
 
{
387
 
  std::list<sTerm>            P(Product);
 
703
  if( Changed ){
 
704
    SubstituteDefinitions(coeff,Result);
 
705
    units = Result;
 
706
  };
 
707
};
 
708
 
 
709
 
 
710
bool  sUnits::Comparable (rcsUnits  units
 
711
                         ,real &    ratio) const
 
712
{
 
713
//  RANet::Log.OpenBlock(sLog::Debug,"sUnits::Comparable"
 
714
//                      ,sString("Comparing '")+Text()+"' to '"+units.Text()+"'");
 
715
  sPhysValue                  R( ToBasic() / units.ToBasic() );
 
716
  if( R.TheUnits.Product.empty() ){
 
717
    ratio = R.ArbValue();
 
718
//    RANet::Log.Put(sLog::Debug,"sUnits::Comparable"
 
719
//                  ,sString("Comparable with ratio=")+R.Text());
 
720
//    RANet::Log.CloseBlock(sLog::Debug,"sUnits::Comparable");
 
721
    return true;
 
722
  };
 
723
//  RANet::Log.Put(sLog::Debug,"sUnits::Comparable",sString("NOT comparable"));
 
724
//  RANet::Log.CloseBlock(sLog::Debug,"sUnits::Comparable");
 
725
  return false;
 
726
};
 
727
 
 
728
 
 
729
/*! Упрощает результат произведения или деления единиц.
 
730
 
 
731
В результате сомножители отсортированы, не дублируются, не содержат _1_
 
732
и лишены метрических префиксов.
 
733
Результирующий показатель порядкового множителя возвращается.
 
734
*/
 
735
int  sUnits::SimplifyProduct (int  log_shift)
 
736
{
 
737
  tProduct                    P(Product);
388
738
  P.sort();
389
739
  Product.clear();
390
 
  log_shift=0;
391
740
  while( ! P.empty() ){
392
741
    sTerm                       T(P.front());
393
742
    P.pop_front();
394
 
    if( Product.empty() ){
 
743
    log_shift += T.PrefixLg*T.Power;
 
744
    T.PrefixLg = 0;
 
745
    if( T.Unit == sUnit::_1_ ){
 
746
      //do nothing
 
747
    }else if( Product.empty() ){
395
748
      Product.push_back(T);
396
 
    }else if( Product.back().Unit->Id() != T.Unit->Id() ){
 
749
    }else if( Product.back().Unit->Symbol() != T.Unit->Symbol() ){
397
750
      Product.push_back(T);
398
751
    }else{
399
 
      Product.back().PrefixLg = Product.back().PrefixLg*Product.back().Power
400
 
                              + T.PrefixLg*T.Power;
401
752
      Product.back().Power += T.Power;
402
753
      if( Product.back().Power == 0 ){
403
 
        log_shift += Product.back().PrefixLg;
404
754
        Product.pop_back();
405
 
      }else{
406
 
        Product.back().PrefixLg /= Product.back().Power;
407
 
      };
408
 
    };
409
 
  };
410
 
  /*! @todo{VB_!_RAlgebra} second pass with PrefixAllowance: Refine(log_shift)?*/
411
 
};
412
 
 
413
 
 
414
 
//void  sUnits::Normalize (int  log_shift)
415
 
//{
416
 
//  MultiplierExp += log_shift;
417
 
//  std::list<sTerm>            P(Product);
418
 
//  P.sort();
419
 
//  Product.clear();
420
 
//  while( ! P.empty() ){
421
 
//    sTerm                       T(P.front());
422
 
//    P.pop_front();
423
 
//    MultiplierExp += T.PrefixLg * T.Power;
424
 
//    T.PrefixLg = 0;
425
 
//    /*! @todo{VB_!_RAlgebra}
426
 
//    if( ! T.Unit->PrefixAllowed(0) ){
427
 
//      изменить префикс (если можно), поправить MultiplierExp
428
 
//    };
429
 
//    */
430
 
//    if( Product.empty() ){
431
 
//      Product.push_back(T);
432
 
//    }else if( Product.back().Unit->Id() != T.Unit->Id() ){
433
 
//      Product.push_back(T);
434
 
//    }else{
435
 
//      Product.back().Power += T.Power;
436
 
//      if( Product.back().Power == 0 )
437
 
//        Product.pop_back();
438
 
//    };
439
 
//  };
440
 
//};
441
 
 
442
 
 
443
 
//sUnits  sUnits::Refine () const
444
 
//{
445
 
//  sUnits                      U(*this);
446
 
//  /*! @todo{VB_!_RAlgebra} sUnits::Refine*/
447
 
//  if( ! Product.empty() ){
448
 
//
449
 
//  };
450
 
//  return U;
 
755
      };
 
756
    };
 
757
  };
 
758
  return log_shift;
 
759
};
 
760
 
 
761
 
 
762
void  sUnits::SmartSort ()
 
763
{
 
764
  tProduct                    P(Product);
 
765
  Product.clear();
 
766
  for( tProduct::const_iterator i = P.begin() ; i != P.end() ; i++ ){
 
767
    if( i->Power > 0 )  Product.push_back(*i);
 
768
  };
 
769
  for( tProduct::const_iterator i = P.begin() ; i != P.end() ; i++ ){
 
770
    if( i->Power < 0 )  Product.push_back(*i);
 
771
  };
 
772
};
 
773
 
 
774
 
 
775
int  sUnits::DissolveOrder (unsigned short int  level
 
776
                           ,int                 log_shift
 
777
                           ,int                 min_rest_expected
 
778
                           ,int                 max_rest_expected)
 
779
{
 
780
//  RANet::Log.OpenBlock(sLog::Debug,"sUnits::DissolveOrder"
 
781
//                                  ,sString("'")+Text()+"'");
 
782
//  TRACENOCR(log_shift);
 
783
  log_shift = SimplifyProduct(log_shift);
 
784
  if( ! Product.empty() ){
 
785
    SmartSort();
 
786
    //! @todo{PhysValues} начинать с разрешённых префиксов
 
787
    tPrefixes                   BestChoice(0,Product.size());
 
788
    int                         BestWeight = std::numeric_limits<int>::min();
 
789
    int                         BestRestOrder = log_shift;
 
790
    FindBestChoice(BestChoice,BestWeight,BestRestOrder
 
791
                  ,min_rest_expected,max_rest_expected
 
792
                  ,BestChoice,0         ,log_shift    ,0
 
793
                  ,level);
 
794
 
 
795
    int                         ii=0;
 
796
    for( tProduct::iterator i = Product.begin() ; i != Product.end() ; i++ ){
 
797
      i->PrefixLg = BestChoice[ii++];
 
798
    };
 
799
    log_shift = BestRestOrder;
 
800
  };
 
801
//  RANet::Log.Put(sLog::Debug,"sUnits::DissolveOrder",sString("result '")+Text()+"'");
 
802
//  RANet::Log.CloseBlock(sLog::Debug,"sUnits::DissolveOrder");
 
803
  return log_shift;
 
804
};
 
805
 
 
806
 
 
807
void  sUnits::FindBestChoice (tPrefixes &  best_choice
 
808
                             ,int       &  best_weight
 
809
                             ,int       &  best_rest_order
 
810
                             ,int          min_rest_expected
 
811
                             ,int          max_rest_expected
 
812
                             ,tPrefixes    current_prefixes
 
813
                             ,int          weight
 
814
                             ,int          rest_order
 
815
                             ,size_t       term_to_vary
 
816
                             ,unsigned short int  level
 
817
                             )
 
818
{
 
819
  if(    (term_to_vary >= level)
 
820
      || (term_to_vary >= current_prefixes.size()) ){
 
821
    if( (rest_order > max_rest_expected) || (rest_order < min_rest_expected) )
 
822
      weight -= 10000;
 
823
    if( weight > best_weight ){
 
824
      best_weight = weight;
 
825
      best_rest_order = rest_order;
 
826
      best_choice = current_prefixes;
 
827
//      TRACE(best_weight);
 
828
//      TRACE(best_rest_order);
 
829
//      sString                     best_text;
 
830
//      for( tProduct::const_iterator i = best_choice.begin()
 
831
//                                  ; i != best_choice.end() ; i++ ){
 
832
//        if( ! best_text.Empty() ){
 
833
//            best_text += "*";
 
834
//        };
 
835
//        if( i->PrefixLg ){
 
836
//          best_text += sMetricPrefix::CombinedSymbol(i->PrefixLg);
 
837
//        };
 
838
//        best_text += i->Unit->Symbol();
 
839
//        if( i->Power != 1 ){
 
840
//          best_text << i->Power;
 
841
//        };
 
842
//      };
 
843
//      TRACE(best_text);
 
844
    };
 
845
  }else{
 
846
    tProduct::const_iterator    i = Product.begin();
 
847
    for( size_t ii = 0 ; ii < term_to_vary ; ii++ ){
 
848
      i++;
 
849
    };
 
850
    for( int L = 24 ; L >= -24 ; --L ){
 
851
      if( i->Unit->PrefixAllowed(L) ){
 
852
        int                         WeightDownshift;
 
853
        WeightDownshift = ( L==0 ? 0                        //за каждый префикс
 
854
                                 : ( term_to_vary==0 ?  700   //на первом месте
 
855
                                                     : 1000 ))//на остальных
 
856
                        + ( (L % 3)==0 ? 0 : 2000 ) //за каждый "кривой" префикс
 
857
                        + ( L>0 ? L*30 : -L*35 )  //за "величину" префикса
 
858
                        ;
 
859
        current_prefixes[term_to_vary] = L;
 
860
        FindBestChoice(best_choice,best_weight,best_rest_order
 
861
                      ,min_rest_expected,max_rest_expected
 
862
                      ,current_prefixes
 
863
                      ,weight - WeightDownshift
 
864
                      ,rest_order - L * i->Power
 
865
                      ,term_to_vary+1
 
866
                      ,level);
 
867
      };
 
868
    };
 
869
  };
 
870
};
 
871
 
 
872
 
 
873
//void  sUnits::OrderPushIn (int  log_shift)
 
874
//{
 
875
//  if( log_shift == 0 ){
 
876
//    //do nothing
 
877
//  }else if( Product.empty() ){
 
878
//    Product.push_back(sTerm(sUnit::_1_,1,log_shift));
 
879
//  }else{
 
880
//    for( tProduct::iterator i = Product.begin()
 
881
//                          ; (i != Product.end()) && (log_shift != 0) ; i++ ){
 
882
//      i->PrefixLg += log_shift / i->Power;
 
883
//      log_shift = log_shift % i->Power;
 
884
//    };
 
885
//    if( log_shift != 0 ){
 
886
//      Product.push_front(sTerm(sUnit::_1_,1,log_shift));
 
887
//    };
 
888
//  };
451
889
//};
452
890
 
453
891
 
454
892
sString  sUnits::Text (eTextFormat  F) const
455
893
{
456
894
  sString                     T;
457
 
  for( std::list<sTerm>::const_iterator i = Product.begin()
458
 
                                      ; i != Product.end() ; i++ ){
459
 
    if( (F == Plain) && ! T.Empty() )
460
 
      T += "*";
461
 
    if( i->PrefixLg )
462
 
      T += sMetricPrefix::Symbol(i->PrefixLg);
 
895
  int                         NegativePowerCount = 0;
 
896
  int                         TermCount = 0;
 
897
  int                         NumOfTerms = 0;
 
898
  for( tProduct::const_iterator i = Product.begin()
 
899
                              ; i != Product.end() ; i++ ){
 
900
    NumOfTerms++;
 
901
    if( i->Power < 0 )  NegativePowerCount++;
 
902
  };
 
903
  for( tProduct::const_iterator i = Product.begin()
 
904
                              ; i != Product.end() ; i++ ){
 
905
    int                         i_Power = i->Power;
 
906
    TermCount++;
 
907
    if( ! T.Empty() ){
 
908
      if( (i_Power < 0) && (NegativePowerCount == 1)
 
909
                        && (TermCount == NumOfTerms) ){
 
910
        T += "/";
 
911
        i_Power = - i_Power;
 
912
      }else{
 
913
        if( F == Plain ){
 
914
          T += "*";
 
915
        }else{
 
916
          T += "·";
 
917
        };
 
918
      };
 
919
    };
 
920
    if( i->PrefixLg ){
 
921
      T += sMetricPrefix::CombinedSymbol(i->PrefixLg);
 
922
      IF_DEBUG( if( F == HTML ) T += "|" );
 
923
    };
463
924
    T += i->Unit->Symbol();
464
 
    if( i->Power != 1 ){
465
 
      if( F == HTML )
466
 
        T += "<sup>";
467
 
      T << i->Power;
468
 
      if( F == HTML )
469
 
        T += "</sup>";
 
925
    if( i_Power != 1 ){
 
926
      if( F == HTML )  T += "<sup>";
 
927
      T << i_Power;
 
928
      if( F == HTML )  T += "</sup>";
470
929
    };
471
930
  };
472
931
  return T;
473
932
};
474
933
 
475
 
 
476
 
//sString  sUnits::TextRefined () const
477
 
//{
478
 
//  return Refine().Text();
479
 
//};
480
 
 
481
934
//------------------------------------------------------------------------------
482
935
}; //namespace RA
483
936