FreeCAD

Форк
0
/
QuantityPyImp.cpp 
768 строк · 24.2 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2013 Jürgen Riegel <juergen.riegel@web.de>              *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
6
 *   This library is free software; you can redistribute it and/or         *
7
 *   modify it under the terms of the GNU Library General Public           *
8
 *   License as published by the Free Software Foundation; either          *
9
 *   version 2 of the License, or (at your option) any later version.      *
10
 *                                                                         *
11
 *   This library  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 Library General Public License for more details.                  *
15
 *                                                                         *
16
 *   You should have received a copy of the GNU Library General Public     *
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24

25
// inclusion of the generated files (generated out of QuantityPy.xml)
26
#include "QuantityPy.h"
27
#include "UnitPy.h"
28
#include "QuantityPy.cpp"
29

30

31
using namespace Base;
32

33
// returns a string which represents the object e.g. when printed in python
34
std::string QuantityPy::representation() const
35
{
36
    std::stringstream ret;
37

38
    double val = getQuantityPtr()->getValue();
39
    Unit unit = getQuantityPtr()->getUnit();
40

41
    // Use Python's implementation to repr() a float
42
    Py::Float flt(val);
43
    ret << static_cast<std::string>(flt.repr());
44
    if (!unit.isEmpty()) {
45
        ret << " " << unit.getString().toUtf8().constData();
46
    }
47

48
    return ret.str();
49
}
50

51
PyObject* QuantityPy::toStr(PyObject* args)
52
{
53
    int prec = getQuantityPtr()->getFormat().precision;
54
    if (!PyArg_ParseTuple(args, "|i", &prec)) {
55
        return nullptr;
56
    }
57

58
    double val = getQuantityPtr()->getValue();
59
    Unit unit = getQuantityPtr()->getUnit();
60

61
    std::stringstream ret;
62
    ret.precision(prec);
63
    ret.setf(std::ios::fixed, std::ios::floatfield);
64
    ret << val;
65
    if (!unit.isEmpty()) {
66
        ret << " " << unit.getString().toUtf8().constData();
67
    }
68

69
    return Py_BuildValue("s", ret.str().c_str());
70
}
71

72
PyObject* QuantityPy::PyMake(PyTypeObject* /*unused*/, PyObject* /*unused*/, PyObject* /*unused*/)
73
{
74
    // create a new instance of QuantityPy and the Twin object
75
    return new QuantityPy(new Quantity);
76
}
77

78
// constructor method
79
int QuantityPy::PyInit(PyObject* args, PyObject* /*kwd*/)
80
{
81
    Quantity* self = getQuantityPtr();
82

83
    PyErr_Clear();  // set by PyArg_ParseTuple()
84
    PyObject* object {};
85
    if (PyArg_ParseTuple(args, "O!", &(Base::QuantityPy::Type), &object)) {
86
        *self = *(static_cast<Base::QuantityPy*>(object)->getQuantityPtr());
87
        return 0;
88
    }
89

90
    PyErr_Clear();  // set by PyArg_ParseTuple()
91
    double f = DOUBLE_MAX;
92
    if (PyArg_ParseTuple(args, "dO!", &f, &(Base::UnitPy::Type), &object)) {
93
        *self = Quantity(f, *(static_cast<Base::UnitPy*>(object)->getUnitPtr()));
94
        return 0;
95
    }
96

97
    PyErr_Clear();  // set by PyArg_ParseTuple()
98
    if (PyArg_ParseTuple(args, "dO!", &f, &(Base::QuantityPy::Type), &object)) {
99
        PyErr_SetString(PyExc_TypeError, "Second argument must be a Unit not a Quantity");
100
        return -1;
101
    }
102

103
    int i1 = 0;
104
    int i2 = 0;
105
    int i3 = 0;
106
    int i4 = 0;
107
    int i5 = 0;
108
    int i6 = 0;
109
    int i7 = 0;
110
    int i8 = 0;
111
    PyErr_Clear();  // set by PyArg_ParseTuple()
112
    if (PyArg_ParseTuple(args, "|diiiiiiii", &f, &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8)) {
113
        if (f < DOUBLE_MAX) {
114
            *self = Quantity(f,
115
                             Unit {static_cast<int8_t>(i1),
116
                                   static_cast<int8_t>(i2),
117
                                   static_cast<int8_t>(i3),
118
                                   static_cast<int8_t>(i4),
119
                                   static_cast<int8_t>(i5),
120
                                   static_cast<int8_t>(i6),
121
                                   static_cast<int8_t>(i7),
122
                                   static_cast<int8_t>(i8)});
123
        }
124
        return 0;
125
    }
126

127
    PyErr_Clear();  // set by PyArg_ParseTuple()
128
    char* string {};
129
    if (PyArg_ParseTuple(args, "et", "utf-8", &string)) {
130
        QString qstr = QString::fromUtf8(string);
131
        PyMem_Free(string);
132
        try {
133
            *self = Quantity::parse(qstr);
134
        }
135
        catch (const Base::ParserError& e) {
136
            PyErr_SetString(PyExc_ValueError, e.what());
137
            return -1;
138
        }
139

140
        return 0;
141
    }
142

143
    PyErr_Clear();  // set by PyArg_ParseTuple()
144
    if (PyArg_ParseTuple(args, "det", &f, "utf-8", &string)) {
145
        QString unit = QString::fromUtf8(string);
146
        PyMem_Free(string);
147
        try {
148
            *self = Quantity(f, unit);
149
        }
150
        catch (const Base::ParserError& e) {
151
            PyErr_SetString(PyExc_ValueError, e.what());
152
            return -1;
153
        }
154

155
        return 0;
156
    }
157

158
    PyErr_SetString(PyExc_TypeError, "Either quantity, float with units or string expected");
159
    return -1;
160
}
161

