/******************************************************************************** * * * 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 . * * * ********************************************************************************/ #include #include #include #include #include "../ifcparse/IfcParse.h" #include "../ifcparse/IfcWrite.h" #include "../ifcparse/IfcCharacterDecoder.h" #include "../ifcparse/IfcFile.h" #ifdef USE_IFC4 #include "../ifcparse/Ifc4-latebound.h" #else #include "../ifcparse/Ifc2x3-latebound.h" #endif using namespace IfcWrite; class SizeVisitor : public boost::static_visitor { 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 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& i) const { return (int)i.size(); } int operator()(const std::vector& i) const { return (int)i.size(); } int operator()(const std::vector< std::vector >& i) const { return (int)i.size(); } int operator()(const std::vector< std::vector >& i) const { return (int)i.size(); } int operator()(const std::vector& 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 IfcEntityList::ptr& i) const { return i->size(); } int operator()(const IfcEntityListList::ptr& i) const { return i->size(); } }; class StringBuilderVisitor : public boost::static_visitor { private: StringBuilderVisitor(const StringBuilderVisitor&); //N/A StringBuilderVisitor& operator =(const StringBuilderVisitor&); //N/A std::ostringstream& data; template void serialize(const std::vector& i) { data << "("; for (typename std::vector::const_iterator it = i.begin(); it != i.end(); ++it) { if (it != i.begin()) data << ","; data << *it; } data << ")"; } // 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::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(); } 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; 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 double& i) { data << format_double(i); } void operator()(const boost::dynamic_bitset<>& i) { data << format_binary(i); } void operator()(const std::string& i) { std::string s = i; if (upper) { data << static_cast(IfcCharacterEncoder(s)); } else { data << '\'' << s << '\''; } } void operator()(const std::vector& i); void operator()(const std::vector& i); void operator()(const std::vector& i); void operator()(const std::vector< boost::dynamic_bitset<> >& i); void operator()(const IfcWriteArgument::EnumerationReference& i) { data << "." << i.enumeration_value << "."; } void operator()(const IfcUtil::IfcBaseClass* const& i) { IfcEntityInstanceData* e = i->entity; if ( IfcSchema::Type::IsSimple(e->type()) ) { data << e->toString(upper); } else { data << "#" << e->id(); } } void operator()(const IfcEntityList::ptr& i) { data << "("; for (IfcEntityList::it it = i->begin(); it != i->end(); ++it) { if (it != i->begin()) data << ","; (*this)(*it); } data << ")"; } void operator()(const std::vector< std::vector >& i); void operator()(const std::vector< std::vector >& i); void operator()(const IfcEntityListList::ptr& i) { data << "("; for (IfcEntityListList::outer_it outer_it = i->begin(); outer_it != i->end(); ++outer_it) { if (outer_it != i->begin()) data << ","; data << "("; for (IfcEntityListList::inner_it inner_it = outer_it->begin(); inner_it != outer_it->end(); ++inner_it) { if (inner_it != outer_it->begin()) data << ","; (*this)(*inner_it); } data << ")"; } data << ")"; } 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(); } }; template <> void StringBuilderVisitor::serialize(const std::vector& i) { data << "("; for (std::vector::const_iterator it = i.begin(); it != i.end(); ++it) { if (it != i.begin()) data << ","; std::string s = IfcCharacterEncoder(*it); data << s; } data << ")"; } template <> void StringBuilderVisitor::serialize(const std::vector& i) { data << "("; for (std::vector::const_iterator it = i.begin(); it != i.end(); ++it) { if (it != i.begin()) data << ","; data << format_double(*it); } data << ")"; } template <> void StringBuilderVisitor::serialize(const std::vector< boost::dynamic_bitset<> >& i) { data << "("; for (std::vector< boost::dynamic_bitset<> >::const_iterator it = i.begin(); it != i.end(); ++it) { if (it != i.begin()) data << ","; data << format_binary(*it); } data << ")"; } void StringBuilderVisitor::operator()(const std::vector& i) { serialize(i); } void StringBuilderVisitor::operator()(const std::vector& i) { serialize(i); } void StringBuilderVisitor::operator()(const std::vector& i) { serialize(i); } void StringBuilderVisitor::operator()(const std::vector< boost::dynamic_bitset<> >& i) { serialize(i); } void StringBuilderVisitor::operator()(const std::vector< std::vector >& i) { data << "("; for (std::vector< std::vector >::const_iterator it = i.begin(); it != i.end(); ++it) { if (it != i.begin()) data << ","; serialize(*it); } data << ")"; } void StringBuilderVisitor::operator()(const std::vector< std::vector >& i) { data << "("; for (std::vector< std::vector >::const_iterator it = i.begin(); it != i.end(); ++it) { if (it != i.begin()) data << ","; serialize(*it); } data << ")"; } IfcWriteArgument::operator int() const { return as(); } IfcWriteArgument::operator bool() const { return as(); } IfcWriteArgument::operator double() const { return as(); } IfcWriteArgument::operator std::string() const { if (type() == IfcUtil::Argument_ENUMERATION) { return as().enumeration_value; } return as(); } IfcWriteArgument::operator IfcUtil::IfcBaseClass*() const { return as(); } IfcWriteArgument::operator boost::dynamic_bitset<>() const { return as< boost::dynamic_bitset<> >(); } IfcWriteArgument::operator std::vector() const { return as >(); } IfcWriteArgument::operator std::vector() const { return as >(); } IfcWriteArgument::operator std::vector() const { return as >(); } IfcWriteArgument::operator std::vector< boost::dynamic_bitset<> >() const { return as< std::vector< boost::dynamic_bitset<> > >(); } IfcWriteArgument::operator IfcEntityList::ptr() const { return as(); } IfcWriteArgument::operator std::vector< std::vector >() const { return as > >(); } IfcWriteArgument::operator std::vector< std::vector >() const { return as > >(); } IfcWriteArgument::operator IfcEntityListList::ptr() const { return as(); } bool IfcWriteArgument::isNull() const { return type() == IfcUtil::Argument_NULL; } Argument* IfcWriteArgument::operator [] (unsigned int /*i*/) const { throw IfcParse::IfcException("Invalid cast"); } std::string IfcWriteArgument::toString(bool upper) const { std::ostringstream str; str.imbue(std::locale::classic()); StringBuilderVisitor v(str, upper); container.apply_visitor(v); return v; } unsigned int IfcWriteArgument::size() const { SizeVisitor v; const int size = container.apply_visitor(v); if (size == -1) { throw IfcParse::IfcException("Invalid cast"); } else { return size; } } IfcUtil::ArgumentType IfcWriteArgument::type() const { return static_cast(container.which()); } // Overload to detect null values void IfcWriteArgument::set(const IfcEntityList::ptr& v) { if (v) { container = v; } else { container = boost::blank(); } } // Overload to detect null values void IfcWriteArgument::set(const IfcEntityListList::ptr& v) { if (v) { container = v; } else { container = boost::blank(); } } // Overload to detect null values void IfcWriteArgument::set(IfcUtil::IfcBaseClass*const& v) { if (v) { container = v; } else { container = boost::blank(); } }