ifcparse refactoring (#190)

Unify attribute containers, provide latebound attribute access on IfcBaseEntity, more basic tests on Travis
This commit is contained in:
Thomas Krijnen
2017-06-05 17:26:58 +02:00
committed by GitHub
parent 9a43658716
commit 5e0da9725a
49 changed files with 9228 additions and 9416 deletions
+94
View File
@@ -0,0 +1,94 @@
/********************************************************************************
* *
* 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/>. *
* *
********************************************************************************/
#ifndef ARGUMENT_H
#define ARGUMENT_H
#include <set>
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>
#include "ifc_parse_api.h"
#ifdef USE_IFC4
#include "../ifcparse/Ifc4enum.h"
#else
#include "../ifcparse/Ifc2x3enum.h"
#endif
#include "../ifcparse/IfcEntityList.h"
#include <boost/shared_ptr.hpp>
#include <boost/dynamic_bitset.hpp>
#include <boost/foreach.hpp>
#define foreach BOOST_FOREACH
#define rforeach BOOST_REVERSE_FOREACH
class Argument;
class IfcEntityList;
class IfcEntityListList;
class IfcEntityInstanceData;
namespace IfcParse {
class IfcFile;
}
namespace IfcUtil {
class IfcBaseClass;
IFC_PARSE_API const char* ArgumentTypeToString(ArgumentType argument_type);
IFC_PARSE_API bool valid_binary_string(const std::string& s);
/// Replaces spaces and potentially other problem causing characters with underscores.
IFC_PARSE_API void sanitate_material_name(std::string &str);
IFC_PARSE_API void escape_xml(std::string &str);
IFC_PARSE_API void unescape_xml(std::string &str);
}
class IFC_PARSE_API Argument {
public:
virtual operator int() const;
virtual operator bool() const;
virtual operator double() const;
virtual operator std::string() const;
virtual operator boost::dynamic_bitset<>() const;
virtual operator IfcUtil::IfcBaseClass*() const;
virtual operator std::vector<int>() const;
virtual operator std::vector<double>() const;
virtual operator std::vector<std::string>() const;
virtual operator std::vector<boost::dynamic_bitset<> >() const;
virtual operator IfcEntityList::ptr() const;
virtual operator std::vector< std::vector<int> >() const;
virtual operator std::vector< std::vector<double> >() const;
virtual operator IfcEntityListList::ptr() const;
virtual bool isNull() const = 0;
virtual unsigned int size() const = 0;
virtual IfcUtil::ArgumentType type() const = 0;
virtual Argument* operator [] (unsigned int i) const = 0;
virtual std::string toString(bool upper=false) const = 0;
virtual ~Argument() {};
};
#endif
+53
View File
@@ -0,0 +1,53 @@
/********************************************************************************
* *
* 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/>. *
* *
********************************************************************************/
#ifndef ARGUMENTTYPE_H
#define ARGUMENTTYPE_H
namespace IfcUtil {
enum ArgumentType {
Argument_NULL,
Argument_DERIVED,
Argument_INT,
Argument_BOOL,
Argument_DOUBLE,
Argument_STRING,
Argument_BINARY,
Argument_ENUMERATION,
Argument_ENTITY_INSTANCE,
Argument_EMPTY_AGGREGATE,
Argument_AGGREGATE_OF_INT,
Argument_AGGREGATE_OF_DOUBLE,
Argument_AGGREGATE_OF_STRING,
Argument_AGGREGATE_OF_BINARY,
Argument_AGGREGATE_OF_ENTITY_INSTANCE,
Argument_AGGREGATE_OF_EMPTY_AGGREGATE,
Argument_AGGREGATE_OF_AGGREGATE_OF_INT,
Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE,
Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE,
Argument_UNKNOWN
};
}
#endif
+11 -12
View File
@@ -17,14 +17,12 @@
* *
********************************************************************************/
/********************************************************************************************
* *
* This file has been generated from *
* http://www.buildingsmart-tech.org/downloads/ifc/ifc2x3tc/IFC2X3_TC1_EXPRESS_longform.zip *
* Do not make modifications but instead modify the Python script that has been *
* used to generate this. *
* *
********************************************************************************************/
/********************************************************************************
* *
* This file has been generated from IFC2X3_TC1.exp. Do not make modifications *
* but instead modify the python script that has been used to generate this. *
* *
********************************************************************************/
#ifndef USE_IFC4
@@ -34,8 +32,7 @@
#include "../ifcparse/Ifc2x3-latebound.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcWrite.h"
#include "../ifcparse/IfcWritableEntity.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcEntityDescriptor.h"
using namespace Ifc2x3;
@@ -4296,12 +4293,14 @@ std::set<std::string> Type::GetInverseAttributeNames(Enum t) {
return return_value;
}
void Type::PopulateDerivedFields(IfcWrite::IfcWritableEntity* e) {
void Type::PopulateDerivedFields(IfcEntityInstanceData* e) {
if (derived_map.empty()) ::InitDerivedMap();
std::map<Type::Enum, std::set<int> >::const_iterator i = derived_map.find(e->type());
if (i != derived_map.end()) {
for (std::set<int>::const_iterator it = i->second.begin(); it != i->second.end(); ++it) {
e->setArgumentDerived(*it);
IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();
attr->set(IfcWrite::IfcWriteArgument::Derived());
e->setArgument(*it, attr);
}
}
}
+8 -11
View File
@@ -17,14 +17,12 @@
* *
********************************************************************************/
/********************************************************************************************
* *
* This file has been generated from *
* http://www.buildingsmart-tech.org/downloads/ifc/ifc2x3tc/IFC2X3_TC1_EXPRESS_longform.zip *
* Do not make modifications but instead modify the Python script that has been *
* used to generate this. *
* *
********************************************************************************************/
/********************************************************************************
* *
* This file has been generated from IFC2X3_TC1.exp. Do not make modifications *
* but instead modify the python script that has been used to generate this. *
* *
********************************************************************************/
#ifndef IFC2X3RT_H
#define IFC2X3RT_H
@@ -32,9 +30,8 @@
#define IfcSchema Ifc2x3
#include "../ifcparse/ifc_parse_api.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcEntityDescriptor.h"
#include "../ifcparse/IfcWritableEntity.h"
namespace Ifc2x3 {
namespace Type {
@@ -48,7 +45,7 @@ namespace Type {
IFC_PARSE_API std::pair<const char*, int> GetEnumerationIndex(Enum t, const std::string& a);
IFC_PARSE_API std::pair<Enum, unsigned> GetInverseAttribute(Enum t, const std::string& a);
IFC_PARSE_API std::set<std::string> GetInverseAttributeNames(Enum t);
IFC_PARSE_API void PopulateDerivedFields(IfcWrite::IfcWritableEntity* e);
IFC_PARSE_API void PopulateDerivedFields(IfcEntityInstanceData* e);
}}
#endif
+2867 -2870
View File
File diff suppressed because one or more lines are too long
+781 -780
View File
File diff suppressed because it is too large Load Diff
+7 -8
View File
@@ -17,20 +17,19 @@
* *
********************************************************************************/
/********************************************************************************************
* *
* This file has been generated from *
* http://www.buildingsmart-tech.org/downloads/ifc/ifc2x3tc/IFC2X3_TC1_EXPRESS_longform.zip *
* Do not make modifications but instead modify the Python script that has been *
* used to generate this. *
* *
********************************************************************************************/
/********************************************************************************
* *
* This file has been generated from IFC2X3_TC1.exp. Do not make modifications *
* but instead modify the python script that has been used to generate this. *
* *
********************************************************************************/
#ifndef IFC2X3ENUM_H
#define IFC2X3ENUM_H
#include "../ifcparse/ifc_parse_api.h"
#include <string>
#include <boost/optional.hpp>
#define IfcSchema Ifc2x3
+7 -8
View File
@@ -19,10 +19,8 @@
/********************************************************************************
* *
* This file has been generated from *
* http://www.buildingsmart-tech.org/ifc/IFC4/Add1/IFC4_ADD1.exp *
* Do not make modifications but instead modify the Python script that has been *
* used to generate this. *
* This file has been generated from IFC4.exp. Do not make modifications *
* but instead modify the python script that has been used to generate this. *
* *
********************************************************************************/
@@ -34,8 +32,7 @@
#include "../ifcparse/Ifc4-latebound.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcWrite.h"
#include "../ifcparse/IfcWritableEntity.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcEntityDescriptor.h"
using namespace Ifc4;
@@ -5013,12 +5010,14 @@ std::set<std::string> Type::GetInverseAttributeNames(Enum t) {
return return_value;
}
void Type::PopulateDerivedFields(IfcWrite::IfcWritableEntity* e) {
void Type::PopulateDerivedFields(IfcEntityInstanceData* e) {
if (derived_map.empty()) ::InitDerivedMap();
std::map<Type::Enum, std::set<int> >::const_iterator i = derived_map.find(e->type());
if (i != derived_map.end()) {
for (std::set<int>::const_iterator it = i->second.begin(); it != i->second.end(); ++it) {
e->setArgumentDerived(*it);
IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();
attr->set(IfcWrite::IfcWriteArgument::Derived());
e->setArgument(*it, attr);
}
}
}
+4 -7
View File
@@ -19,10 +19,8 @@
/********************************************************************************
* *
* This file has been generated from *
* http://www.buildingsmart-tech.org/ifc/IFC4/Add1/IFC4_ADD1.exp *
* Do not make modifications but instead modify the Python script that has been *
* used to generate this. *
* This file has been generated from IFC4.exp. Do not make modifications *
* but instead modify the python script that has been used to generate this. *
* *
********************************************************************************/
@@ -32,9 +30,8 @@
#define IfcSchema Ifc4
#include "../ifcparse/ifc_parse_api.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcEntityDescriptor.h"
#include "../ifcparse/IfcWritableEntity.h"
namespace Ifc4 {
namespace Type {
@@ -48,7 +45,7 @@ namespace Type {
IFC_PARSE_API std::pair<const char*, int> GetEnumerationIndex(Enum t, const std::string& a);
IFC_PARSE_API std::pair<Enum, unsigned> GetInverseAttribute(Enum t, const std::string& a);
IFC_PARSE_API std::set<std::string> GetInverseAttributeNames(Enum t);
IFC_PARSE_API void PopulateDerivedFields(IfcWrite::IfcWritableEntity* e);
IFC_PARSE_API void PopulateDerivedFields(IfcEntityInstanceData* e);
}}
#endif
+3281 -3284
View File
File diff suppressed because one or more lines are too long
+906 -905
View File
File diff suppressed because it is too large Load Diff
+3 -4
View File
@@ -19,10 +19,8 @@
/********************************************************************************
* *
* This file has been generated from *
* http://www.buildingsmart-tech.org/ifc/IFC4/Add1/IFC4_ADD1.exp *
* Do not make modifications but instead modify the Python script that has been *
* used to generate this. *
* This file has been generated from IFC4.exp. Do not make modifications *
* but instead modify the python script that has been used to generate this. *
* *
********************************************************************************/
@@ -31,6 +29,7 @@
#include "../ifcparse/ifc_parse_api.h"
#include <string>
#include <boost/optional.hpp>
#define IfcSchema Ifc4
+84
View File
@@ -0,0 +1,84 @@
/********************************************************************************
* *
* 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/>. *
* *
********************************************************************************/
#ifndef IFCBASECLASS_H
#define IFCBASECLASS_H
#include "ifc_parse_api.h"
#ifdef USE_IFC4
#include "../ifcparse/Ifc4enum.h"
#else
#include "../ifcparse/Ifc2x3enum.h"
#endif
#include "../ifcparse/IfcEntityInstanceData.h"
class Argument;
namespace IfcUtil {
class IFC_PARSE_API IfcBaseClass {
public:
virtual ~IfcBaseClass() {}
IfcEntityInstanceData* entity;
virtual bool is(IfcSchema::Type::Enum v) const = 0;
virtual IfcSchema::Type::Enum type() const = 0;
virtual unsigned int getArgumentCount() const = 0;
virtual IfcUtil::ArgumentType getArgumentType(unsigned int i) const = 0;
virtual IfcSchema::Type::Enum getArgumentEntity(unsigned int i) const = 0;
virtual Argument* getArgument(unsigned int i) const = 0;
virtual const char* getArgumentName(unsigned int i) const = 0;
template <class T>
T* as() {
return is(T::Class())
? static_cast<T*>(this)
: static_cast<T*>(0);
}
template <class T>
const T* as() const {
return is(T::Class())
? static_cast<const T*>(this)
: static_cast<const T*>(0);
}
};
class IFC_PARSE_API IfcBaseEntity : public IfcBaseClass {
public:
Argument* getArgumentByName(const std::string& name) const;
std::vector<std::string> getAttributeNames() const;
std::vector<std::string> getInverseAttributeNames() const;
unsigned id() const { return entity->id(); }
};
// TODO: Investigate whether these should be template classes instead
class IFC_PARSE_API IfcBaseType : public IfcBaseEntity {
public:
unsigned int getArgumentCount() const;
Argument* getArgument(unsigned int i) const;
const char* getArgumentName(unsigned int i) const;
IfcSchema::Type::Enum getArgumentEntity(unsigned int /*i*/) const { return IfcSchema::Type::UNDEFINED; }
};
}
#endif
+1 -1
View File
@@ -28,7 +28,7 @@
#include <boost/shared_ptr.hpp>
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcException.h"
#ifdef USE_IFC4
+106
View File
@@ -0,0 +1,106 @@
/********************************************************************************
* *
* 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/>. *
* *
********************************************************************************/
#ifndef IFCENTITYINSTANCEDATA_H
#define IFCENTITYINSTANCEDATA_H
#include "../ifcparse/ArgumentType.h"
#include <boost/shared_ptr.hpp>
#include <vector>
class Argument;
class IfcEntityList;
namespace IfcParse {
class IfcFile;
}
class IFC_PARSE_API IfcEntityInstanceData {
public:
// Public for backwards compatibility
IfcParse::IfcFile* file;
protected:
unsigned id_;
IfcSchema::Type::Enum type_;
mutable std::vector<Argument*> attributes_;
// To reduce memory footprint, these two could potentially be combined,
// e.g. initialized_ <-> offset_in_file_ == 0, but it would imply that
// instances cannot be located at the beginning of the file. Officially
// there should be a header anyways.
mutable bool initialized_;
unsigned offset_in_file_;
void load_() const;
public:
IfcEntityInstanceData(IfcSchema::Type::Enum type, IfcParse::IfcFile* file_, unsigned id = 0, unsigned offset_in_file = 0)
: file(file_), id_(id), type_(type), initialized_(false), offset_in_file_(offset_in_file)
{}
IfcEntityInstanceData(IfcSchema::Type::Enum type)
: file(0), id_(0), type_(type), initialized_(true)
{}
/*
IfcEntityInstanceData(IfcParse::IfcFile* file = 0, unsigned id = 0, IfcSchema::Type::Enum type = IfcSchema::Type::UNDEFINED, unsigned offset_in_file = 0, size_t n)
: file_(file), id_(0), type_(type), initialized_(false)
{
attributes_.reserve(n);
}
IfcEntityInstanceData(IfcParse::IfcFile* file = 0, unsigned id = 0, IfcSchema::Type::Enum type = IfcSchema::Type::UNDEFINED, const std::vector<Argument*>& attributes)
: file_(file), id_(0), type_(type), attributes_(attributes), initialized_(true)
{}
*/
IfcEntityInstanceData(const IfcEntityInstanceData& e);
~IfcEntityInstanceData();
boost::shared_ptr<IfcEntityList> getInverse(IfcSchema::Type::Enum type, int attribute_index);
Argument* getArgument(unsigned int i) const;
// NB: This makes a copy of the argument
void setArgument(unsigned int i, Argument* a, IfcUtil::ArgumentType attr_type = IfcUtil::Argument_UNKNOWN);
unsigned int getArgumentCount() const {
if (!initialized_) {
load_();
}
return attributes_.size();
}
IfcSchema::Type::Enum type() const {
return type_;
}
std::string toString(bool upper = false) const;
unsigned int id() const { return id_; }
unsigned int offset_in_file() const { return offset_in_file_; }
// NB: const ommitted for lazy loading
std::vector<Argument*>& attributes() const { return attributes_; }
unsigned set_id(boost::optional<unsigned> i = boost::none);
};
#endif
+184
View File
@@ -0,0 +1,184 @@
/********************************************************************************
* *
* 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/>. *
* *
********************************************************************************/
#ifndef IFCENTITYLIST_H
#define IFCENTITYLIST_H
#include "../ifcparse/IfcBaseClass.h"
#include <boost/shared_ptr.hpp>
#include <set>
template <class T>
class IfcTemplatedEntityList;
class IFC_PARSE_API IfcEntityList {
std::vector<IfcUtil::IfcBaseClass*> ls;
public:
typedef boost::shared_ptr<IfcEntityList> ptr;
typedef std::vector<IfcUtil::IfcBaseClass*>::const_iterator it;
void push(IfcUtil::IfcBaseClass* l);
void push(const ptr& l);
it begin();
it end();
IfcUtil::IfcBaseClass* operator[] (int i);
unsigned int size() const;
bool contains(IfcUtil::IfcBaseClass*) const;
template <class U>
typename U::list::ptr as() {
typename U::list::ptr r(new typename U::list);
const bool all = U::Class() == IfcSchema::Type::UNDEFINED;
for (it i = begin(); i != end(); ++i) if (all || (*i)->is(U::Class())) r->push((U*)*i);
return r;
}
void remove(IfcUtil::IfcBaseClass*);
IfcEntityList::ptr filtered(const std::set<IfcSchema::Type::Enum>& entities);
};
template <class T>
class IfcTemplatedEntityList {
std::vector<T*> ls;
public:
typedef boost::shared_ptr< IfcTemplatedEntityList<T> > ptr;
typedef typename std::vector<T*>::const_iterator it;
void push(T* t) { if (t) { ls.push_back(t); } }
void push(ptr t) { if (t) { for (typename T::list::it it = t->begin(); it != t->end(); ++it) push(*it); } }
it begin() { return ls.begin(); }
it end() { return ls.end(); }
unsigned int size() const { return (unsigned int)ls.size(); }
IfcEntityList::ptr generalize() {
IfcEntityList::ptr r(new IfcEntityList());
for (it i = begin(); i != end(); ++i) r->push(*i);
return r;
}
bool contains(T* t) const { return std::find(ls.begin(), ls.end(), t) != ls.end(); }
template <class U>
typename U::list::ptr as() {
typename U::list::ptr r(new typename U::list);
const bool all = U::Class() == IfcSchema::Type::UNDEFINED;
for (it i = begin(); i != end(); ++i) if (all || (*i)->is(U::Class())) r->push((U*)*i);
return r;
}
void remove(T* t) {
typename std::vector<T*>::iterator it;
while ((it = std::find(ls.begin(), ls.end(), t)) != ls.end()) {
ls.erase(it);
}
}
};
template <class T>
class IfcTemplatedEntityListList;
class IFC_PARSE_API IfcEntityListList {
std::vector< std::vector<IfcUtil::IfcBaseClass*> > ls;
public:
typedef boost::shared_ptr< IfcEntityListList > ptr;
typedef std::vector< std::vector<IfcUtil::IfcBaseClass*> >::const_iterator outer_it;
typedef std::vector<IfcUtil::IfcBaseClass*>::const_iterator inner_it;
void push(const std::vector<IfcUtil::IfcBaseClass*>& l) {
ls.push_back(l);
}
void push(const IfcEntityList::ptr& l) {
if (l) {
std::vector<IfcUtil::IfcBaseClass*> li;
for (std::vector<IfcUtil::IfcBaseClass*>::const_iterator jt = l->begin(); jt != l->end(); ++jt) {
li.push_back(*jt);
}
push(li);
}
}
outer_it begin() const { return ls.begin(); }
outer_it end() const { return ls.end(); }
int size() const { return (int)ls.size(); }
int totalSize() const {
int accum = 0;
for (outer_it it = begin(); it != end(); ++it) {
accum += (int)it->size();
}
return accum;
}
bool contains(IfcUtil::IfcBaseClass* instance) const {
for (outer_it it = begin(); it != end(); ++it) {
const std::vector<IfcUtil::IfcBaseClass*>& inner = *it;
if (std::find(inner.begin(), inner.end(), instance) != inner.end()) {
return true;
}
}
return false;
}
template <class U>
typename IfcTemplatedEntityListList<U>::ptr as() {
typename IfcTemplatedEntityListList<U>::ptr r(new IfcTemplatedEntityListList<U>);
const bool all = U::Class() == IfcSchema::Type::UNDEFINED;
for (outer_it outer = begin(); outer != end(); ++outer) {
const std::vector<IfcUtil::IfcBaseClass*>& from = *outer;
typename std::vector<U*> to;
for (inner_it inner = from.begin(); inner != from.end(); ++inner) {
if (all || (*inner)->is(U::Class())) to.push_back((U*)*inner);
}
r->push(to);
}
return r;
}
};
template <class T>
class IfcTemplatedEntityListList {
std::vector< std::vector<T*> > ls;
public:
typedef typename boost::shared_ptr< IfcTemplatedEntityListList<T> > ptr;
typedef typename std::vector< std::vector<T*> >::const_iterator outer_it;
typedef typename std::vector<T*>::const_iterator inner_it;
void push(const std::vector<T*>& t) { ls.push_back(t); }
outer_it begin() { return ls.begin(); }
outer_it end() { return ls.end(); }
int size() const { return (int)ls.size(); }
int totalSize() const {
int accum = 0;
for (outer_it it = begin(); it != end(); ++it) {
accum += it->size();
}
return accum;
}
bool contains(T* t) const {
for (outer_it it = begin(); it != end(); ++it) {
const std::vector<T*>& inner = *it;
if (std::find(inner.begin(), inner.end(), t) != inner.end()) {
return true;
}
}
return false;
}
IfcEntityListList::ptr generalize() {
IfcEntityListList::ptr r(new IfcEntityListList());
for (outer_it outer = begin(); outer != end(); ++outer) {
const std::vector<T*>& from = *outer;
std::vector<IfcUtil::IfcBaseClass*> to;
for (inner_it inner = from.begin(); inner != from.end(); ++inner) {
to.push_back(*inner);
}
r->push(to);
}
return r;
}
};
#endif
+7 -9
View File
@@ -37,34 +37,31 @@ public:
typedef std::map<IfcSchema::Type::Enum, IfcEntityList::ptr> entities_by_type_t;
typedef std::map<unsigned int, IfcUtil::IfcBaseClass*> entity_by_id_t;
typedef std::map<std::string, IfcSchema::IfcRoot*> entity_by_guid_t;
typedef std::map<unsigned int, IfcEntityList::ptr> entities_by_ref_t;
typedef std::map<unsigned int, unsigned int> offset_by_id_t;
typedef std::map<unsigned int, std::vector<unsigned int> > entities_by_ref_t;
typedef entity_by_id_t::const_iterator const_iterator;
private:
typedef std::map<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*> entity_entity_map_t;
bool _create_latebound_entities;
bool parsing_complete_;
entity_by_id_t byid;
entities_by_type_t bytype;
entities_by_ref_t byref;
entity_by_guid_t byguid;
offset_by_id_t offsets;
entity_entity_map_t entity_file_map;
unsigned int lastId;
unsigned int MaxId;
IfcSpfHeader _header;
void setDefaultHeaderValues();
void traverse(IfcUtil::IfcBaseClass*, std::set<IfcUtil::IfcBaseClass*>& visited, IfcEntityList::ptr list, int level, int max_level);
void register_inverse(unsigned, Token);
public:
IfcParse::IfcSpfLexer* tokens;
IfcParse::IfcSpfStream* stream;
IfcFile(bool create_latebound_entities = false);
IfcFile();
~IfcFile();
/// Returns the first entity in the file, this probably is the entity
@@ -130,9 +127,10 @@ public:
std::string createTimestamp() const;
bool create_latebound_entities() const { return _create_latebound_entities; }
std::pair<IfcSchema::IfcNamedUnit*, double> getUnit(IfcSchema::IfcUnitEnum::IfcUnitEnum);
void load(const IfcEntityInstanceData&);
void load(unsigned entity_instance_name, std::vector<Argument*>& attributes);
};
}
+1 -1
View File
@@ -28,7 +28,7 @@
#include "../ifcparse/IfcGlobalId.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcLogger.h"
static const char* chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$";
-261
View File
@@ -1,261 +0,0 @@
/********************************************************************************
* *
* 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/>. *
* *
********************************************************************************/
#include <sstream>
#include <boost/algorithm/string.hpp>
#include "../ifcparse/IfcWritableEntity.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcWrite.h"
#ifdef USE_IFC4
#include "../ifcparse/Ifc4-latebound.h"
#else
#include "../ifcparse/Ifc2x3-latebound.h"
#endif
#include "IfcLateBoundEntity.h"
using namespace IfcUtil;
IfcWrite::IfcWritableEntity* IfcParse::IfcLateBoundEntity::writable_entity() {
IfcWrite::IfcWritableEntity* e;
if (entity->isWritable()) {
e = (IfcWrite::IfcWritableEntity*) entity;
} else {
entity = e = new IfcWrite::IfcWritableEntity(entity);
}
return e;
}
IfcParse::IfcLateBoundEntity::IfcLateBoundEntity(const std::string& s) {
IfcSchema::Type::Enum ty = IfcSchema::Type::FromString(boost::to_upper_copy(s));
entity = new IfcWrite::IfcWritableEntity(ty);
for (unsigned i = 0; i < getArgumentCount(); ++i) {
// Side effect of this is that a NULL attribute is created.
entity->getArgument(i);
}
IfcSchema::Type::PopulateDerivedFields(writable_entity());
}
IfcParse::IfcLateBoundEntity::IfcLateBoundEntity(IfcAbstractEntity* e) {
entity = e;
}
unsigned int IfcParse::IfcLateBoundEntity::id() const {
if (entity->file) {
return static_cast<unsigned int>(entity->id());
} else {
throw IfcException("Entity not bound to a file");
}
}
bool IfcParse::IfcLateBoundEntity::is(IfcSchema::Type::Enum v) const {
IfcSchema::Type::Enum _ty = entity->type();
if (v == _ty) return true;
while (IfcSchema::Type::Parent(_ty)) {
_ty = *IfcSchema::Type::Parent(_ty);
if (v == _ty) return true;
}
return false;
}
std::string IfcParse::IfcLateBoundEntity::is_a() const {
return IfcSchema::Type::ToString(entity->type());
}
bool IfcParse::IfcLateBoundEntity::is_a(const std::string& s) const {
return is(IfcSchema::Type::FromString(boost::to_upper_copy(s)));
}
IfcSchema::Type::Enum IfcParse::IfcLateBoundEntity::type() const {
return entity->type();
}
unsigned int IfcParse::IfcLateBoundEntity::getArgumentCount() const {
return IfcSchema::Type::GetAttributeCount(entity->type());
}
IfcUtil::ArgumentType IfcParse::IfcLateBoundEntity::getArgumentType(unsigned int i) const {
return IfcSchema::Type::GetAttributeDerived(entity->type(), (unsigned char)i)
? IfcUtil::Argument_DERIVED
: IfcSchema::Type::GetAttributeType(entity->type(), (unsigned char)i);
}
IfcSchema::Type::Enum IfcParse::IfcLateBoundEntity::getArgumentEntity(unsigned int i) const {
return IfcSchema::Type::GetAttributeEntity(entity->type(), (unsigned char)i);
}
Argument* IfcParse::IfcLateBoundEntity::getArgument(unsigned int i) const {
return entity->getArgument(i);
}
const char* IfcParse::IfcLateBoundEntity::getArgumentName(unsigned int i) const {
return IfcSchema::Type::GetAttributeName(entity->type(), (unsigned char)i).c_str();
}
bool IfcParse::IfcLateBoundEntity::getArgumentOptionality(unsigned int i) const {
return IfcSchema::Type::GetAttributeOptional(entity->type(), (unsigned char)i);
}
void IfcParse::IfcLateBoundEntity::invalid_argument(unsigned int i, const std::string& t) {
const std::string arg_name = IfcSchema::Type::GetAttributeName(entity->type(), (unsigned char)i);
throw IfcException(t + " is not a valid type for '" + arg_name + "'");
}
void IfcParse::IfcLateBoundEntity::setArgumentAsNull(unsigned int i) {
bool is_optional = IfcSchema::Type::GetAttributeOptional(entity->type(), (unsigned char)i);
if (is_optional) {
writable_entity()->setArgument(i);
} else invalid_argument(i,"NULL");
}
void IfcParse::IfcLateBoundEntity::setArgumentAsInt(unsigned int i, int v) {
IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(entity->type(), (unsigned char)i);
if (arg_type == Argument_INT) {
writable_entity()->setArgument(i,v);
} else if ( (arg_type == Argument_BOOL) && ( (v == 0) || (v == 1) ) ) {
writable_entity()->setArgument(i, v == 1);
} else invalid_argument(i,"INTEGER");
}
void IfcParse::IfcLateBoundEntity::setArgumentAsBool(unsigned int i, bool v) {
IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(entity->type(), (unsigned char)i);
if (arg_type == Argument_BOOL) {
writable_entity()->setArgument(i,v);
} else invalid_argument(i,"BOOLEAN");
}
void IfcParse::IfcLateBoundEntity::setArgumentAsDouble(unsigned int i, double v) {
IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(entity->type(), (unsigned char)i);
if (arg_type == Argument_DOUBLE) {
writable_entity()->setArgument(i,v);
} else invalid_argument(i,"REAL");
}
void IfcParse::IfcLateBoundEntity::setArgumentAsString(unsigned int i, const std::string& a) {
IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(entity->type(), (unsigned char)i);
if (arg_type == Argument_STRING) {
writable_entity()->setArgument(i,a);
} else if (arg_type == Argument_ENUMERATION) {
std::pair<const char*, int> enum_data = IfcSchema::Type::GetEnumerationIndex(IfcSchema::Type::GetAttributeEntity(entity->type(), (unsigned char)i), a);
writable_entity()->setArgument(i, enum_data.second, enum_data.first);
} else if (arg_type == Argument_BINARY) {
if (valid_binary_string(a)) {
boost::dynamic_bitset<> bits(a);
writable_entity()->setArgument(i, bits);
} else {
throw IfcException("String not a valid binary representation");
}
} else invalid_argument(i,"STRING");
}
void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfInt(unsigned int i, const std::vector<int>& v) {
IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(entity->type(), (unsigned char)i);
if (arg_type == Argument_AGGREGATE_OF_INT) {
writable_entity()->setArgument(i,v);
} else invalid_argument(i,"AGGREGATE OF INT");
}
void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfDouble(unsigned int i, const std::vector<double>& v) {
IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(entity->type(), (unsigned char)i);
if (arg_type == Argument_AGGREGATE_OF_DOUBLE) {
writable_entity()->setArgument(i,v);
} else invalid_argument(i,"AGGREGATE OF DOUBLE");
}
void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfString(unsigned int i, const std::vector<std::string>& v) {
IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(entity->type(), (unsigned char)i);
if (arg_type == Argument_AGGREGATE_OF_STRING) {
writable_entity()->setArgument(i,v);
} else if (arg_type == Argument_AGGREGATE_OF_BINARY) {
std::vector< boost::dynamic_bitset<> > bits;
bits.reserve(v.size());
for (std::vector<std::string>::const_iterator it = v.begin(); it != v.end(); ++it) {
if (valid_binary_string(*it)) {
bits.push_back(boost::dynamic_bitset<>(*it));
} else {
throw IfcException("String not a valid binary representation");
}
}
writable_entity()->setArgument(i, bits);
} else invalid_argument(i,"AGGREGATE OF STRING");
}
void IfcParse::IfcLateBoundEntity::setArgumentAsEntityInstance(unsigned int i, IfcParse::IfcLateBoundEntity* v) {
IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(entity->type(), (unsigned char)i);
if (arg_type == Argument_ENTITY_INSTANCE) {
writable_entity()->setArgument(i,v);
} else invalid_argument(i,"ENTITY INSTANCE");
}
void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfEntityInstance(unsigned int i, IfcEntityList::ptr v) {
IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(entity->type(), (unsigned char)i);
if (arg_type == Argument_AGGREGATE_OF_ENTITY_INSTANCE) {
writable_entity()->setArgument(i,v);
} else invalid_argument(i,"AGGREGATE OF ENTITY INSTANCE");
}
void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfAggregateOfInt(unsigned int i, const std::vector< std::vector<int> >& v) {
IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(entity->type(), (unsigned char)i);
if (arg_type == Argument_AGGREGATE_OF_AGGREGATE_OF_INT) {
writable_entity()->setArgument(i,v);
} else invalid_argument(i,"AGGREGATE OF AGGREGATE OF INT");
}
void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfAggregateOfDouble(unsigned int i, const std::vector< std::vector<double> >& v) {
IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(entity->type(), (unsigned char)i);
if (arg_type == Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE) {
writable_entity()->setArgument(i,v);
} else invalid_argument(i,"AGGREGATE OF AGGREGATE OF DOUBLE");
}
void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfAggregateOfEntityInstance(unsigned int i, IfcEntityListList::ptr v) {
IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(entity->type(), (unsigned char)i);
if (arg_type == Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE) {
writable_entity()->setArgument(i,v);
} else invalid_argument(i,"AGGREGATE OF AGGREGATE OF ENTITY INSTANCE");
}
unsigned IfcParse::IfcLateBoundEntity::getArgumentIndex(const std::string& a) const {
return IfcSchema::Type::GetAttributeIndex(entity->type(),a);
}
std::string IfcParse::IfcLateBoundEntity::toString() {
return entity->toString(false);
}
IfcEntityList::ptr IfcParse::IfcLateBoundEntity::get_inverse(const std::string& a) {
std::pair<IfcSchema::Type::Enum, unsigned> inv = IfcSchema::Type::GetInverseAttribute(entity->type(), a);
return entity->getInverse(inv.first, inv.second);
}
bool IfcParse::IfcLateBoundEntity::is_valid() {
const unsigned arg_count = getArgumentCount();
bool valid = true;
std::ostringstream oss;
oss << "Argument ";
for (unsigned i = 0; i < arg_count; ++i) {
bool is_null = true;
try {
const Argument& arg = *getArgument(i);
is_null = arg.isNull();
} catch(IfcException) {}
if (!IfcSchema::Type::GetAttributeOptional(entity->type(), (unsigned char)i) && is_null) {
if (!valid) {
oss << ", ";
}
oss << "\"" << getArgumentName(i) << "\"";
valid = false;
}
}
oss << " not optional";
if (!valid) {
throw IfcException(oss.str());
}
return valid;
}
std::vector<std::string> IfcParse::IfcLateBoundEntity::getAttributeNames() const {
std::vector<std::string> return_value;
return_value.reserve(getArgumentCount());
for (unsigned i = 0; i < getArgumentCount(); ++i) {
return_value.push_back(getArgumentName(i));
}
return return_value;
}
std::vector<std::string> IfcParse::IfcLateBoundEntity::getInverseAttributeNames() const {
std::vector<std::string> return_value;
std::set<std::string> values = IfcSchema::Type::GetInverseAttributeNames(entity->type());
std::copy(values.begin(), values.end(), std::back_inserter(return_value));
return return_value;
}
-87
View File
@@ -1,87 +0,0 @@
/********************************************************************************
* *
* 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/>. *
* *
********************************************************************************/
#ifndef IFCLATEBOUNDENTITY_H
#define IFCLATEBOUNDENTITY_H
#include <string>
#include "ifc_parse_api.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcWrite.h"
#include "../ifcparse/IfcWritableEntity.h"
namespace IfcParse {
// TODO: Somehow these methods should become part of IfcBaseEntity directly so
// that in the IfcFile class the distinction what entity type to be created is
// no longer necessary and weird diagonal casts when creating geometry from
// IfcLateBoundEntities are eliminated.
class IFC_PARSE_API IfcLateBoundEntity : public IfcUtil::IfcBaseEntity {
private:
IfcWrite::IfcWritableEntity* writable_entity();
void invalid_argument(unsigned int i, const std::string& t);
public:
IfcLateBoundEntity(const std::string& s);
IfcLateBoundEntity(IfcAbstractEntity* e);
bool is(IfcSchema::Type::Enum v) const;
IfcSchema::Type::Enum type() const;
bool is_a(const std::string& s) const;
std::string is_a() const;
unsigned int id() const;
unsigned int getArgumentCount() const;
IfcUtil::ArgumentType getArgumentType(unsigned int i) const;
IfcSchema::Type::Enum getArgumentEntity(unsigned int i) const;
Argument* getArgument(unsigned int i) const;
const char* getArgumentName(unsigned int i) const;
unsigned getArgumentIndex(const std::string& a) const;
bool getArgumentOptionality(unsigned int i) const;
IfcEntityList::ptr get_inverse(const std::string& a);
std::vector<std::string> getAttributeNames() const;
std::vector<std::string> getInverseAttributeNames() const;
void setArgumentAsNull(unsigned int i);
void setArgumentAsInt(unsigned int i, int v);
void setArgumentAsBool(unsigned int i, bool v);
void setArgumentAsDouble(unsigned int i, double v);
void setArgumentAsString(unsigned int i, const std::string& v);
void setArgumentAsEntityInstance(unsigned int i, IfcLateBoundEntity* v);
void setArgumentAsAggregateOfInt(unsigned int i, const std::vector<int>& v);
void setArgumentAsAggregateOfDouble(unsigned int i, const std::vector<double>& v);
void setArgumentAsAggregateOfString(unsigned int i, const std::vector<std::string>& v);
void setArgumentAsAggregateOfEntityInstance(unsigned int i, IfcEntityList::ptr v);
void setArgumentAsAggregateOfAggregateOfInt(unsigned int i, const std::vector< std::vector<int> >& v);
void setArgumentAsAggregateOfAggregateOfDouble(unsigned int i, const std::vector< std::vector<double> >& v);
void setArgumentAsAggregateOfAggregateOfEntityInstance(unsigned int i, IfcEntityListList::ptr v);
std::string toString();
bool is_valid();
};
}
#endif
+1 -1
View File
@@ -37,7 +37,7 @@ void Logger::SetOutput(std::ostream* l1, std::ostream* l2) {
log2 = &log_stream;
}
}
void Logger::Message(Logger::Severity type, const std::string& message, IfcAbstractEntity* entity) {
void Logger::Message(Logger::Severity type, const std::string& message, IfcEntityInstanceData* entity) {
if ( log2 && type >= verbosity ) {
(*log2) << "[" << severity_strings[type] << "] ";
if ( current_product ) {
+4 -4
View File
@@ -54,10 +54,10 @@ public:
static void Verbosity(Severity v);
static Severity Verbosity();
/// Log a message to the output stream
static void Message(Severity type, const std::string& message, IfcAbstractEntity* entity=0);
static void Notice(const std::string& message, IfcAbstractEntity* entity = 0) { Message(LOG_NOTICE, message, entity); }
static void Warning(const std::string& message, IfcAbstractEntity* entity=0) { Message(LOG_WARNING, message, entity); }
static void Error(const std::string& message, IfcAbstractEntity* entity=0) { Message(LOG_ERROR, message, entity); }
static void Message(Severity type, const std::string& message, IfcEntityInstanceData* entity=0);
static void Notice(const std::string& message, IfcEntityInstanceData* entity = 0) { Message(LOG_NOTICE, message, entity); }
static void Warning(const std::string& message, IfcEntityInstanceData* entity=0) { Message(LOG_WARNING, message, entity); }
static void Error(const std::string& message, IfcEntityInstanceData* entity=0) { Message(LOG_ERROR, message, entity); }
static void Status(const std::string& message, bool new_line=true);
static void ProgressBar(int progress);
static std::string GetLog();
+321 -189
View File
@@ -23,6 +23,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <ctime>
#include <boost/circular_buffer.hpp>
#ifdef _MSC_VER
#include <Windows.h>
@@ -34,13 +35,17 @@
#include "../ifcparse/IfcCharacterDecoder.h"
#include "../ifcparse/IfcParse.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcSpfStream.h"
#include "../ifcparse/IfcWritableEntity.h"
#include "../ifcparse/IfcLateBoundEntity.h"
#include "../ifcparse/IfcFile.h"
#include "../ifcparse/IfcSIPrefix.h"
#ifdef USE_IFC4
#include "../ifcparse/Ifc4-latebound.h"
#else
#include "../ifcparse/Ifc2x3-latebound.h"
#endif
#define PERMISSIVE_FLOAT
using namespace IfcParse;
@@ -384,7 +389,7 @@ void IfcSpfLexer::TokenString(unsigned int offset, std::string &buffer) {
if ( c == ' ' || c == '\r' || c == '\n' || c == '\t' ) continue;
else if ( c == '\'' ) {
buffer = *decoder;
return;
break;
}
else buffer.push_back(c);
}
@@ -623,20 +628,18 @@ TokenArgument::TokenArgument(const Token& t) {
EntityArgument::EntityArgument(const Token& t) {
IfcParse::IfcFile* file = t.lexer->file;
if (file->create_latebound_entities()) {
entity = new IfcLateBoundEntity(new Entity(0, file, t.startPos));
} else {
entity = IfcSchema::SchemaEntity(new Entity(0, file, t.startPos));
}
IfcEntityInstanceData* data = read(0, file, t.startPos);
entity = IfcSchema::SchemaEntity(data);
// Needs to be loaded, for the tokens to be consumed
file->load(*data);
}
//
// Reads the arguments from a list of token
// Aditionally, stores the ids (i.e. #[\d]+) in a vector
// Aditionally, registers the ids (i.e. #[\d]+) in the inverse map
//
void ArgumentList::read(IfcSpfLexer* t, std::vector<unsigned int>& ids) {
//IfcParse::IfcFile* file = t->file;
Token next = t->Next();
void IfcParse::IfcFile::load(unsigned entity_instance_name, std::vector<Argument*>& attributes) {
Token next = tokens->Next();
while( next.startPos || next.lexer ) {
if ( TokenFunc::isOperator(next,',') ) {
// do nothing
@@ -644,23 +647,25 @@ void ArgumentList::read(IfcSpfLexer* t, std::vector<unsigned int>& ids) {
break;
} else if ( TokenFunc::isOperator(next,'(') ) {
ArgumentList* alist = new ArgumentList();
alist->read(t, ids);
push(alist);
load(entity_instance_name, alist->arguments());
attributes.push_back(alist);
} else {
if ( TokenFunc::isIdentifier(next) ) {
ids.push_back(TokenFunc::asIdentifier(next));
if (!parsing_complete_) {
register_inverse(entity_instance_name, next);
}
} if ( TokenFunc::isKeyword(next) ) {
t->Next();
// tokens->Next();
try {
push ( new EntityArgument(next) );
attributes.push_back(new EntityArgument(next));
} catch ( IfcException& e ) {
Logger::Message(Logger::LOG_ERROR,e.what());
Logger::Message(Logger::LOG_ERROR, e.what());
}
} else {
push ( new TokenArgument(next) );
attributes.push_back(new TokenArgument(next));
}
}
next = t->Next();
next = tokens->Next();
}
}
@@ -874,124 +879,99 @@ std::string EntityArgument::toString(bool upper) const {
bool EntityArgument::isNull() const { return false; }
EntityArgument::~EntityArgument() { delete entity->entity; delete entity;}
//
// Reads an Entity from the list of Tokens
//
Entity::Entity(unsigned int i, IfcFile* f) : args(0), _id(i) {
file = f;
Token datatype = f->tokens->Next();
if ( ! TokenFunc::isKeyword(datatype)) throw IfcException("Unexpected token while parsing entity");
_type = IfcSchema::Type::FromString(TokenFunc::asStringRef(datatype));
offset = datatype.startPos;
}
//
// Reads an Entity from the list of Tokens at the specified offset in the file
//
Entity::Entity(unsigned int i, IfcFile* f, unsigned int o) { // : file(f) {
file = f;
std::vector<unsigned int> ids;
_id = i;
offset = o;
Load(ids, true);
}
//
// Access the Nth argument from the ArgumentList
//
Argument* Entity::getArgument(unsigned int i) {
if ( ! args ) {
std::vector<unsigned int> ids;
Load(ids, true);
IfcEntityInstanceData* IfcParse::read(unsigned int i, IfcFile* f, boost::optional<unsigned> offset) {
if (offset) {
f->tokens->stream->Seek(*offset);
}
return (*args)[i];
Token datatype = f->tokens->Next();
if (!TokenFunc::isKeyword(datatype)) throw IfcException("Unexpected token while parsing entity");
IfcSchema::Type::Enum ty = IfcSchema::Type::FromString(TokenFunc::asStringRef(datatype));
IfcEntityInstanceData* e = new IfcEntityInstanceData(ty, f, i, offset.get_value_or(0));
return e;
}
unsigned int Entity::getArgumentCount() const {
if ( ! args ) {
std::vector<unsigned int> ids;
Load(ids, true);
void IfcParse::IfcFile::load(const IfcEntityInstanceData& data) {
if (tokens->stream->Tell() != data.offset_in_file()) {
tokens->stream->Seek(data.offset_in_file());
Token datatype = tokens->Next();
if (!TokenFunc::isKeyword(datatype)) throw IfcException("Unexpected token while parsing entity instance");
}
return args->size();
}
//
// Load the ArgumentList
//
void Entity::Load(std::vector<unsigned int>& ids, bool seek) const {
if ( seek ) {
file->tokens->stream->Seek(offset);
Token datatype = file->tokens->Next();
if ( ! TokenFunc::isKeyword(datatype)) throw IfcException("Unexpected token while parsing entity");
_type = IfcSchema::Type::FromString(TokenFunc::asStringRef(datatype));
tokens->Next();
load(data.id(), data.attributes());
unsigned int old_offset = tokens->stream->Tell();
Token semilocon = tokens->Next();
if (!TokenFunc::isOperator(semilocon, ';')) {
tokens->stream->Seek(old_offset);
}
/*Token open =*/ file->tokens->Next();
args = new ArgumentList();
args->read(file->tokens, ids);
unsigned int old_offset = file->tokens->stream->Tell();
Token semilocon = file->tokens->Next();
if ( ! TokenFunc::isOperator(semilocon,';') ) file->tokens->stream->Seek(old_offset);
}
IfcSchema::Type::Enum Entity::type() const {
return _type;
}
//
// Returns the CamelCase string representation of the datatype as it is defined in the schema
//
std::string Entity::datatype() const {
return IfcSchema::Type::ToString(_type);
void IfcParse::IfcFile::register_inverse(unsigned id_from, Token t) {
// Assume a check on token type has already been performed
byref[t.value_int].push_back(id_from);
}
//
// Returns a string representation of the entity
// Note that this initializes the entity if it is not initialized
//
std::string Entity::toString(bool upper) const {
if (!args) {
std::vector<unsigned int> ids;
Load(ids, true);
std::string IfcEntityInstanceData::toString(bool upper) const {
if (!initialized_) {
load_();
}
std::stringstream ss;
ss.imbue(std::locale::classic());
std::string dt = datatype();
std::string dt = IfcSchema::Type::ToString(type());
if (upper) {
boost::to_upper(dt);
}
if (!IfcSchema::Type::IsSimple(type()) || _id != 0) {
ss << "#" << _id << "=";
if (!IfcSchema::Type::IsSimple(type()) || id_ != 0) {
ss << "#" << id_ << "=";
}
ss << dt << args->toString(upper);
ss << dt << "(";
std::vector<Argument*>::const_iterator it = attributes_.begin();
for (; it != attributes_.end(); ++it) {
if (it != attributes_.begin()) {
ss << ",";
}
ss << (*it)->toString(upper);
}
ss << ")";
return ss.str();
}
Entity::~Entity() {
delete args;
IfcEntityInstanceData::~IfcEntityInstanceData() {
std::vector<Argument*>::const_iterator it = attributes_.begin();
for (; it != attributes_.end(); ++it) {
delete *it;
}
}
unsigned IfcEntityInstanceData::set_id(boost::optional<unsigned> i) {
if (i) {
return id_ = *i;
} else {
return id_ = file->FreshId();
}
}
//
// Returns the entities of Entity type that have this entity in their ArgumentList
//
IfcEntityList::ptr Entity::getInverse(IfcSchema::Type::Enum type, int attribute_index) {
return file->getInverse(_id, type, attribute_index);
IfcEntityList::ptr IfcEntityInstanceData::getInverse(IfcSchema::Type::Enum type, int attribute_index) {
return file->getInverse(id_, type, attribute_index);
}
bool Entity::is(IfcSchema::Type::Enum v) const { return _type == v; }
unsigned int Entity::id() { return _id; }
IfcWrite::IfcWritableEntity* Entity::isWritable() {
return 0;
}
IfcFile::IfcFile(bool create_latebound_entities)
: _create_latebound_entities(create_latebound_entities)
, lastId(0)
IfcFile::IfcFile()
: parsing_complete_(false)
, MaxId(0)
, tokens(0)
, stream(0)
@@ -999,6 +979,147 @@ IfcFile::IfcFile(bool create_latebound_entities)
setDefaultHeaderValues();
}
void IfcEntityInstanceData::load_() const {
file->load(*this);
initialized_ = true;
}
IfcEntityInstanceData::IfcEntityInstanceData(const IfcEntityInstanceData& e) {
file = e.file;
type_ = e.type_;
id_ = 0;
const unsigned int count = e.getArgumentCount();
for (unsigned int i = 0; i < count; ++i) {
this->setArgument(i, e.getArgument(i));
}
}
Argument* IfcEntityInstanceData::getArgument(unsigned int i) const {
if (!initialized_) {
load_();
}
if (i < attributes_.size()) {
return attributes_[i];
} else {
throw IfcParse::IfcException("Attribute index out of range");
}
}
void IfcEntityInstanceData::setArgument(unsigned int i, Argument* a, IfcUtil::ArgumentType attr_type) {
while (attributes_.size() < i) {
attributes_.push_back(new NullArgument());
}
if (i < attributes_.size()) {
delete attributes_[i];
}
if (attr_type == IfcUtil::Argument_UNKNOWN) {
attr_type = a->type();
}
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
switch (attr_type) {
case IfcUtil::Argument_NULL:
copy->set(boost::blank());
break;
case IfcUtil::Argument_DERIVED:
copy->set(IfcWrite::IfcWriteArgument::Derived());
break;
case IfcUtil::Argument_INT:
copy->set(static_cast<int>(*a));
break;
case IfcUtil::Argument_BOOL:
copy->set(static_cast<bool>(*a));
break;
case IfcUtil::Argument_DOUBLE:
copy->set(static_cast<double>(*a));
break;
case IfcUtil::Argument_STRING:
copy->set(static_cast<std::string>(*a));
break;
case IfcUtil::Argument_BINARY: {
boost::dynamic_bitset<> attr_value = *a;
copy->set(attr_value);
break; }
case IfcUtil::Argument_AGGREGATE_OF_INT: {
std::vector<int> attr_value = *a;
copy->set(attr_value);
break; }
case IfcUtil::Argument_AGGREGATE_OF_DOUBLE: {
std::vector<double> attr_value = *a;
copy->set(attr_value);
break; }
case IfcUtil::Argument_AGGREGATE_OF_STRING: {
std::vector<std::string> attr_value = *a;
copy->set(attr_value);
break; }
case IfcUtil::Argument_AGGREGATE_OF_BINARY: {
std::vector< boost::dynamic_bitset<> > attr_value = *a;
copy->set(attr_value);
break; }
case IfcUtil::Argument_ENUMERATION: {
IfcSchema::Type::Enum ty = IfcSchema::Type::GetAttributeEntity(type_, (unsigned char)i);
std::string enum_literal = a->toString();
// Remove leading and trailing '.'
enum_literal = enum_literal.substr(1, enum_literal.size() - 2);
std::pair<const char*, int> enum_ref = IfcSchema::Type::GetEnumerationIndex(ty, enum_literal);
copy->set(IfcWrite::IfcWriteArgument::EnumerationReference(enum_ref.second, enum_ref.first));
break; }
case IfcUtil::Argument_ENTITY_INSTANCE: {
copy->set(static_cast<IfcUtil::IfcBaseClass*>(*a));
break; }
case IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE: {
IfcEntityList::ptr instances = *a;
IfcEntityList::ptr mapped_instances(new IfcEntityList);
for (IfcEntityList::it it = instances->begin(); it != instances->end(); ++it) {
mapped_instances->push(*it);
}
copy->set(mapped_instances);
break; }
case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_INT: {
std::vector< std::vector<int> > attr_value = *a;
copy->set(attr_value);
break; }
case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE: {
std::vector< std::vector<double> > attr_value = *a;
copy->set(attr_value);
break; }
case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE: {
IfcEntityListList::ptr instances = *a;
IfcEntityListList::ptr mapped_instances(new IfcEntityListList);
for (IfcEntityListList::outer_it it = instances->begin(); it != instances->end(); ++it) {
std::vector<IfcUtil::IfcBaseClass*> inner;
for (IfcEntityListList::inner_it jt = it->begin(); jt != it->end(); ++jt) {
inner.push_back(*jt);
}
mapped_instances->push(inner);
}
copy->set(mapped_instances);
break; }
case IfcUtil::Argument_EMPTY_AGGREGATE:
case IfcUtil::Argument_AGGREGATE_OF_EMPTY_AGGREGATE: {
IfcUtil::ArgumentType t2 = IfcSchema::Type::GetAttributeType(type(), (unsigned char)i);
delete copy;
setArgument(i, a, t2);
break; }
default:
case IfcUtil::Argument_UNKNOWN:
throw IfcParse::IfcException(std::string("Unknown attribute encountered: '") + a->toString() + "' at index '" + boost::lexical_cast<std::string>(i) + "'");
break;
}
if (i < attributes_.size()) {
attributes_[i] = copy;
} else {
// We have asserted above that the size is at least i
attributes_.push_back(copy);
}
}
//
// Parses the IFC file in fn
// Creates the maps
@@ -1026,7 +1147,7 @@ bool IfcFile::Init(IfcParse::IfcSpfStream* s) {
}
tokens = new IfcSpfLexer(stream, this);
_header.lexer(tokens);
_header.file(this);
_header.tryRead();
std::vector<std::string> schemas;
@@ -1037,37 +1158,42 @@ bool IfcFile::Init(IfcParse::IfcSpfStream* s) {
Logger::Message(Logger::LOG_ERROR, std::string("File schema encountered different from expected '") + IfcSchema::Identifier + "'");
}
Token token = NoneTokenPtr();
Token previous = NoneTokenPtr();
boost::circular_buffer<Token> token_stream(3);
unsigned int currentId = 0;
lastId = 0;
int x = 0;
Entity* e;
IfcUtil::IfcBaseClass* entity = 0;
IfcEntityInstanceData* data;
IfcUtil::IfcBaseClass* instance = 0;
unsigned current_id = 0;
int progress = 0;
Logger::Status("Scanning file...");
while ( ! stream->eof ) {
if ( currentId ) {
while (!stream->eof) {
if (token_stream[0].type == IfcParse::Token_IDENTIFIER &&
token_stream[1].type == IfcParse::Token_OPERATOR &&
token_stream[1].value_char == '=' &&
token_stream[2].type == IfcParse::Token_KEYWORD)
{
current_id = (unsigned) TokenFunc::asIdentifier(token_stream[0]);
IfcSchema::Type::Enum entity_type;
try {
e = new Entity(currentId,this);
if (this->create_latebound_entities()) {
entity = new IfcLateBoundEntity(e);
} else {
entity = IfcSchema::SchemaEntity(e);
}
entity_type = IfcSchema::Type::FromString(TokenFunc::asStringRef(token_stream[2]));
} catch (const IfcException& ex) {
currentId = 0;
Logger::Message(Logger::LOG_ERROR,ex.what());
Logger::Message(Logger::LOG_ERROR, ex.what());
continue;
}
}
data = new IfcEntityInstanceData(entity_type, this, current_id, token_stream[2].startPos);
instance = IfcSchema::SchemaEntity(data);
/// @todo Printing to stdout in a library class feels weird. Maybe move the progress prints to the client code?
// Update the status after every 1000 instances parsed
if ( !((++x)%1000) ) {
std::stringstream ss; ss << "\r#" << currentId;
if (!((++progress) % 1000)) {
std::stringstream ss; ss << "\r#" << current_id;
Logger::Status(ss.str(), false);
}
if ( entity->is(IfcSchema::Type::IfcRoot) ) {
IfcSchema::IfcRoot* ifc_root = (IfcSchema::IfcRoot*) entity;
if (instance->is(IfcSchema::Type::IfcRoot)) {
IfcSchema::IfcRoot* ifc_root = (IfcSchema::IfcRoot*) instance;
try {
const std::string guid = ifc_root->GlobalId();
if ( byguid.find(guid) != byguid.end() ) {
@@ -1081,14 +1207,14 @@ bool IfcFile::Init(IfcParse::IfcSpfStream* s) {
}
}
IfcSchema::Type::Enum ty = entity->type();
IfcSchema::Type::Enum ty = instance->type();
for (;;) {
IfcEntityList::ptr instances_by_type = entitiesByType(ty);
if (!instances_by_type) {
instances_by_type = IfcEntityList::ptr(new IfcEntityList());
bytype[ty] = instances_by_type;
}
instances_by_type->push(entity);
instances_by_type->push(instance);
boost::optional<IfcSchema::Type::Enum> pt = IfcSchema::Type::Parent(ty);
if (pt) {
ty = *pt;
@@ -1097,45 +1223,36 @@ bool IfcFile::Init(IfcParse::IfcSpfStream* s) {
}
}
if ( byid.find(currentId) != byid.end() ) {
if (byid.find(current_id) != byid.end()) {
std::stringstream ss;
ss << "Overwriting instance with name #" << currentId;
ss << "Overwriting instance with name #" << current_id;
Logger::Message(Logger::LOG_WARNING,ss.str());
}
byid[currentId] = entity;
byid[current_id] = instance;
MaxId = (std::max)(MaxId,currentId);
currentId = 0;
} else {
try {
token = tokens->Next();
} catch (const IfcException& e) {
Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + ". Parsing terminated");
token = NoneTokenPtr();
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Parsing terminated");
token = NoneTokenPtr();
}
MaxId = (std::max)(MaxId, current_id);
} else if (token_stream[0].type == IfcParse::Token_IDENTIFIER && instance) {
register_inverse(current_id, token_stream[0]);
}
if ( ! (token.startPos || token.lexer) ) break;
if ( (previous.startPos || previous.lexer) && TokenFunc::isIdentifier(previous) ) {
int id = TokenFunc::asIdentifier(previous);
if ( TokenFunc::isOperator(token,'=') ) {
currentId = id;
} else if (entity) {
IfcEntityList::ptr instances_by_ref = entitiesByReference(id);
if (!instances_by_ref) {
instances_by_ref = IfcEntityList::ptr(new IfcEntityList());
byref[id] = instances_by_ref;
}
instances_by_ref->push(entity);
}
Token next_token;
try {
next_token = tokens->Next();
} catch (const IfcException& e) {
Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + ". Parsing terminated");
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Parsing terminated");
}
previous = token;
if (next_token.type == Token_NONE) break;
token_stream.push_back(next_token);
}
Logger::Status("\rDone scanning file ");
parsing_complete_ = true;
return true;
}
@@ -1215,12 +1332,8 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity) {
// container and entity is created. The attribute references
// need to be updated to point to instances in this file.
IfcFile* other_file = entity->entity->file;
IfcWrite::IfcWritableEntity* we = new IfcWrite::IfcWritableEntity(entity->entity);
if (this->create_latebound_entities()) {
entity = new IfcLateBoundEntity(we);
} else {
entity = IfcSchema::SchemaEntity(we);
}
IfcEntityInstanceData* we = new IfcEntityInstanceData(*entity->entity);
entity = IfcSchema::SchemaEntity(we);
// In case an entity is added that contains geometry, the unit
// information needs to be accounted for for IfcLengthMeasures.
@@ -1232,7 +1345,10 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity) {
if (attr_type == IfcUtil::Argument_ENTITY_INSTANCE) {
entity_entity_map_t::const_iterator eit = entity_file_map.find(*attr);
if (eit == entity_file_map.end()) throw IfcParse::IfcException("Unable to map instance to file");
we->setArgument(i, eit->second);
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
copy->set(eit->second);
we->setArgument(i, copy);
} else if (attr_type == IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE) {
IfcEntityList::ptr instances = *attr;
IfcEntityList::ptr new_instances(new IfcEntityList);
@@ -1241,7 +1357,10 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity) {
if (eit == entity_file_map.end()) throw IfcParse::IfcException("Unable to map instance to file");
new_instances->push(eit->second);
}
we->setArgument(i, new_instances);
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
copy->set(new_instances);
we->setArgument(i, copy);
} else if (attr_type == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE) {
IfcEntityListList::ptr instances = *attr;
IfcEntityListList::ptr new_instances(new IfcEntityListList);
@@ -1254,7 +1373,11 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity) {
}
new_instances->push(list);
}
we->setArgument(i, new_instances);
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
copy->set(new_instances);
we->setArgument(i, copy);
} else if (entity->getArgumentEntity(i) == IfcSchema::Type::IfcLengthMeasure ||
entity->getArgumentEntity(i) == IfcSchema::Type::IfcPositiveLengthMeasure)
{
@@ -1265,13 +1388,19 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity) {
if (attr_type == IfcUtil::Argument_DOUBLE) {
double v = *attr;
v *= conversion_factor;
we->setArgument(i, v);
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
copy->set(v);
we->setArgument(i, copy);
} else if (attr_type == IfcUtil::Argument_AGGREGATE_OF_DOUBLE) {
std::vector<double> v = *attr;
for (std::vector<double>::iterator it = v.begin(); it != v.end(); ++it) {
(*it) *= conversion_factor;
}
we->setArgument(i, v);
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
copy->set(v);
we->setArgument(i, copy);
}
}
}
@@ -1279,7 +1408,7 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity) {
// A new entity instance name is generated and
// the instance is pointed to this file.
we->file = this;
we->setId(FreshId());
we->set_id(FreshId());
}
// For subtypes of IfcRoot, the GUID mapping needs to be updated.
@@ -1317,10 +1446,10 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity) {
}
int new_id = -1;
if (entity->entity->isWritable() && !entity->entity->file) {
if (!entity->entity->file) {
// For newly created entities ensure a valid ENTITY_INSTANCE_NAME is set
entity->entity->file = this;
new_id = entity->entity->isWritable()->setId();
new_id = entity->entity->set_id();
} else {
new_id = entity->entity->id();
}
@@ -1346,12 +1475,7 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity) {
try {
if (!IfcSchema::Type::IsSimple(entity_attribute->type())) {
unsigned entity_attribute_id = entity_attribute->entity->id();
IfcEntityList::ptr refs = entitiesByReference(entity_attribute_id);
if (!refs) {
refs = IfcEntityList::ptr(new IfcEntityList);
byref[entity_attribute_id] = refs;
}
refs->push(entity);
byref[entity_attribute_id].push_back(entity->entity->id());
}
} catch (const IfcParse::IfcException&) {}
}
@@ -1359,16 +1483,6 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity) {
return entity;
}
IfcWrite::IfcWritableEntity* make_writable(IfcUtil::IfcBaseClass* instance) {
if (instance->entity->isWritable()) {
return instance->entity->isWritable();
}
IfcWrite::IfcWritableEntity* return_value;
instance->entity = return_value = new IfcWrite::IfcWritableEntity(instance->entity);
return return_value;
}
void IfcFile::removeEntity(IfcUtil::IfcBaseClass* entity) {
const unsigned id = entity->entity->id();
IfcUtil::IfcBaseClass* file_entity = entityById(id);
@@ -1403,14 +1517,19 @@ void IfcFile::removeEntity(IfcUtil::IfcBaseClass* entity) {
case IfcUtil::Argument_ENTITY_INSTANCE: {
IfcUtil::IfcBaseClass* instance_attribute = *attr;
if (instance_attribute == entity) {
make_writable(related_instance)->setArgument(i);
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
copy->set(boost::blank());
related_instance->entity->setArgument(i, copy);
} }
break;
case IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE: {
IfcEntityList::ptr instance_list = *attr;
if (instance_list->contains(entity)) {
instance_list->remove(entity);
make_writable(related_instance)->setArgument(i, instance_list);
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
copy->set(instance_list);
related_instance->entity->setArgument(i, copy);
} }
break;
case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE: {
@@ -1425,7 +1544,10 @@ void IfcFile::removeEntity(IfcUtil::IfcBaseClass* entity) {
}
new_list->push(instances);
}
make_writable(related_instance)->setArgument(i, new_list);
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
copy->set(new_list);
related_instance->entity->setArgument(i, copy);
} }
break;
default: break;
@@ -1474,7 +1596,17 @@ IfcEntityList::ptr IfcFile::entitiesByType(const std::string& t) {
IfcEntityList::ptr IfcFile::entitiesByReference(int t) {
entities_by_ref_t::const_iterator it = byref.find(t);
return (it == byref.end()) ? IfcEntityList::ptr() : it->second;
IfcEntityList::ptr return_value;
if (it != byref.end()) {
const std::vector<unsigned>& ids = it->second;
for (std::vector<unsigned>::const_iterator jt = ids.begin(); jt != ids.end(); ++jt) {
if (!return_value) {
return_value.reset(new IfcEntityList);
}
return_value->push(entityById(*jt));
}
}
return return_value;
}
IfcUtil::IfcBaseClass* IfcFile::entityById(int id) {
+10 -34
View File
@@ -43,8 +43,9 @@
#include "ifc_parse_api.h"
#include "../ifcparse/IfcCharacterDecoder.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcLogger.h"
#include "../ifcparse/Argument.h"
#ifdef USE_IFC4
#include "../ifcparse/Ifc4.h"
@@ -56,7 +57,6 @@
namespace IfcParse {
class Entity;
class IfcFile;
class IfcSpfLexer;
@@ -75,7 +75,7 @@ namespace IfcParse {
struct Token {
IfcSpfLexer* lexer; //TODO: remove it from here
unsigned startPos, endPos;
unsigned startPos;
TokenType type;
union {
bool value_bool; //types: BOOL
@@ -84,9 +84,9 @@ namespace IfcParse {
double value_double; //types: FLOAT
};
Token() : lexer(0), startPos(0), endPos(0), type(Token_NONE) {}
Token(IfcSpfLexer* _lexer, unsigned _startPos, unsigned _endPos, TokenType _type)
: lexer(_lexer), startPos(_startPos), endPos(_endPos), type(_type) {}
Token() : lexer(0), startPos(0), type(Token_NONE) {}
Token(IfcSpfLexer* _lexer, unsigned _startPos, unsigned /*_endPos*/, TokenType _type)
: lexer(_lexer), startPos(_startPos), type(_type) {}
};
/// Provides functions to convert Tokens to binary data
@@ -192,6 +192,8 @@ namespace IfcParse {
void set(unsigned int i, Argument*);
std::string toString(bool upper=false) const;
std::vector<Argument*>& arguments() { return list; }
};
@@ -253,34 +255,8 @@ namespace IfcParse {
Argument* operator [] (unsigned int i) const;
std::string toString(bool upper=false) const;
};
/// Entity defined in an IFC file, e.g.
/// #1=IfcDirection((1.,0.,0.));
/// ============================
class IFC_PARSE_API Entity : public IfcAbstractEntity {
private:
mutable ArgumentList* args;
mutable IfcSchema::Type::Enum _type;
public:
/// The EXPRESS ENTITY_INSTANCE_NAME
unsigned int _id;
/// The offset at which the entity is read
unsigned int offset;
Entity(unsigned int i, IfcFile* t);
Entity(unsigned int i, IfcFile* t, unsigned int o);
virtual ~Entity();
IfcEntityList::ptr getInverse(IfcSchema::Type::Enum type, int attribute_index);
void Load(std::vector<unsigned int>& ids, bool seek=false) const;
Argument* getArgument (unsigned int i);
unsigned int getArgumentCount() const;
std::string toString(bool upper=false) const;
std::string datatype() const;
IfcSchema::Type::Enum type() const;
bool is(IfcSchema::Type::Enum v) const;
unsigned int id();
IfcWrite::IfcWritableEntity* isWritable();
};
IfcEntityInstanceData* read(unsigned int i, IfcFile* t, boost::optional<unsigned> offset = boost::none);
}
IFC_PARSE_API std::ostream& operator<< (std::ostream& os, const IfcParse::IfcFile& f);
+26 -16
View File
@@ -17,7 +17,7 @@
* *
********************************************************************************/
#include "../ifcparse/IfcParse.h"
#include "../ifcparse/IfcFile.h"
#include "IfcSpfHeader.h"
@@ -35,20 +35,30 @@ static const char * const DATA = "DATA";
using namespace IfcParse;
HeaderEntity::HeaderEntity(const char * const datatype, IfcFile* file)
: IfcEntityInstanceData(IfcSchema::Type::UNDEFINED, file), _datatype(datatype)
{
if (file) {
offset_in_file_ = file->stream->Tell();
load_();
}
}
void IfcSpfHeader::readSemicolon() {
if (!TokenFunc::isOperator(_lexer->Next(), ';')) {
if (!TokenFunc::isOperator(file_->tokens->Next(), ';')) {
throw IfcException(std::string("Expected ;"));
}
}
void IfcSpfHeader::readParen() {
if (!TokenFunc::isOperator(_lexer->Next(), '(')) {
if (!TokenFunc::isOperator(file_->tokens->Next(), '(')) {
throw IfcException(std::string("Expected ("));
}
}
void IfcSpfHeader::readTerminal(const std::string& term, Trail trail) {
if (TokenFunc::asStringRef(_lexer->Next()) != term) {
if (TokenFunc::asStringRef(file_->tokens->Next()) != term) {
throw IfcException(std::string("Expected " + term));
}
if (trail == TRAILING_SEMICOLON) {
@@ -72,20 +82,20 @@ void IfcSpfHeader::read() {
//
// ISO 10303-21 Second edition 2002-01-15 p. 16
readTerminal(FILE_DESCRIPTION, TRAILING_PAREN);
readTerminal(FILE_DESCRIPTION, NONE);
delete _file_description;
_file_description = new FileDescription(_lexer);
readSemicolon();
_file_description = new FileDescription(file_);
// readSemicolon();
readTerminal(FILE_NAME, TRAILING_PAREN);
readTerminal(FILE_NAME, NONE);
delete _file_name;
_file_name = new FileName(_lexer);
readSemicolon();
_file_name = new FileName(file_);
// readSemicolon();
readTerminal(FILE_SCHEMA, TRAILING_PAREN);
readTerminal(FILE_SCHEMA, NONE);
delete _file_schema;
_file_schema = new FileSchema(_lexer);
readSemicolon();
_file_schema = new FileSchema(file_);
// readSemicolon();
}
bool IfcSpfHeader::tryRead() {
@@ -155,6 +165,6 @@ FileSchema& IfcSpfHeader::file_schema() {
}
}
FileDescription::FileDescription(IfcSpfLexer* lexer) : HeaderEntity(FILE_DESCRIPTION, lexer) {}
FileName::FileName(IfcSpfLexer* lexer) : HeaderEntity(FILE_NAME, lexer) {}
FileSchema::FileSchema(IfcSpfLexer* lexer) : HeaderEntity(FILE_SCHEMA, lexer) {}
FileDescription::FileDescription(IfcFile* file) : HeaderEntity(FILE_DESCRIPTION, file) {}
FileName::FileName(IfcFile* file) : HeaderEntity(FILE_NAME, file) {}
FileSchema::FileSchema(IfcFile* file) : HeaderEntity(FILE_SCHEMA, file) {}
+37 -76
View File
@@ -27,98 +27,59 @@
namespace IfcParse {
class IFC_PARSE_API HeaderEntity : public IfcAbstractEntity {
class IFC_PARSE_API HeaderEntity : public IfcEntityInstanceData {
private:
ArgumentList* _list;
const char * const _datatype;
HeaderEntity(const HeaderEntity&); //N/A
HeaderEntity& operator =(const HeaderEntity&); //N/A
protected:
HeaderEntity(const char * const datatype, IfcSpfLexer* lexer)
: _list(0), _datatype(datatype)
{
std::vector<unsigned int> ids;
_list = new ArgumentList();
if (lexer) {
_list->read(lexer, ids);
}
}
HeaderEntity(const char * const datatype, IfcParse::IfcFile* file);
virtual ~HeaderEntity() {
delete _list;
}
void setArgument(unsigned int i, const std::string& s) {
void setValue(unsigned int i, const std::string& s) {
IfcWrite::IfcWriteArgument* argument = new IfcWrite::IfcWriteArgument;
argument->set(s);
_list->set(i, argument);
setArgument(i, argument);
}
void setArgument(unsigned int i, const std::vector<std::string>& s) {
void setValue(unsigned int i, const std::vector<std::string>& s) {
IfcWrite::IfcWriteArgument* argument = new IfcWrite::IfcWriteArgument;
argument->set(s);
_list->set(i, argument);
setArgument(i, argument);
}
public:
Argument* getArgument(unsigned int i) const {
return (*_list)[i];
}
Argument* getArgument(unsigned int i) {
return (*_list)[i];
}
IfcEntityList::ptr getInverse(IfcSchema::Type::Enum /*type*/, int /*attribute_index*/) {
return IfcEntityList::ptr(new IfcEntityList);
}
std::string datatype() const {
return _datatype;
}
unsigned int getArgumentCount() const {
return _list->size();
}
IfcSchema::Type::Enum type() const {
return (IfcSchema::Type::Enum) -1;
}
bool is(IfcSchema::Type::Enum /*v*/) const {
return false;
}
std::string toString(bool upper=false) const {
std::stringstream ss;
ss << _datatype << _list->toString(upper) << ";";
// Unfortunately this is duplicated from IfcEntityInstanceData::toString()
ss << _datatype << "(";
std::vector<Argument*>::const_iterator it = attributes_.begin();
for (; it != attributes_.end(); ++it) {
if (it != attributes_.begin()) {
ss << ",";
}
ss << (*it)->toString(upper);
}
ss << ")";
return ss.str();
}
unsigned int id() {
return 0;
}
IfcWrite::IfcWritableEntity* isWritable() {
return 0;
}
};
class IFC_PARSE_API FileDescription : public HeaderEntity {
public:
explicit FileDescription(IfcSpfLexer* = 0);
explicit FileDescription(IfcFile* = 0);
std::vector<std::string> description() const { return *getArgument(0); }
std::string implementation_level() const { return *getArgument(1); }
void description(const std::vector<std::string>& value) { setArgument(0, value); }
void implementation_level(const std::string& value) { setArgument(1, value); }
void description(const std::vector<std::string>& value) { setValue(0, value); }
void implementation_level(const std::string& value) { setValue(1, value); }
};
class IFC_PARSE_API FileName : public HeaderEntity {
public:
explicit FileName(IfcSpfLexer* = 0);
explicit FileName(IfcFile* = 0);
std::string name() const { return *getArgument(0); }
std::string time_stamp() const { return *getArgument(1); }
@@ -128,27 +89,27 @@ public:
std::string originating_system() const { return *getArgument(5); }
std::string authorization() const { return *getArgument(6); }
void name(const std::string& value) { setArgument(0, value); }
void time_stamp(const std::string& value) { setArgument(1, value); }
void author(const std::vector<std::string>& value) { setArgument(2, value); }
void organization(const std::vector<std::string>& value) { setArgument(3, value); }
void preprocessor_version(const std::string& value) { setArgument(4, value); }
void originating_system(const std::string& value) { setArgument(5, value); }
void authorization(const std::string& value) { setArgument(6, value); }
void name(const std::string& value) { setValue(0, value); }
void time_stamp(const std::string& value) { setValue(1, value); }
void author(const std::vector<std::string>& value) { setValue(2, value); }
void organization(const std::vector<std::string>& value) { setValue(3, value); }
void preprocessor_version(const std::string& value) { setValue(4, value); }
void originating_system(const std::string& value) { setValue(5, value); }
void authorization(const std::string& value) { setValue(6, value); }
};
class IFC_PARSE_API FileSchema : public HeaderEntity {
public:
explicit FileSchema(IfcSpfLexer* = 0);
explicit FileSchema(IfcFile* = 0);
std::vector<std::string> schema_identifiers() const { return *getArgument(0); }
void schema_identifiers(const std::vector<std::string>& value) { setArgument(0, value); }
void schema_identifiers(const std::vector<std::string>& value) { setValue(0, value); }
};
class IFC_PARSE_API IfcSpfHeader {
private:
IfcSpfLexer* _lexer;
IfcFile* file_;
FileDescription* _file_description;
FileName* _file_name;
FileSchema* _file_schema;
@@ -161,12 +122,12 @@ private:
};
void readTerminal(const std::string& term, Trail trail);
public:
explicit IfcSpfHeader(IfcSpfLexer* lexer = 0)
: _lexer(lexer), _file_description(0), _file_name(0), _file_schema(0)
explicit IfcSpfHeader(IfcParse::IfcFile* file = 0)
: file_(file), _file_description(0), _file_name(0), _file_schema(0)
{
_file_description = new FileDescription();
_file_name = new FileName();
_file_schema = new FileSchema();
_file_description = new FileDescription(file_);
_file_name = new FileName(file_);
_file_schema = new FileSchema(file_);
}
~IfcSpfHeader()
@@ -176,8 +137,8 @@ public:
delete _file_description;
}
IfcSpfLexer* lexer() { return _lexer; }
void lexer(IfcSpfLexer* l) { _lexer = l; }
IfcParse::IfcFile* file() { return file_; }
void file(IfcParse::IfcFile * file) { file_ = file; }
void read();
bool tryRead();
+30 -1
View File
@@ -17,8 +17,16 @@
* *
********************************************************************************/
#include "IfcUtil.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/Argument.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcEntityList.h"
#ifdef USE_IFC4
#include "../ifcparse/Ifc4-latebound.h"
#else
#include "../ifcparse/Ifc2x3-latebound.h"
#endif
#include <boost/algorithm/string/replace.hpp>
#include <boost/optional.hpp>
@@ -155,3 +163,24 @@ void IfcUtil::unescape_xml(std::string &str)
boost::replace_all(str, "&gt;", ">");
boost::replace_all(str, "&amp;", "&");
}
std::vector<std::string> IfcUtil::IfcBaseEntity::getAttributeNames() const {
std::vector<std::string> return_value;
return_value.reserve(getArgumentCount());
for (unsigned i = 0; i < getArgumentCount(); ++i) {
return_value.push_back(getArgumentName(i));
}
return return_value;
}
std::vector<std::string> IfcUtil::IfcBaseEntity::getInverseAttributeNames() const {
std::vector<std::string> return_value;
std::set<std::string> values = IfcSchema::Type::GetInverseAttributeNames(entity->type());
std::copy(values.begin(), values.end(), std::back_inserter(return_value));
return return_value;
}
Argument* IfcUtil::IfcBaseEntity::getArgumentByName(const std::string& name) const {
unsigned int i = IfcSchema::Type::GetAttributeIndex(type(), name);
return getArgument(i);
}
-332
View File
@@ -1,332 +0,0 @@
/********************************************************************************
* *
* 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/>. *
* *
********************************************************************************/
#ifndef IFCUTIL_H
#define IFCUTIL_H
#include <set>
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>
#include "ifc_parse_api.h"
#ifdef USE_IFC4
#include "../ifcparse/Ifc4enum.h"
#else
#include "../ifcparse/Ifc2x3enum.h"
#endif
#include <boost/shared_ptr.hpp>
#include <boost/dynamic_bitset.hpp>
#include <boost/foreach.hpp>
#define foreach BOOST_FOREACH
#define rforeach BOOST_REVERSE_FOREACH
class Argument;
class IfcEntityList;
class IfcEntityListList;
class IfcAbstractEntity;
namespace IfcWrite {
class IfcWritableEntity;
}
namespace IfcUtil {
enum ArgumentType {
Argument_NULL,
Argument_DERIVED,
Argument_INT,
Argument_BOOL,
Argument_DOUBLE,
Argument_STRING,
Argument_BINARY,
Argument_ENUMERATION,
Argument_ENTITY_INSTANCE,
Argument_EMPTY_AGGREGATE,
Argument_AGGREGATE_OF_INT,
Argument_AGGREGATE_OF_DOUBLE,
Argument_AGGREGATE_OF_STRING,
Argument_AGGREGATE_OF_BINARY,
Argument_AGGREGATE_OF_ENTITY_INSTANCE,
Argument_AGGREGATE_OF_EMPTY_AGGREGATE,
Argument_AGGREGATE_OF_AGGREGATE_OF_INT,
Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE,
Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE,
Argument_UNKNOWN
};
IFC_PARSE_API const char* ArgumentTypeToString(ArgumentType argument_type);
class IFC_PARSE_API IfcBaseClass {
public:
virtual ~IfcBaseClass() {}
IfcAbstractEntity* entity;
virtual bool is(IfcSchema::Type::Enum v) const = 0;
virtual IfcSchema::Type::Enum type() const = 0;
virtual unsigned int getArgumentCount() const = 0;
virtual ArgumentType getArgumentType(unsigned int i) const = 0;
virtual IfcSchema::Type::Enum getArgumentEntity(unsigned int i) const = 0;
virtual Argument* getArgument(unsigned int i) const = 0;
virtual const char* getArgumentName(unsigned int i) const = 0;
template <class T>
T* as() {
return is(T::Class())
? static_cast<T*>(this)
: static_cast<T*>(0);
}
template <class T>
const T* as() const {
return is(T::Class())
? static_cast<const T*>(this)
: static_cast<const T*>(0);
}
};
class IFC_PARSE_API IfcBaseEntity : public IfcBaseClass {
};
// TODO: Investigate whether these should be template classes instead
class IFC_PARSE_API IfcBaseType : public IfcBaseEntity {
public:
unsigned int getArgumentCount() const;
Argument* getArgument(unsigned int i) const;
const char* getArgumentName(unsigned int i) const;
IfcSchema::Type::Enum getArgumentEntity(unsigned int /*i*/) const { return IfcSchema::Type::UNDEFINED; }
};
IFC_PARSE_API bool valid_binary_string(const std::string& s);
/// Replaces spaces and potentially other problem causing characters with underscores.
IFC_PARSE_API void sanitate_material_name(std::string &str);
IFC_PARSE_API void escape_xml(std::string &str);
IFC_PARSE_API void unescape_xml(std::string &str);
}
template <class T>
class IfcTemplatedEntityList;
class IFC_PARSE_API IfcEntityList {
std::vector<IfcUtil::IfcBaseClass*> ls;
public:
typedef boost::shared_ptr<IfcEntityList> ptr;
typedef std::vector<IfcUtil::IfcBaseClass*>::const_iterator it;
void push(IfcUtil::IfcBaseClass* l);
void push(const ptr& l);
it begin();
it end();
IfcUtil::IfcBaseClass* operator[] (int i);
unsigned int size() const;
bool contains(IfcUtil::IfcBaseClass*) const;
template <class U>
typename U::list::ptr as() {
typename U::list::ptr r(new typename U::list);
const bool all = U::Class() == IfcSchema::Type::UNDEFINED;
for ( it i = begin(); i != end(); ++ i ) if (all || (*i)->is(U::Class())) r->push((U*)*i);
return r;
}
void remove(IfcUtil::IfcBaseClass*);
IfcEntityList::ptr filtered(const std::set<IfcSchema::Type::Enum>& entities);
};
template <class T>
class IfcTemplatedEntityList {
std::vector<T*> ls;
public:
typedef boost::shared_ptr< IfcTemplatedEntityList<T> > ptr;
typedef typename std::vector<T*>::const_iterator it;
void push(T* t) { if (t) { ls.push_back(t); } }
void push(ptr t) { if (t) { for ( typename T::list::it it = t->begin(); it != t->end(); ++it ) push(*it); } }
it begin() { return ls.begin(); }
it end() { return ls.end(); }
unsigned int size() const { return (unsigned int) ls.size(); }
IfcEntityList::ptr generalize() {
IfcEntityList::ptr r (new IfcEntityList());
for ( it i = begin(); i != end(); ++ i ) r->push(*i);
return r;
}
bool contains(T* t) const { return std::find(ls.begin(), ls.end(), t) != ls.end(); }
template <class U>
typename U::list::ptr as() {
typename U::list::ptr r(new typename U::list);
const bool all = U::Class() == IfcSchema::Type::UNDEFINED;
for ( it i = begin(); i != end(); ++ i ) if (all || (*i)->is(U::Class())) r->push((U*)*i);
return r;
}
void remove(T* t) {
typename std::vector<T*>::iterator it;
while ((it = std::find(ls.begin(), ls.end(), t)) != ls.end()) {
ls.erase(it);
}
}
};
template <class T>
class IfcTemplatedEntityListList;
class IFC_PARSE_API IfcEntityListList {
std::vector< std::vector<IfcUtil::IfcBaseClass*> > ls;
public:
typedef boost::shared_ptr< IfcEntityListList > ptr;
typedef std::vector< std::vector<IfcUtil::IfcBaseClass*> >::const_iterator outer_it;
typedef std::vector<IfcUtil::IfcBaseClass*>::const_iterator inner_it;
void push(const std::vector<IfcUtil::IfcBaseClass*>& l) {
ls.push_back(l);
}
void push(const IfcEntityList::ptr& l) {
if (l) {
std::vector<IfcUtil::IfcBaseClass*> li;
for (std::vector<IfcUtil::IfcBaseClass*>::const_iterator jt = l->begin(); jt != l->end(); ++jt) {
li.push_back(*jt);
}
push(li);
}
}
outer_it begin() const { return ls.begin(); }
outer_it end() const { return ls.end(); }
int size() const { return (int)ls.size(); }
int totalSize() const {
int accum = 0;
for (outer_it it = begin(); it != end(); ++it) {
accum += (int)it->size();
}
return accum;
}
bool contains(IfcUtil::IfcBaseClass* instance) const {
for (outer_it it = begin(); it != end(); ++it) {
const std::vector<IfcUtil::IfcBaseClass*>& inner = *it;
if (std::find(inner.begin(), inner.end(), instance) != inner.end()) {
return true;
}
}
return false;
}
template <class U>
typename IfcTemplatedEntityListList<U>::ptr as() {
typename IfcTemplatedEntityListList<U>::ptr r(new IfcTemplatedEntityListList<U>);
const bool all = U::Class() == IfcSchema::Type::UNDEFINED;
for (outer_it outer = begin(); outer != end(); ++ outer) {
const std::vector<IfcUtil::IfcBaseClass*>& from = *outer;
typename std::vector<U*> to;
for (inner_it inner = from.begin(); inner != from.end(); ++ inner) {
if (all || (*inner)->is(U::Class())) to.push_back((U*)*inner);
}
r->push(to);
}
return r;
}
};
template <class T>
class IfcTemplatedEntityListList {
std::vector< std::vector<T*> > ls;
public:
typedef typename boost::shared_ptr< IfcTemplatedEntityListList<T> > ptr;
typedef typename std::vector< std::vector<T*> >::const_iterator outer_it;
typedef typename std::vector<T*>::const_iterator inner_it;
void push(const std::vector<T*>& t) {ls.push_back(t);}
outer_it begin() { return ls.begin(); }
outer_it end() { return ls.end(); }
int size() const { return (int)ls.size(); }
int totalSize() const {
int accum = 0;
for (outer_it it = begin(); it != end(); ++it) {
accum += it->size();
}
return accum;
}
bool contains(T* t) const {
for (outer_it it = begin(); it != end(); ++it) {
const std::vector<T*>& inner = *it;
if (std::find(inner.begin(), inner.end(), t) != inner.end()) {
return true;
}
}
return false;
}
IfcEntityListList::ptr generalize() {
IfcEntityListList::ptr r (new IfcEntityListList());
for (outer_it outer = begin(); outer != end(); ++ outer) {
const std::vector<T*>& from = *outer;
std::vector<IfcUtil::IfcBaseClass*> to;
for (inner_it inner = from.begin(); inner != from.end(); ++ inner) {
to.push_back(*inner);
}
r->push(to);
}
return r;
}
};
namespace IfcParse {
class IfcFile;
}
class IFC_PARSE_API Argument {
public:
virtual operator int() const;
virtual operator bool() const;
virtual operator double() const;
virtual operator std::string() const;
virtual operator boost::dynamic_bitset<>() const;
virtual operator IfcUtil::IfcBaseClass*() const;
virtual operator std::vector<int>() const;
virtual operator std::vector<double>() const;
virtual operator std::vector<std::string>() const;
virtual operator std::vector<boost::dynamic_bitset<> >() const;
virtual operator IfcEntityList::ptr() const;
virtual operator std::vector< std::vector<int> >() const;
virtual operator std::vector< std::vector<double> >() const;
virtual operator IfcEntityListList::ptr() const;
virtual bool isNull() const = 0;
virtual unsigned int size() const = 0;
virtual IfcUtil::ArgumentType type() const = 0;
virtual Argument* operator [] (unsigned int i) const = 0;
virtual std::string toString(bool upper=false) const = 0;
virtual ~Argument() {};
};
class IFC_PARSE_API IfcAbstractEntity {
public:
IfcParse::IfcFile* file;
virtual IfcEntityList::ptr getInverse(IfcSchema::Type::Enum type, int attribute_index) = 0;
virtual std::string datatype() const = 0;
virtual Argument* getArgument (unsigned int i) = 0;
virtual unsigned int getArgumentCount() const = 0;
virtual ~IfcAbstractEntity() {};
virtual IfcSchema::Type::Enum type() const = 0;
virtual bool is(IfcSchema::Type::Enum v) const = 0;
virtual std::string toString(bool upper=false) const = 0;
virtual unsigned int id() = 0;
virtual IfcWrite::IfcWritableEntity* isWritable() = 0;
};
#endif
-94
View File
@@ -1,94 +0,0 @@
/********************************************************************************
* *
* 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/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* This namespace provides implementations of Argument and Entity that use STL *
* containers for their datatypes and are not just lazy references to the *
* IFC-SPF file. Therefore they can be modified by the client application. *
* *
* An IfcWritableEntity can be constructed from a regular IfcParse entity to be *
* able to modify the data in existing IFC files. *
* *
********************************************************************************/
#ifndef IFCWRITABLEENTITY_H
#define IFCWRITABLEENTITY_H
#include <map>
#include <boost/dynamic_bitset.hpp>
#include "ifc_parse_api.h"
#include "IfcUtil.h"
namespace IfcWrite {
class IFC_PARSE_API IfcWritableEntity : public IfcAbstractEntity {
private:
std::map<int,bool> writemask;
std::map<int,Argument*> args;
IfcSchema::Type::Enum _type;
int* _id;
bool arg_writable(int i);
void arg_writable(int i, bool b);
template <typename T> void _setArgument(int i, const T&);
public:
IfcWritableEntity(IfcSchema::Type::Enum t);
~IfcWritableEntity();
int setId(int i=-1);
IfcWritableEntity(IfcAbstractEntity* e);
IfcEntityList::ptr getInverse(IfcSchema::Type::Enum type, int attribute_index);
std::string datatype() const;
Argument* getArgument (unsigned int i);
unsigned int getArgumentCount() const;
IfcSchema::Type::Enum type() const;
bool is(IfcSchema::Type::Enum v) const;
std::string toString(bool upper=false) const;
unsigned int id();
IfcWritableEntity* isWritable();
void setArgument(int i, Argument* a, IfcUtil::ArgumentType attr_type = IfcUtil::Argument_UNKNOWN);
void setArgument(int i);
void setArgumentDerived(int i);
void setArgument(int i,int v);
void setArgument(int i,bool v);
void setArgument(int i,double v);
void setArgument(int i,const std::string& v);
void setArgument(int i,const boost::dynamic_bitset<>& v);
void setArgument(int i,int v, const char* c);
void setArgument(int i,IfcUtil::IfcBaseClass* v);
void setArgument(int i,const std::vector<int>& v);
void setArgument(int i,const std::vector<double>& v);
void setArgument(int i,const std::vector<std::string>& v);
void setArgument(int i,const std::vector< boost::dynamic_bitset<> >& v);
void setArgument(int i,IfcEntityList::ptr v);
void setArgument(int i,const std::vector< std::vector<int> >& v);
void setArgument(int i,const std::vector< std::vector<double> >& v);
void setArgument(int i,IfcEntityListList::ptr v);
};
}
#endif
+26 -284
View File
@@ -25,7 +25,6 @@
#include "../ifcparse/IfcParse.h"
#include "../ifcparse/IfcWrite.h"
#include "../ifcparse/IfcWritableEntity.h"
#include "../ifcparse/IfcCharacterDecoder.h"
#include "../ifcparse/IfcFile.h"
@@ -37,268 +36,6 @@
using namespace IfcWrite;
IfcWritableEntity::IfcWritableEntity(IfcSchema::Type::Enum t) {
_type = t;
_id = 0;
file = 0;
}
IfcWritableEntity::~IfcWritableEntity() {
delete _id;
for (std::map<int,Argument*>::iterator it = args.begin(); it != args.end(); ++it)
delete it->second;
}
int IfcWritableEntity::setId(int i) {
if (i > 0) {
delete _id;
return *(_id = new int(i));
} else {
if (_id) { return *_id; }
else {
delete _id;
return *(_id = new int(file->FreshId()));
}
}
}
IfcWritableEntity::IfcWritableEntity(IfcAbstractEntity* e)
{
file = e->file;
_type = e->type();
_id = new int(e->id());
const unsigned int count = e->getArgumentCount();
for ( unsigned int i = 0; i < count; ++ i ) {
this->setArgument(i, e->getArgument(i));
}
}
IfcEntityList::ptr IfcWritableEntity::getInverse(IfcSchema::Type::Enum type, int attribute_index) {
if (file) {
int id = _id ? *_id : setId();
return file->getInverse(id, type, attribute_index);
} else {
throw IfcParse::IfcException("Instance not part of a file");
}
}
std::string IfcWritableEntity::datatype() const { return IfcSchema::Type::ToString(_type); }
Argument* IfcWritableEntity::getArgument (unsigned int i) {
if (args[i] == 0) {
_setArgument(i, boost::blank());
}
return args[i];
}
unsigned int IfcWritableEntity::getArgumentCount() const { return (unsigned)args.size(); }
IfcSchema::Type::Enum IfcWritableEntity::type() const { return _type; }
bool IfcWritableEntity::is(IfcSchema::Type::Enum v) const { return _type == v; }
std::string IfcWritableEntity::toString(bool upper) const {
std::stringstream ss;
ss.imbue(std::locale::classic());
std::string dt = datatype();
if (upper) {
boost::to_upper(dt);
}
if (_id && !IfcSchema::Type::IsSimple(type())) {
ss << "#" << *_id;
ss << "=";
}
ss << dt << "(";
for (std::map<int,Argument*>::const_iterator it = args.begin(); it != args.end(); ++ it) {
if ( it != args.begin() ) ss << ",";
ss << it->second->toString(upper);
}
ss << ")";
return ss.str();
}
unsigned int IfcWritableEntity::id() {
if (!file) {
return 0;
}
if ( !_id ) {
_id = new int(file->FreshId());
}
return *_id;
}
IfcWritableEntity* IfcWritableEntity::isWritable() { return this; }
bool IfcWritableEntity::arg_writable(int i) {
std::map<int,bool>::const_iterator it = writemask.find(i);
if ( it == writemask.end() ) return false;
else return it->second;
}
void IfcWritableEntity::arg_writable(int i, bool b) {
writemask[i] = b;
}
template <typename T> void IfcWritableEntity::_setArgument(int i, const T& t) {
if ( arg_writable(i) ) delete args[i];
IfcWriteArgument* arg = new IfcWriteArgument;
args[i] = arg;
arg->set(t);
arg_writable(i,true);
}
void IfcWritableEntity::setArgument(int i) {
_setArgument(i, boost::none);
}
void IfcWritableEntity::setArgument(int i, Argument* a, IfcUtil::ArgumentType attr_type) {
if (attr_type == IfcUtil::Argument_UNKNOWN) {
attr_type = a->type();
}
switch(attr_type) {
case IfcUtil::Argument_NULL:
this->setArgument(i);
break;
case IfcUtil::Argument_DERIVED:
this->setArgumentDerived(i);
break;
case IfcUtil::Argument_INT:
this->setArgument(i, static_cast<int>(*a));
break;
case IfcUtil::Argument_BOOL:
this->setArgument(i, static_cast<bool>(*a));
break;
case IfcUtil::Argument_DOUBLE:
this->setArgument(i, static_cast<double>(*a));
break;
case IfcUtil::Argument_STRING:
this->setArgument(i, static_cast<std::string>(*a));
break;
case IfcUtil::Argument_BINARY: {
boost::dynamic_bitset<> attr_value = *a;
this->setArgument(i, attr_value); }
break;
case IfcUtil::Argument_AGGREGATE_OF_INT: {
std::vector<int> attr_value = *a;
this->setArgument(i, attr_value); }
break;
case IfcUtil::Argument_AGGREGATE_OF_DOUBLE: {
std::vector<double> attr_value = *a;
this->setArgument(i, attr_value); }
break;
case IfcUtil::Argument_AGGREGATE_OF_STRING: {
std::vector<std::string> attr_value = *a;
this->setArgument(i, attr_value); }
break;
case IfcUtil::Argument_AGGREGATE_OF_BINARY: {
std::vector< boost::dynamic_bitset<> > attr_value = *a;
this->setArgument(i, attr_value); }
break;
case IfcUtil::Argument_ENUMERATION: {
IfcSchema::Type::Enum ty = IfcSchema::Type::GetAttributeEntity(_type, (unsigned char)i);
std::string enum_literal = a->toString();
// Remove leading and trailing '.'
enum_literal = enum_literal.substr(1, enum_literal.size() - 2);
std::pair<const char*, int> enum_ref = IfcSchema::Type::GetEnumerationIndex(ty, enum_literal);
this->setArgument(i, enum_ref.second, enum_ref.first); }
break;
case IfcUtil::Argument_ENTITY_INSTANCE: {
this->setArgument(i, static_cast<IfcUtil::IfcBaseClass*>(*a)); }
break;
case IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE: {
IfcEntityList::ptr instances = *a;
IfcEntityList::ptr mapped_instances(new IfcEntityList);
for (IfcEntityList::it it = instances->begin(); it != instances->end(); ++it) {
mapped_instances->push(*it);
}
this->setArgument(i, mapped_instances); }
break;
case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_INT: {
std::vector< std::vector<int> > attr_value = *a;
this->setArgument(i, attr_value); }
break;
case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE: {
std::vector< std::vector<double> > attr_value = *a;
this->setArgument(i, attr_value); }
break;
case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE: {
IfcEntityListList::ptr instances = *a;
IfcEntityListList::ptr mapped_instances(new IfcEntityListList);
for (IfcEntityListList::outer_it it = instances->begin(); it != instances->end(); ++it) {
std::vector<IfcUtil::IfcBaseClass*> inner;
for (IfcEntityListList::inner_it jt = it->begin(); jt != it->end(); ++jt) {
inner.push_back(*jt);
}
mapped_instances->push(inner);
}
this->setArgument(i, mapped_instances); }
break;
case IfcUtil::Argument_EMPTY_AGGREGATE:
case IfcUtil::Argument_AGGREGATE_OF_EMPTY_AGGREGATE: {
IfcUtil::ArgumentType t2 = IfcSchema::Type::GetAttributeType(type(), (unsigned char) i);
this->setArgument(i, a, t2); }
break;
default:
case IfcUtil::Argument_UNKNOWN:
throw IfcParse::IfcException(std::string("Unknown attribute encountered: '") + a->toString() + "' at index '" + boost::lexical_cast<std::string>(i) + "'");
break;
}
}
void IfcWritableEntity::setArgumentDerived(int i) {
_setArgument(i, IfcWriteArgument::Derived());
}
void IfcWritableEntity::setArgument(int i,int v) {
_setArgument(i, v);
}
void IfcWritableEntity::setArgument(int i,bool v) {
_setArgument(i, v);
}
void IfcWritableEntity::setArgument(int i,int v, const char* c){
_setArgument(i, IfcWriteArgument::EnumerationReference(v, c));
}
void IfcWritableEntity::setArgument(int i,const std::string& v){
_setArgument(i, v);
}
void IfcWritableEntity::setArgument(int i,const boost::dynamic_bitset<>& v){
_setArgument(i, v);
}
void IfcWritableEntity::setArgument(int i,double v){
_setArgument(i, v);
}
void IfcWritableEntity::setArgument(int i,IfcUtil::IfcBaseClass* v){
if ( v ) {
_setArgument(i, v);
} else {
_setArgument(i, boost::none);
}
}
void IfcWritableEntity::setArgument(int i,IfcEntityList::ptr v){
if ( v.get() ) {
_setArgument(i, v);
} else {
_setArgument(i, boost::none);
}
}
void IfcWritableEntity::setArgument(int i,IfcEntityListList::ptr v){
if ( v.get() ) {
_setArgument(i, v);
} else {
_setArgument(i, boost::none);
}
}
void IfcWritableEntity::setArgument(int i,const std::vector<double>& v){
_setArgument(i, v);
}
void IfcWritableEntity::setArgument(int i,const std::vector< std::vector<double> >& v){
_setArgument(i, v);
}
void IfcWritableEntity::setArgument(int i,const std::vector<std::string>& v){
_setArgument(i, v);
}
void IfcWritableEntity::setArgument(int i,const std::vector<int>& v){
_setArgument(i, v);
}
void IfcWritableEntity::setArgument(int i,const std::vector< std::vector<int> >& v){
_setArgument(i, v);
}
void IfcWritableEntity::setArgument(int i,const std::vector< boost::dynamic_bitset<> >& v){
_setArgument(i, v);
}
class SizeVisitor : public boost::static_visitor<int> {
public:
int operator()(const boost::blank& /*i*/) const { return -1; }
@@ -407,7 +144,7 @@ public:
data << "." << i.enumeration_value << ".";
}
void operator()(const IfcUtil::IfcBaseClass* const& i) {
IfcAbstractEntity* e = i->entity;
IfcEntityInstanceData* e = i->entity;
if ( IfcSchema::Type::IsSimple(e->type()) ) {
data << e->toString(upper);
} else {
@@ -447,12 +184,8 @@ void StringBuilderVisitor::serialize(const std::vector<std::string>& i) {
data << "(";
for (std::vector<std::string>::const_iterator it = i.begin(); it != i.end(); ++it) {
if (it != i.begin()) data << ",";
if (upper) {
std::string s = IfcCharacterEncoder(*it);
data << s;
} else {
data << *it;
}
std::string s = IfcCharacterEncoder(*it);
data << s;
}
data << ")";
}
@@ -540,20 +273,29 @@ IfcUtil::ArgumentType IfcWriteArgument::type() const {
return static_cast<IfcUtil::ArgumentType>(container.which());
}
EntityBuffer* EntityBuffer::i = 0;
EntityBuffer* EntityBuffer::instance() {
if ( ! i ) {
i = new EntityBuffer();
i->buffer = IfcEntityList::ptr(new IfcEntityList);
// Overload to detect null values
void IfcWriteArgument::set(const IfcEntityList::ptr& v) {
if (v) {
container = v;
} else {
container = boost::blank();
}
return i;
}
IfcEntityList::ptr EntityBuffer::Get() {
return instance()->buffer;
}
void EntityBuffer::Clear() {
instance()->buffer = IfcEntityList::ptr(new IfcEntityList);
}
void EntityBuffer::Add(IfcUtil::IfcBaseClass* e) {
instance()->buffer->push(e);
// 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();
}
}
+22 -16
View File
@@ -32,9 +32,13 @@
#include <boost/optional.hpp>
#include <boost/dynamic_bitset.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include "ifc_parse_api.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcParse.h"
namespace IfcWrite {
@@ -111,17 +115,31 @@ namespace IfcWrite {
IfcEntityListList::ptr
> container;
public:
template <typename T> const T& as() const {
template <typename T>
const T& as() const {
if (const T* val = boost::get<T>(&container)) {
return *val;
} else {
throw IfcParse::IfcException("Invalid cast");
}
}
template <typename T> void set(const T& t) {
template <typename T>
typename boost::disable_if<boost::is_base_of<IfcUtil::IfcBaseClass, typename boost::remove_pointer<T>::type>, void>::type
set(const T& t) {
container = t;
}
// Overload to detect null values
void set(const IfcEntityList::ptr& v);
// Overload to detect null values
void set(const IfcEntityListList::ptr& v);
// Overload to detect null values
void set(IfcUtil::IfcBaseClass*const & v);
operator int() const;
operator bool() const;
operator double() const;
@@ -146,19 +164,7 @@ namespace IfcWrite {
IfcUtil::ArgumentType type() const;
};
// Accumulates all schema instances created from constructors
// This way they can be added in a single batch to the IfcFile
class IFC_PARSE_API EntityBuffer {
private:
IfcEntityList::ptr buffer;
static EntityBuffer* i;
static EntityBuffer* instance();
public:
static IfcEntityList::ptr Get();
static void Clear();
static void Add(IfcUtil::IfcBaseClass* e);
};
}
#endif