162
PyObject* QuantityPy::getUserPreferred(PyObject* /*args*/)
163
{
164
    QString uus;
165
    double factor {};
166
    Py::Tuple res(3);
167

168
    QString uss = getQuantityPtr()->getUserString(factor, uus);
169

170
    res[0] = Py::String(uss.toUtf8(), "utf-8");
171
    res[1] = Py::Float(factor);
172
    res[2] = Py::String(uus.toUtf8(), "utf-8");
173

174
    return Py::new_reference_to(res);
175
}
176

177
PyObject* QuantityPy::getValueAs(PyObject* args)
178
{
179
    Quantity quant;
180
    quant.setInvalid();
181

182
    // first try Quantity
183
    if (!quant.isValid()) {
184
        PyObject* object {};
185
        if (PyArg_ParseTuple(args, "O!", &(Base::QuantityPy::Type), &object)) {
186
            quant = *static_cast<Base::QuantityPy*>(object)->getQuantityPtr();
187
        }
188
    }
189

190
    if (!quant.isValid()) {
191
        PyObject* object {};
192
        PyErr_Clear();
193
        if (PyArg_ParseTuple(args, "O!", &(Base::UnitPy::Type), &object)) {
194
            quant.setUnit(*static_cast<Base::UnitPy*>(object)->getUnitPtr());
195
            quant.setValue(1.0);
196
        }
197
    }
198

199
    if (!quant.isValid()) {
200
        PyObject* object {};
201
        double value {};
202
        PyErr_Clear();
203
        if (PyArg_ParseTuple(args, "dO!", &value, &(Base::UnitPy::Type), &object)) {
204
            quant.setUnit(*static_cast<Base::UnitPy*>(object)->getUnitPtr());
205
            quant.setValue(value);
206
        }
207
    }
208

209
    if (!quant.isValid()) {
210
        double f = DOUBLE_MAX;
211
        int i1 = 0;
212
        int i2 = 0;
213
        int i3 = 0;
214
        int i4 = 0;
215
        int i5 = 0;
216
        int i6 = 0;
217
        int i7 = 0;
218
        int i8 = 0;
219
        PyErr_Clear();
220
        if (PyArg_ParseTuple(args, "d|iiiiiiii", &f, &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8)) {
221
            if (f < DOUBLE_MAX) {
222
                quant = Quantity(f,
223
                                 Unit {static_cast<int8_t>(i1),
224
                                       static_cast<int8_t>(i2),
225
                                       static_cast<int8_t>(i3),
226
                                       static_cast<int8_t>(i4),
227
                                       static_cast<int8_t>(i5),
228
                                       static_cast<int8_t>(i6),
229
                                       static_cast<int8_t>(i7),
230
                                       static_cast<int8_t>(i8)});
231
            }
232
        }
233
    }
234

235
    if (!quant.isValid()) {
236
        PyErr_Clear();
237
        char* string {};
238
        if (PyArg_ParseTuple(args, "et", "utf-8", &string)) {
239
            QString qstr = QString::fromUtf8(string);
240
            PyMem_Free(string);
241
            quant = Quantity::parse(qstr);
242
        }
243
    }
244

245
    if (!quant.isValid()) {
246
        PyErr_SetString(PyExc_TypeError, "Either quantity, string, float or unit expected");
247
        return nullptr;
248
    }
249

250
    if (getQuantityPtr()->getUnit() != quant.getUnit() && quant.isQuantity()) {
251
        PyErr_SetString(PyExc_ValueError, "Unit mismatch");
252
        return nullptr;
253
    }
254

255
    quant = Quantity(getQuantityPtr()->getValueAs(quant));
256
    return new QuantityPy(new Quantity(quant));
257
}
258

