Files
IfcOpenShell/src/ifcparse/IfcWrite.cpp
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

318 lines
13 KiB
C++
Raw Normal View History

/********************************************************************************
2012-07-19 13:07:55 +00:00
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
2023-09-17 12:30:17 +02:00
#include "IfcWrite.h"
2014-06-11 10:24:11 +00:00
2023-09-17 12:30:17 +02:00
#include "IfcCharacterDecoder.h"
2023-09-17 12:30:17 +02:00
#include <boost/algorithm/string.hpp>
#include <iomanip>
#include <limits>
#include <locale>
2012-07-19 13:07:55 +00:00
using namespace IfcWrite;
class SizeVisitor : public boost::static_visitor<int> {
2023-09-17 12:30:17 +02:00
public:
int operator()(const boost::blank& /*i*/) const { return -1; }
int operator()(const IfcWriteArgument::Derived& /*i*/) const { return -1; }
int operator()(const int& /*i*/) const { return -1; }
int operator()(const bool& /*i*/) const { return -1; }
int operator()(const boost::logic::tribool& /*i*/) const { return -1; }
int operator()(const double& /*i*/) const { return -1; }
int operator()(const std::string& /*i*/) const { return -1; }
int operator()(const boost::dynamic_bitset<>& /*i*/) const { return -1; }
int operator()(const IfcWriteArgument::empty_aggregate_t&) const { return 0; }
int operator()(const IfcWriteArgument::empty_aggregate_of_aggregate_t&) const { return 0; }
int operator()(const std::vector<int>& i) const { return (int)i.size(); }
int operator()(const std::vector<double>& i) const { return (int)i.size(); }
int operator()(const std::vector<std::vector<int>>& i) const { return (int)i.size(); }
int operator()(const std::vector<std::vector<double>>& i) const { return (int)i.size(); }
int operator()(const std::vector<std::string>& i) const { return (int)i.size(); }
int operator()(const std::vector<boost::dynamic_bitset<>>& i) const { return (int)i.size(); }
int operator()(const IfcWriteArgument::EnumerationReference& /*i*/) const { return -1; }
int operator()(const IfcUtil::IfcBaseClass* const& /*i*/) const { return -1; }
int operator()(const aggregate_of_instance::ptr& i) const { return i->size(); }
int operator()(const aggregate_of_aggregate_of_instance::ptr& i) const { return i->size(); }
};
class StringBuilderVisitor : public boost::static_visitor<void> {
2023-09-17 12:30:17 +02:00
private:
StringBuilderVisitor(const StringBuilderVisitor&); //N/A
StringBuilderVisitor& operator=(const StringBuilderVisitor&); //N/A
std::ostringstream& data_;
2023-09-17 12:30:17 +02:00
template <typename T>
void serialize(const std::vector<T>& i) {
data_ << "(";
2023-09-17 12:30:17 +02:00
for (typename std::vector<T>::const_iterator it = i.begin(); it != i.end(); ++it) {
if (it != i.begin()) {
data_ << ",";
2023-09-17 12:30:17 +02:00
}
data_ << *it;
2023-09-17 12:30:17 +02:00
}
data_ << ")";
2023-09-17 12:30:17 +02:00
}
// The REAL token definition from the IFC SPF standard does not necessarily match
// the output of the C++ ostream formatting operation.
// REAL = [ SIGN ] DIGIT { DIGIT } "." { DIGIT } [ "E" [ SIGN ] DIGIT { DIGIT } ] .
std::string format_double(const double& d) {
std::ostringstream oss;
oss.imbue(std::locale::classic());
oss << std::setprecision(std::numeric_limits<double>::digits10) << d;
const std::string str = oss.str();
oss.str("");
std::string::size_type e = str.find('e');
if (e == std::string::npos) {
e = str.find('E');
}
const std::string mantissa = str.substr(0, e);
oss << mantissa;
if (mantissa.find('.') == std::string::npos) {
oss << ".";
}
if (e != std::string::npos) {
oss << "E";
oss << str.substr(e + 1);
}
return oss.str();
}
2023-09-17 12:30:17 +02:00
std::string format_binary(const boost::dynamic_bitset<>& b) {
std::ostringstream oss;
oss.imbue(std::locale::classic());
oss.put('"');
oss << std::hex << std::setw(1);
unsigned c = (unsigned)b.size();
unsigned n = (4 - (c % 4)) & 3;
oss << n;
for (unsigned i = 0; i < c + n;) {
unsigned accum = 0;
for (int j = 0; j < 4; ++j, ++i) {
unsigned bit = i < n ? 0 : b.test(c - i + n - 1) ? 1
: 0;
accum |= bit << (3 - j);
}
oss << accum;
}
oss.put('"');
return oss.str();
}
bool upper_;
2023-09-17 12:30:17 +02:00
public:
StringBuilderVisitor(std::ostringstream& stream, bool upper = false)
: data_(stream),
upper_(upper) {}
void operator()(const boost::blank& /*i*/) { data_ << "$"; }
void operator()(const IfcWriteArgument::Derived& /*i*/) { data_ << "*"; }
void operator()(const int& i) { data_ << i; }
void operator()(const bool& i) { data_ << (i ? ".T." : ".F."); }
void operator()(const boost::logic::tribool& i) { data_ << (i ? ".T." : (boost::logic::indeterminate(i) ? ".U." : ".F.")); }
void operator()(const double& i) { data_ << format_double(i); }
void operator()(const boost::dynamic_bitset<>& i) { data_ << format_binary(i); }
2023-09-17 12:30:17 +02:00
void operator()(const std::string& i) {
std::string s = i;
if (upper_) {
data_ << static_cast<std::string>(IfcCharacterEncoder(s));
2023-09-17 12:30:17 +02:00
} else {
data_ << '\'' << s << '\'';
2023-09-17 12:30:17 +02:00
}
}
void operator()(const std::vector<int>& i);
void operator()(const std::vector<double>& i);
void operator()(const std::vector<std::string>& i);
void operator()(const std::vector<boost::dynamic_bitset<>>& i);
void operator()(const IfcWriteArgument::EnumerationReference& i) {
data_ << "." << i.enumeration_value << ".";
2023-09-17 12:30:17 +02:00
}
void operator()(const IfcUtil::IfcBaseClass* const& i) {
const IfcEntityInstanceData& e = i->data();
if (e.type()->as_entity() == nullptr) {
data_ << e.toString(upper_);
2023-09-17 12:30:17 +02:00
} else {
data_ << "#" << e.id();
2023-09-17 12:30:17 +02:00
}
}
void operator()(const aggregate_of_instance::ptr& i) {
data_ << "(";
2023-09-17 12:30:17 +02:00
for (aggregate_of_instance::it it = i->begin(); it != i->end(); ++it) {
if (it != i->begin()) {
data_ << ",";
2023-09-17 12:30:17 +02:00
}
(*this)(*it);
}
data_ << ")";
2023-09-17 12:30:17 +02:00
}
void operator()(const std::vector<std::vector<int>>& i);
void operator()(const std::vector<std::vector<double>>& i);
void operator()(const aggregate_of_aggregate_of_instance::ptr& i) {
data_ << "(";
2023-09-17 12:30:17 +02:00
for (aggregate_of_aggregate_of_instance::outer_it outer_it = i->begin(); outer_it != i->end(); ++outer_it) {
if (outer_it != i->begin()) {
data_ << ",";
2023-09-17 12:30:17 +02:00
}
data_ << "(";
2023-09-17 12:30:17 +02:00
for (aggregate_of_aggregate_of_instance::inner_it inner_it = outer_it->begin(); inner_it != outer_it->end(); ++inner_it) {
if (inner_it != outer_it->begin()) {
data_ << ",";
2023-09-17 12:30:17 +02:00
}
(*this)(*inner_it);
}
data_ << ")";
2023-09-17 12:30:17 +02:00
}
data_ << ")";
2023-09-17 12:30:17 +02:00
}
void operator()(const IfcWriteArgument::empty_aggregate_t&) const { data_ << "()"; }
void operator()(const IfcWriteArgument::empty_aggregate_of_aggregate_t&) const { data_ << "()"; }
operator std::string() { return data_.str(); }
};
2015-01-16 16:26:40 +00:00
template <>
void StringBuilderVisitor::serialize(const std::vector<std::string>& i) {
data_ << "(";
2023-09-17 12:30:17 +02:00
for (std::vector<std::string>::const_iterator it = i.begin(); it != i.end(); ++it) {
if (it != i.begin()) {
data_ << ",";
2023-09-17 12:30:17 +02:00
}
std::string encoder = IfcCharacterEncoder(*it);
data_ << encoder;
2023-09-17 12:30:17 +02:00
}
data_ << ")";
2015-01-16 16:26:40 +00:00
}
template <>
void StringBuilderVisitor::serialize(const std::vector<double>& i) {
data_ << "(";
2023-09-17 12:30:17 +02:00
for (std::vector<double>::const_iterator it = i.begin(); it != i.end(); ++it) {
if (it != i.begin()) {
data_ << ",";
2023-09-17 12:30:17 +02:00
}
data_ << format_double(*it);
2023-09-17 12:30:17 +02:00
}
data_ << ")";
2015-01-16 16:26:40 +00:00
}
template <>
2023-09-17 12:30:17 +02:00
void StringBuilderVisitor::serialize(const std::vector<boost::dynamic_bitset<>>& i) {
data_ << "(";
2023-09-17 12:30:17 +02:00
for (std::vector<boost::dynamic_bitset<>>::const_iterator it = i.begin(); it != i.end(); ++it) {
if (it != i.begin()) {
data_ << ",";
2023-09-17 12:30:17 +02:00
}
data_ << format_binary(*it);
2023-09-17 12:30:17 +02:00
}
data_ << ")";
}
2015-01-16 16:26:40 +00:00
void StringBuilderVisitor::operator()(const std::vector<int>& i) { serialize(i); }
void StringBuilderVisitor::operator()(const std::vector<double>& i) { serialize(i); }
void StringBuilderVisitor::operator()(const std::vector<std::string>& i) { serialize(i); }
2023-09-17 12:30:17 +02:00
void StringBuilderVisitor::operator()(const std::vector<boost::dynamic_bitset<>>& i) { serialize(i); }
void StringBuilderVisitor::operator()(const std::vector<std::vector<int>>& i) {
data_ << "(";
2023-09-17 12:30:17 +02:00
for (std::vector<std::vector<int>>::const_iterator it = i.begin(); it != i.end(); ++it) {
if (it != i.begin()) {
data_ << ",";
2023-09-17 12:30:17 +02:00
}
serialize(*it);
}
data_ << ")";
}
2023-09-17 12:30:17 +02:00
void StringBuilderVisitor::operator()(const std::vector<std::vector<double>>& i) {
data_ << "(";
2023-09-17 12:30:17 +02:00
for (std::vector<std::vector<double>>::const_iterator it = i.begin(); it != i.end(); ++it) {
if (it != i.begin()) {
data_ << ",";
2023-09-17 12:30:17 +02:00
}
serialize(*it);
}
data_ << ")";
}
2015-01-16 16:26:40 +00:00
IfcWriteArgument::operator int() const { return as<int>(); }
IfcWriteArgument::operator bool() const { return as<bool>(); }
2021-07-29 16:32:45 +02:00
IfcWriteArgument::operator boost::logic::tribool() const { return as<boost::logic::tribool>(); }
IfcWriteArgument::operator double() const { return as<double>(); }
2023-09-17 12:30:17 +02:00
IfcWriteArgument::operator std::string() const {
if (type() == IfcUtil::Argument_ENUMERATION) {
return as<EnumerationReference>().enumeration_value;
}
return as<std::string>();
}
IfcWriteArgument::operator IfcUtil::IfcBaseClass*() const { return as<IfcUtil::IfcBaseClass*>(); }
2023-09-17 12:30:17 +02:00
IfcWriteArgument::operator boost::dynamic_bitset<>() const { return as<boost::dynamic_bitset<>>(); }
IfcWriteArgument::operator std::vector<double>() const { return as<std::vector<double>>(); }
IfcWriteArgument::operator std::vector<int>() const { return as<std::vector<int>>(); }
IfcWriteArgument::operator std::vector<std::string>() const { return as<std::vector<std::string>>(); }
IfcWriteArgument::operator std::vector<boost::dynamic_bitset<>>() const { return as<std::vector<boost::dynamic_bitset<>>>(); }
2021-07-29 14:54:51 +02:00
IfcWriteArgument::operator aggregate_of_instance::ptr() const { return as<aggregate_of_instance::ptr>(); }
2023-09-17 12:30:17 +02:00
IfcWriteArgument::operator std::vector<std::vector<int>>() const { return as<std::vector<std::vector<int>>>(); }
IfcWriteArgument::operator std::vector<std::vector<double>>() const { return as<std::vector<std::vector<double>>>(); }
2021-07-29 14:54:51 +02:00
IfcWriteArgument::operator aggregate_of_aggregate_of_instance::ptr() const { return as<aggregate_of_aggregate_of_instance::ptr>(); }
bool IfcWriteArgument::isNull() const { return type() == IfcUtil::Argument_NULL; }
2023-09-17 12:30:17 +02:00
Argument* IfcWriteArgument::operator[](unsigned int /*i*/) const { throw IfcParse::IfcException("Invalid cast"); }
std::string IfcWriteArgument::toString(bool upper) const {
2023-09-17 12:30:17 +02:00
std::ostringstream str;
str.imbue(std::locale::classic());
StringBuilderVisitor visitor(str, upper);
container_.apply_visitor(visitor);
return visitor;
}
2015-01-10 22:13:52 +00:00
unsigned int IfcWriteArgument::size() const {
SizeVisitor visitor;
const int size = container_.apply_visitor(visitor);
2023-09-17 12:30:17 +02:00
if (size == -1) {
throw IfcParse::IfcException("Invalid cast");
}
return size;
}
2012-07-19 13:07:55 +00:00
IfcUtil::ArgumentType IfcWriteArgument::type() const {
return static_cast<IfcUtil::ArgumentType>(container_.which());
}
2017-06-05 17:26:58 +02:00
// Overload to detect null values
void IfcWriteArgument::set(const aggregate_of_instance::ptr& value) {
if (value) {
container_ = value;
2023-09-17 12:30:17 +02:00
} else {
container_ = boost::blank();
2023-09-17 12:30:17 +02:00
}
}
2017-06-05 17:26:58 +02:00
// Overload to detect null values
void IfcWriteArgument::set(const aggregate_of_aggregate_of_instance::ptr& value) {
if (value) {
container_ = value;
2023-09-17 12:30:17 +02:00
} else {
container_ = boost::blank();
2023-09-17 12:30:17 +02:00
}
}
2017-06-05 17:26:58 +02:00
// Overload to detect null values
void IfcWriteArgument::set(IfcUtil::IfcBaseInterface* const& value) {
if (value != nullptr) {
container_ = value->as<IfcUtil::IfcBaseClass>();
2023-09-17 12:30:17 +02:00
} else {
container_ = boost::blank();
2023-09-17 12:30:17 +02:00
}
}