259
PyObject* QuantityPy::__round__(PyObject* args)
260
{
261
    double val = getQuantityPtr()->getValue();
262
    Unit unit = getQuantityPtr()->getUnit();
263
    Py::Float flt(val);
264
    Py::Callable func(flt.getAttr("__round__"));
265
    double rnd = static_cast<double>(Py::Float(func.apply(args)));
266

267
    return new QuantityPy(new Quantity(rnd, unit));
268
}
269

270
PyObject* QuantityPy::number_float_handler(PyObject* self)
271
{
272
    if (!PyObject_TypeCheck(self, &(QuantityPy::Type))) {
273
        PyErr_SetString(PyExc_TypeError, "Arg must be Quantity");
274
        return nullptr;
275
    }
276

277
    QuantityPy* q = static_cast<QuantityPy*>(self);
278
    return PyFloat_FromDouble(q->getValue());
279
}
280

281
PyObject* QuantityPy::number_int_handler(PyObject* self)
282
{
283
    if (!PyObject_TypeCheck(self, &(QuantityPy::Type))) {
284
        PyErr_SetString(PyExc_TypeError, "Arg must be Quantity");
285
        return nullptr;
286
    }
287

288
    QuantityPy* q = static_cast<QuantityPy*>(self);
289
    return PyLong_FromLong(long(q->getValue()));
290
}
291

292
PyObject* QuantityPy::number_negative_handler(PyObject* self)
293
{
294
    if (!PyObject_TypeCheck(self, &(QuantityPy::Type))) {
295
        PyErr_SetString(PyExc_TypeError, "Arg must be Quantity");
296
        return nullptr;
297
    }
298

299
    Base::Quantity* a = static_cast<QuantityPy*>(self)->getQuantityPtr();
300
    double b = -1;
301
    return new QuantityPy(new Quantity(*a * b));
302
}
303

304
PyObject* QuantityPy::number_positive_handler(PyObject* self)
305
{
306
    if (!PyObject_TypeCheck(self, &(QuantityPy::Type))) {
307
        PyErr_SetString(PyExc_TypeError, "Arg must be Quantity");
308
        return nullptr;
309
    }
310

311
    Base::Quantity* a = static_cast<QuantityPy*>(self)->getQuantityPtr();
312
    return new QuantityPy(new Quantity(*a));
313
}
314

315
PyObject* QuantityPy::number_absolute_handler(PyObject* self)
316
{
317
    if (!PyObject_TypeCheck(self, &(QuantityPy::Type))) {
318
        PyErr_SetString(PyExc_TypeError, "Arg must be Quantity");
319
        return nullptr;
320
    }
321

322
    Base::Quantity* a = static_cast<QuantityPy*>(self)->getQuantityPtr();
323
    return new QuantityPy(new Quantity(fabs(a->getValue()), a->getUnit()));
324
}
325

326
static Quantity& pyToQuantity(Quantity& q, PyObject* pyobj)
327
{
328
    if (PyObject_TypeCheck(pyobj, &Base::QuantityPy::Type)) {
329
        q = *static_cast<Base::QuantityPy*>(pyobj)->getQuantityPtr();
330
    }
331
    else if (PyFloat_Check(pyobj)) {
332
        q = Quantity(PyFloat_AsDouble(pyobj));
333
    }
334
    else if (PyLong_Check(pyobj)) {
335
        q = Quantity(PyLong_AsLong(pyobj));
336
    }
337
    else {
338
        PyErr_Format(PyExc_TypeError, "Cannot convert %s to Quantity", Py_TYPE(pyobj)->tp_name);
339
        throw Py::Exception();
340
    }
341
    return q;
342
}
343

344
PyObject* QuantityPy::number_add_handler(PyObject* self, PyObject* other)
345
{
346
    Quantity* pa = nullptr;
347
    Quantity* pb = nullptr;
348
    Quantity a;
349
    Quantity b;
350
    PY_TRY
351
    {
352
        if (PyObject_TypeCheck(self, &(QuantityPy::Type))) {
353
            pa = static_cast<QuantityPy*>(self)->getQuantityPtr();
354
        }
355
        else {
356
            pa = &pyToQuantity(a, self);
357
        }
358

359
        if (PyObject_TypeCheck(other, &(QuantityPy::Type))) {
360
            pb = static_cast<QuantityPy*>(other)->getQuantityPtr();
361
        }
362
        else {
363
            pb = &pyToQuantity(b, other);
364
        }
365
        return new QuantityPy(new Quantity(*pa + *pb));
366
    }
367
    PY_CATCH
368
}
369

370
PyObject* QuantityPy::number_subtract_handler(PyObject* self, PyObject* other)
371
{
372
    Quantity* pa = nullptr;
373
    Quantity* pb = nullptr;
374
    Quantity a;
375
    Quantity b;
376
    PY_TRY
377
    {
378
        if (PyObject_TypeCheck(self, &(QuantityPy::Type))) {
379
            pa = static_cast<QuantityPy*>(self)->getQuantityPtr();
380
        }
381
        else {
382
            pa = &pyToQuantity(a, self);
383
        }
384

385
        if (PyObject_TypeCheck(other, &(QuantityPy::Type))) {
386
            pb = static_cast<QuantityPy*>(other)->getQuantityPtr();
387
        }
388
        else {
389
            pb = &pyToQuantity(b, other);
390
        }
391
        return new QuantityPy(new Quantity(*pa - *pb));
392
    }
393
    PY_CATCH
394
}
395

396
PyObject* QuantityPy::number_multiply_handler(PyObject* self, PyObject* other)
397
{
398
    Quantity* pa = nullptr;
399
    Quantity* pb = nullptr;
400
    Quantity a;
401
    Quantity b;
402
    PY_TRY
403
    {
404
        if (PyObject_TypeCheck(self, &(QuantityPy::Type))) {
405
            pa = static_cast<QuantityPy*>(self)->getQuantityPtr();
406
        }
407
        else {
408
            pa = &pyToQuantity(a, self);
409
        }
410

411
        if (PyObject_TypeCheck(other, &(QuantityPy::Type))) {
412
            pb = static_cast<QuantityPy*>(other)->getQuantityPtr();
413
        }
414
        else {
415
            pb = &pyToQuantity(b, other);
416
        }
417
        return new QuantityPy(new Quantity(*pa * *pb));
418
    }
419
    PY_CATCH
420
}
421

422
PyObject* QuantityPy::number_divide_handler(PyObject* self, PyObject* other)
423
{
424
    Quantity* pa = nullptr;
425
    Quantity* pb = nullptr;
426
    Quantity a;
427
    Quantity b;
428
    PY_TRY
429
    {
430
        if (PyObject_TypeCheck(self, &(QuantityPy::Type))) {
431
            pa = static_cast<QuantityPy*>(self)->getQuantityPtr();
432
        }
433
        else {
434
            pa = &pyToQuantity(a, self);
435
        }
436

437
        if (PyObject_TypeCheck(other, &(QuantityPy::Type))) {
438
            pb = static_cast<QuantityPy*>(other)->getQuantityPtr();
439
        }
440
        else {
441
            pb = &pyToQuantity(b, other);
442
        }
443
        return new QuantityPy(new Quantity(*pa / *pb));
444
    }
445
    PY_CATCH
446
}
447

448
PyObject* QuantityPy::number_remainder_handler(PyObject* self, PyObject* other)
449
{
450
    if (!PyObject_TypeCheck(self, &(QuantityPy::Type))) {
451
        PyErr_SetString(PyExc_TypeError, "First arg must be Quantity");
452
        return nullptr;
453
    }
454

455
    double d1 {};
456
    double d2 {};
457
    Base::Quantity* a = static_cast<QuantityPy*>(self)->getQuantityPtr();
458
    d1 = a->getValue();
459

460
    if (PyObject_TypeCheck(other, &(QuantityPy::Type))) {
461
        Base::Quantity* b = static_cast<QuantityPy*>(other)->getQuantityPtr();
462
        d2 = b->getValue();
463
    }
464
    else if (PyFloat_Check(other)) {
465
        d2 = PyFloat_AsDouble(other);
466
    }
467
    else if (PyLong_Check(other)) {
468
        d2 = (double)PyLong_AsLong(other);
469
    }
470
    else {
471
        PyErr_SetString(PyExc_TypeError, "Expected quantity or number");
472
        return nullptr;
473
    }
474

475
    PyObject* p1 = PyFloat_FromDouble(d1);
476
    PyObject* p2 = PyFloat_FromDouble(d2);
477
    PyObject* r = PyNumber_Remainder(p1, p2);
478
    Py_DECREF(p1);
479
    Py_DECREF(p2);
480
    if (!r) {
481
        return nullptr;
482
    }
483
    double q = PyFloat_AsDouble(r);
484
    Py_DECREF(r);
485
    return new QuantityPy(new Quantity(q, a->getUnit()));
486
}
487

488
PyObject* QuantityPy::number_divmod_handler(PyObject* /*self*/, PyObject* /*other*/)
489
{
490
    // PyNumber_Divmod();
491
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
492
    return nullptr;
493
}
494

495
PyObject* QuantityPy::number_power_handler(PyObject* self, PyObject* other, PyObject* /*modulo*/)
496
{
497
    if (!PyObject_TypeCheck(self, &(QuantityPy::Type))) {
498
        PyErr_SetString(PyExc_TypeError, "First arg must be Quantity");
499
        return nullptr;
500
    }
501

502
    PY_TRY
503
    {
504
        if (PyObject_TypeCheck(other, &(QuantityPy::Type))) {
505
            Base::Quantity* a = static_cast<QuantityPy*>(self)->getQuantityPtr();
506
            Base::Quantity* b = static_cast<QuantityPy*>(other)->getQuantityPtr();
507
            Base::Quantity q(a->pow(*b));  // to prevent memory leak in case of exception
508

509
            return new QuantityPy(new Quantity(q));
510
        }
511
        if (PyFloat_Check(other)) {
512
            Base::Quantity* a = static_cast<QuantityPy*>(self)->getQuantityPtr();
513
            double b = PyFloat_AsDouble(other);
514
            return new QuantityPy(new Quantity(a->pow(b)));
515
        }
516
        if (PyLong_Check(other)) {
517
            Base::Quantity* a = static_cast<QuantityPy*>(self)->getQuantityPtr();
518
            double b = (double)PyLong_AsLong(other);
519
            return new QuantityPy(new Quantity(a->pow(b)));
520
        }
521
        PyErr_SetString(PyExc_TypeError, "Expected quantity or number");
522
        return nullptr;
523
    }
524
    PY_CATCH
525
}
526

527
int QuantityPy::number_nonzero_handler(PyObject* self)
528
{
529
    if (!PyObject_TypeCheck(self, &(QuantityPy::Type))) {
530
        return 1;
531
    }
532

533
    Base::Quantity* a = static_cast<QuantityPy*>(self)->getQuantityPtr();
534
    return a->getValue() != 0.0;
535
}
536

537
PyObject* QuantityPy::richCompare(PyObject* v, PyObject* w, int op)
538
{
539
    if (PyObject_TypeCheck(v, &(QuantityPy::Type)) && PyObject_TypeCheck(w, &(QuantityPy::Type))) {
540
        const Quantity* u1 = static_cast<QuantityPy*>(v)->getQuantityPtr();
541
        const Quantity* u2 = static_cast<QuantityPy*>(w)->getQuantityPtr();
542

543
        PyObject* res = nullptr;
544
        switch (op) {
545
            case Py_NE:
546
                res = (!(*u1 == *u2)) ? Py_True : Py_False;
547
                Py_INCREF(res);
548
                return res;
549
            case Py_LT:
550
                res = (*u1 < *u2) ? Py_True : Py_False;
551
                Py_INCREF(res);
552
                return res;
553
            case Py_LE:
554
                res = (*u1 < *u2) || (*u1 == *u2) ? Py_True : Py_False;
555
                Py_INCREF(res);
556
                return res;
557
            case Py_GT:
558
                res = (!(*u1 < *u2)) && (!(*u1 == *u2)) ? Py_True : Py_False;
559
                Py_INCREF(res);
560
                return res;
561
            case Py_GE:
562
                res = (!(*u1 < *u2)) ? Py_True : Py_False;
563
                Py_INCREF(res);
564
                return res;
565
            case Py_EQ:
566
                res = (*u1 == *u2) ? Py_True : Py_False;
567
                Py_INCREF(res);
568
                return res;
569
        }
570
    }
571
    else if (PyNumber_Check(v) && PyNumber_Check(w)) {
572
        // Try to get floating numbers
573
        double u1 = PyFloat_AsDouble(v);
574
        double u2 = PyFloat_AsDouble(w);
575
        PyObject* res = nullptr;
576
        switch (op) {
577
            case Py_NE:
578
                res = (u1 != u2) ? Py_True : Py_False;
579
                Py_INCREF(res);
580
                return res;
581
            case Py_LT:
582
                res = (u1 < u2) ? Py_True : Py_False;
583
                Py_INCREF(res);
584
                return res;
585
            case Py_LE:
586
                res = (u1 <= u2) ? Py_True : Py_False;
587
                Py_INCREF(res);
588
                return res;
589
            case Py_GT:
590
                res = (u1 > u2) ? Py_True : Py_False;
591
                Py_INCREF(res);
592
                return res;
593
            case Py_GE:
594
                res = (u1 >= u2) ? Py_True : Py_False;
595
                Py_INCREF(res);
596
                return res;
597
            case Py_EQ:
598
                res = (u1 == u2) ? Py_True : Py_False;
599
                Py_INCREF(res);
600
                return res;
601
        }
602
    }
603

604
    // This always returns False
605
    Py_INCREF(Py_NotImplemented);
606
    return Py_NotImplemented;
607
}
608

609
Py::Float QuantityPy::getValue() const
610
{
611
    return Py::Float(getQuantityPtr()->getValue());
612
}
613

614
void QuantityPy::setValue(Py::Float arg)
615
{
616
    getQuantityPtr()->setValue(arg);
617
}
618

619
Py::Object QuantityPy::getUnit() const
620
{
621
    return Py::asObject(new UnitPy(new Unit(getQuantityPtr()->getUnit())));
622
}
623

624
void QuantityPy::setUnit(Py::Object arg)
625
{
626
    Py::Type UnitType(Base::getTypeAsObject(&Base::UnitPy::Type));
627
    if (!arg.isType(UnitType)) {
628
        throw Py::AttributeError("Not yet implemented");
629
    }
630

631
    getQuantityPtr()->setUnit(*static_cast<Base::UnitPy*>((*arg))->getUnitPtr());
632
}
633

634
Py::String QuantityPy::getUserString() const
635
{
636
    return {getQuantityPtr()->getUserString().toUtf8(), "utf-8"};
637
}
638

639
Py::Dict QuantityPy::getFormat() const
640
{
641
    QuantityFormat fmt = getQuantityPtr()->getFormat();
642

643
    Py::Dict dict;
644
    dict.setItem("Precision", Py::Int(fmt.precision));
645
    dict.setItem("NumberFormat", Py::Char(fmt.toFormat()));
646
    dict.setItem("Denominator", Py::Int(fmt.denominator));
647
    return dict;
648
}
649

650
void QuantityPy::setFormat(Py::Dict arg)
651
{
652
    QuantityFormat fmt = getQuantityPtr()->getFormat();
653

654
    if (arg.hasKey("Precision")) {
655
        Py::Int prec(arg.getItem("Precision"));
656
        fmt.precision = static_cast<int>(prec);
657
    }
658

659
    if (arg.hasKey("NumberFormat")) {
660
        Py::Object item = arg.getItem("NumberFormat");
661
        if (item.isNumeric()) {
662
            int format = static_cast<int>(Py::Int(item));
663
            if (format < 0 || format > QuantityFormat::Scientific) {
664
                throw Py::ValueError("Invalid format value");
665
            }
666
            fmt.format = static_cast<QuantityFormat::NumberFormat>(format);
667
        }
668
        else {
669
            Py::Char form(item);
670
            std::string fmtstr = static_cast<std::string>(Py::String(form));
671
            if (fmtstr.size() != 1) {
672
                throw Py::ValueError("Invalid format character");
673
            }
674

675
            bool ok = false;
676
            fmt.format = Base::QuantityFormat::toFormat(fmtstr[0], &ok);
677
            if (!ok) {
678
                throw Py::ValueError("Invalid format character");
679
            }
680
        }
681
    }
682

683
    if (arg.hasKey("Denominator")) {
684
        Py::Int denom(arg.getItem("Denominator"));
685
        int fracInch = static_cast<int>(denom);
686
        // check that the value is positive and a power of 2
687
        if (fracInch <= 0) {
688
            throw Py::ValueError("Denominator must be higher than zero");
689
        }
690
        // bitwise check
691
        if (fracInch & (fracInch - 1)) {
692
            throw Py::ValueError("Denominator must be a power of two");
693
        }
694
        fmt.denominator = fracInch;
695
    }
696

697
    getQuantityPtr()->setFormat(fmt);
698
}
699

700
PyObject* QuantityPy::getCustomAttributes(const char* attr) const
701
{
702
    QuantityPy* py = nullptr;
703
    if (strcmp(attr, "Torr") == 0) {
704
        py = new QuantityPy(new Quantity(Quantity::Torr));
705
    }
706
    else if (strcmp(attr, "mTorr") == 0) {
707
        py = new QuantityPy(new Quantity(Quantity::mTorr));
708
    }
709
    else if (strcmp(attr, "yTorr") == 0) {
710
        py = new QuantityPy(new Quantity(Quantity::yTorr));
711
    }
712
    else if (strcmp(attr, "PoundForce") == 0) {
713
        py = new QuantityPy(new Quantity(Quantity::PoundForce));
714
    }
715
    else if (strcmp(attr, "AngularMinute") == 0) {
716
        py = new QuantityPy(new Quantity(Quantity::AngMinute));
717
    }
718
    else if (strcmp(attr, "AngularSecond") == 0) {
719
        py = new QuantityPy(new Quantity(Quantity::AngSecond));
720
    }
721

722
    if (py) {
723
        py->setNotTracking();
724
    }
725

726
    return py;
727
}
728

729
int QuantityPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
730
{
731
    return 0;
732
}
733

734
PyObject* QuantityPy::number_invert_handler(PyObject* /*self*/)
735
{
736
    PyErr_SetString(PyExc_TypeError, "bad operand type for unary ~");
737
    return nullptr;
738
}
739

740
PyObject* QuantityPy::number_lshift_handler(PyObject* /*self*/, PyObject* /*other*/)
741
{
742
    PyErr_SetString(PyExc_TypeError, "unsupported operand type(s) for <<");
743
    return nullptr;
744
}
745

746
PyObject* QuantityPy::number_rshift_handler(PyObject* /*self*/, PyObject* /*other*/)
747
{
748
    PyErr_SetString(PyExc_TypeError, "unsupported operand type(s) for >>");
749
    return nullptr;
750
}
751

752
PyObject* QuantityPy::number_and_handler(PyObject* /*self*/, PyObject* /*other*/)
753
{
754
    PyErr_SetString(PyExc_TypeError, "unsupported operand type(s) for &");
755
    return nullptr;
756
}
757

758
PyObject* QuantityPy::number_xor_handler(PyObject* /*self*/, PyObject* /*other*/)
759
{
760
    PyErr_SetString(PyExc_TypeError, "unsupported operand type(s) for ^");
761
    return nullptr;
762
}
763

764
PyObject* QuantityPy::number_or_handler(PyObject* /*self*/, PyObject* /*other*/)
765
{
766
    PyErr_SetString(PyExc_TypeError, "unsupported operand type(s) for |");
767
    return nullptr;
768
}
769

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.